Simplify asyncExpectThrows and enhance Expect.throws.

For `asyncExpectThrows`, instead of taking a function,
then checking if that function can be called with zero arguments,
and then immediately calling it and checking that it returns a future,
just take the future as argument.

Since synchronus errors from calling the function were not caught
anyway, doing the entire `Future` computation directly shouldn't
change behavior.

Also make `asyncExpectThrows` and `Expect.throws` return the caught error,
so that you can use normal `Expect.something` checks on it afterwards,
instead of doing that in the `check` function.
That basically makes the `check` function unnecessary (but hard to remove
with the existing test corpus using it heavily).

This makes some uses of the `asyncExpectThrows` function slightly more
complicated, those that have no other way to create a future than calling
the argument function anyway, but other uses become simpler
when they can avoid adding the function wrapper.

TEST= Refactoring. If the tests keep running, it's successful.

Change-Id: I983eb65ea4805760339073fabc27f78c57f9a471
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/226102
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2022-01-06 17:06:47 +00:00 committed by Commit Bot
parent 540dde6329
commit cd0606e425
14 changed files with 461 additions and 280 deletions

View file

@ -89,56 +89,50 @@ Future<void> asyncTest(f()) {
return f().then(asyncSuccess);
}
bool _pass(dynamic object) => true;
/// Calls [f] and verifies that it throws a `T`.
/// Verifies that the asyncronous [result] throws a [T].
///
/// The optional [check] function can provide additional validation that the
/// correct object is being thrown. For example, to check the content of the
/// thrown object you could write this:
/// Fails if [result] completes with a value, or it completes with
/// an error which is not a [T].
///
/// asyncExpectThrows<MyException>(myThrowingFunction,
/// (e) => e.myMessage.contains("WARNING"));
///
/// If `f` fails an expectation (i.e., throws an [ExpectException]), that
/// exception is not caught by [asyncExpectThrows]. The test is still considered
/// failing.
void asyncExpectThrows<T>(Future<void> f(),
[bool check(T error) = _pass, String reason = ""]) {
var type = "";
if (T != dynamic && T != Object) type = "<$T>";
/// Returns the accepted thrown object.
/// For example, to check the content of the thrown object,
/// you could write this:
/// ```
/// var e = await asyncExpectThrows<MyException>(asyncExpression)
/// Expect.isTrue(e.myMessage.contains("WARNING"));
/// ```
/// If `result` completes with an [ExpectException] error from another
/// failed test expectation, that error cannot be caught and accepted.
Future<T> asyncExpectThrows<T extends Object>(Future<void> result,
[String reason = ""]) {
// Handle null being passed in from legacy code while also avoiding producing
// an unnecessary null check warning here.
if ((reason as dynamic) == null) reason = "";
var type = "";
if (T != dynamic && T != Object) type = "<$T>";
var header = "asyncExpectThrows$type(${reason}):";
if ((result as dynamic) == null) {
Expect.testError("$header result Future must not be null.");
}
// TODO(rnystrom): It might useful to validate that T is not bound to
// ExpectException since that won't work.
if (f is! Function()) {
// Only throws from executing the function body should count as throwing.
// The failure to even call `f` should throw outside the try/catch.
Expect.testError("$header Function not callable with zero arguments.");
}
var result = f();
if (result is! Future) {
Expect.testError("$header Function did not return a Future.");
}
asyncStart();
result.then<Null>((_) {
return result.then<T>((_) {
throw ExpectException("$header Did not throw.");
}).catchError((error, stack) {
}, onError: (error, stack) {
// A test failure doesn't count as throwing.
if (error is ExpectException) throw error;
if (error is! T || (check != null && !check(error))) {
if (error is! T) {
// Throws something unexpected.
throw ExpectException(
"$header Unexpected '${Error.safeToString(error)}'\n$stack");
}
asyncEnd();
return error;
});
}

View file

@ -215,14 +215,14 @@ void isNull(dynamic o) {
Expect.isNull(o);
}
void _checkThrow<T>(dynamic v, void onError(error)) {
void _checkThrow<T extends Object>(dynamic v, void onError(error)) {
if (v is Future) {
asyncStart();
v.then((_) {
Expect.fail("Did not throw");
}, onError: (e, s) {
if (e is! T) throw e;
if (onError != null) onError(e);
onError(e);
asyncEnd();
});
return;

View file

@ -243,9 +243,13 @@ class Expect {
buffer.write('_');
} else {
int first = equivalence[0];
buffer..write('#')..write(first);
buffer
..write('#')
..write(first);
if (first == i) {
buffer..write('=')..write(objects[i]);
buffer
..write('=')
..write(objects[i]);
}
}
}
@ -259,7 +263,10 @@ class Expect {
if (first.isNotEmpty && first.length == objects.length) return;
var buffer = new StringBuffer("Expect.allIdentical([");
_writeEquivalences(objects, equivalences, buffer);
buffer..write("]")..write(msg)..write(")");
buffer
..write("]")
..write(msg)
..write(")");
_fail(buffer.toString());
}
@ -290,7 +297,10 @@ class Expect {
if (!hasEquivalence) return;
var buffer = new StringBuffer("Expect.allDistinct([");
_writeEquivalences(objects, equivalences, buffer);
buffer..write("]")..write(msg)..write(")");
buffer
..write("]")
..write(msg)
..write(")");
_fail(buffer.toString());
}
@ -387,7 +397,7 @@ class Expect {
String defaultMessage =
'Expect.stringEquals(expected: <$expected>", <$actual>$msg) fails';
if ((expected == null) || (actual == null)) {
if ((expected as dynamic) == null || (actual as dynamic) == null) {
_fail('$defaultMessage');
}
@ -583,45 +593,52 @@ class Expect {
}
}
static bool _defaultCheck([dynamic e]) => true;
static bool _defaultCheck([dynamic _]) => true;
/**
* Calls the function [f] and verifies that it throws a `T`.
* The optional [check] function can provide additional validation
* that the correct object is being thrown. For example, to check
* the content of the thrown boject you could write this:
* Verifies that [computation] throws a [T].
*
* Expect.throws<MyException>(myThrowingFunction,
* (e) => e.myMessage.contains("WARNING"));
* Calls the [computation] function and fails if that call doesn't throw,
* throws something which is not a [T], or throws a [T] which does not
* satisfy the optional [check] function.
*
* The type variable can be omitted and the type checked in [check]
* instead. This was traditionally done before Dart had generic methods.
* Returns the accepted thrown [T] object, if one is caught.
* This value can be checked further, instead of checking it in the [check]
* function. For example, to check the content of the thrown object,
* you could write this:
* ```
* var e = Expect.throws<MyException>(myThrowingFunction);
* Expect.isTrue(e.myMessage.contains("WARNING"));
* ```
* The type variable can be omitted, in which case it defaults to [Object],
* and the (sub-)type of the object can be checked in [check] instead.
* This was traditionally done before Dart had generic methods.
*
* If `f` fails an expectation (i.e., throws an [ExpectException]), that
* exception is not caught by [Expect.throws]. The test is still considered
* failing.
* If `computation` fails another test expectation
* (i.e., throws an [ExpectException]),
* that exception cannot be caught and accepted by [Expect.throws].
* The test is still considered failing.
*/
static void throws<T>(void f(),
[bool check(T error) = _defaultCheck, String reason = ""]) {
static T throws<T extends Object>(void Function() computation,
[bool Function(T error)? check, String? reason]) {
// TODO(vsm): Make check and reason nullable or change call sites.
// Existing tests pass null to set a reason and/or pass them through
// via helpers.
// TODO(rnystrom): Using the strange form below instead of "??=" to avoid
// warnings of unnecessary null checks when analyzed as NNBD code.
if ((check as dynamic) == null) check = _defaultCheck;
if ((reason as dynamic) == null) reason = "";
reason ??= "";
String msg = reason.isEmpty ? "" : "($reason)";
if (f is! Function()) {
if ((computation as dynamic) == null) {
// Only throws from executing the function body should count as throwing.
// The failure to even call `f` should throw outside the try/catch.
_fail("Expect.throws$msg: Function f not callable with zero arguments");
testError("Function must not be null");
}
try {
f();
computation();
} catch (e, s) {
// A test failure doesn't count as throwing.
if (e is ExpectException) rethrow;
if (e is T && check(e as dynamic)) return;
if (e is T && (check ?? _defaultCheck)(e)) return e;
// Throws something unexpected.
String type = "";
if (T != dynamic && T != Object) {
@ -633,47 +650,41 @@ class Expect {
_fail('Expect.throws$msg fails: Did not throw');
}
static void throwsArgumentError(void f(), [String reason = "ArgumentError"]) {
Expect.throws(f, (error) => error is ArgumentError, reason);
}
static ArgumentError throwsArgumentError(void f(),
[String reason = "ArgumentError"]) =>
Expect.throws<ArgumentError>(f, _defaultCheck, reason);
static void throwsAssertionError(void f(),
[String reason = "AssertionError"]) {
Expect.throws(f, (error) => error is AssertionError, reason);
}
static AssertionError throwsAssertionError(void f(),
[String reason = "AssertionError"]) =>
Expect.throws<AssertionError>(f, _defaultCheck, reason);
static void throwsFormatException(void f(),
[String reason = "FormatException"]) {
Expect.throws(f, (error) => error is FormatException, reason);
}
static FormatException throwsFormatException(void f(),
[String reason = "FormatException"]) =>
Expect.throws<FormatException>(f, _defaultCheck, reason);
static void throwsNoSuchMethodError(void f(),
[String reason = "NoSuchMethodError"]) {
Expect.throws(f, (error) => error is NoSuchMethodError, reason);
}
static NoSuchMethodError throwsNoSuchMethodError(void f(),
[String reason = "NoSuchMethodError"]) =>
Expect.throws<NoSuchMethodError>(f, _defaultCheck, reason);
static void throwsReachabilityError(void f(),
[String reason = "ReachabilityError"]) {
Expect.throws(
f, (error) => error.toString().startsWith('ReachabilityError'), reason);
}
static Error throwsReachabilityError(void f(),
[String reason = "ReachabilityError"]) =>
Expect.throws<Error>(f,
(error) => error.toString().startsWith('ReachabilityError'), reason);
static void throwsRangeError(void f(), [String reason = "RangeError"]) {
Expect.throws(f, (error) => error is RangeError, reason);
}
static RangeError throwsRangeError(void f(),
[String reason = "RangeError"]) =>
Expect.throws<RangeError>(f, _defaultCheck, reason);
static void throwsStateError(void f(), [String reason = "StateError"]) {
Expect.throws(f, (error) => error is StateError, reason);
}
static StateError throwsStateError(void f(),
[String reason = "StateError"]) =>
Expect.throws<StateError>(f, _defaultCheck, reason);
static void throwsTypeError(void f(), [String reason = "TypeError"]) {
Expect.throws(f, (error) => error is TypeError, reason);
}
static TypeError throwsTypeError(void f(), [String reason = "TypeError"]) =>
Expect.throws<TypeError>(f, _defaultCheck, reason);
static void throwsUnsupportedError(void f(),
[String reason = "UnsupportedError"]) {
Expect.throws(f, (error) => error is UnsupportedError, reason);
}
static UnsupportedError throwsUnsupportedError(void f(),
[String reason = "UnsupportedError"]) =>
Expect.throws<UnsupportedError>(f, _defaultCheck, reason);
/// Reports that there is an error in the test itself and not the code under
/// test.
@ -748,20 +759,20 @@ class ExpectException {
_getTestName = getName;
}
// TODO(rnystrom): Type this `String Function()?` once this library doesn't
// need to be NNBD-agnostic.
static dynamic _getTestName;
static String Function() _getTestName = _kEmptyString;
final String message;
final String name;
ExpectException(this.message)
: name = (_getTestName == null) ? "" : _getTestName();
ExpectException(this.message) : name = _getTestName();
String toString() {
if (name != "") return 'In test "$name" $message';
return message;
}
/// Initial value for _getTestName.
static String _kEmptyString() => "";
}
/// Is true iff type assertions are enabled.
@ -769,7 +780,7 @@ class ExpectException {
final bool typeAssertionsEnabled = (() {
try {
dynamic i = 42;
String s = i;
String s = i; // ignore: unused_local_variable
} on TypeError {
return true;
}

View file

@ -6,7 +6,7 @@ import "package:expect/expect.dart";
final bool strong = () {
try {
int i = null as dynamic;
int i = null as dynamic; // ignore: unused_local_variable
return false;
} catch (e) {
return true;

View file

@ -56,7 +56,7 @@ static method main() → void {
new self::A::•();
new self::B::•();
self::C<core::num> c = new self::D::•();
exp::Expect::throws<dynamic>(() → void {
exp::Expect::throws<core::Object>(() → void {
[@vm.call-site-attributes.metadata=receiverType:#lib::C<dart.core::num>] [@vm.direct-call.metadata=#lib::D.bar] c.{self::C::bar} = 3.14;
});
self::E e = new self::F::•();

View file

@ -9,11 +9,14 @@ void main() {
asyncTest(() async {
// Null stream.
dynamic nullStream = null;
asyncExpectThrows<Error>(
() async => <int>[await for (var i in nullStream) 1]);
asyncExpectThrows<Error>(
() async => <int, int>{await for (var i in nullStream) 1: 1});
asyncExpectThrows<Error>(
() async => <int>{await for (var i in nullStream) 1});
asyncExpectThrows<Error>(() async {
<int>[await for (var i in nullStream) 1];
}());
asyncExpectThrows<Error>(() async {
<int, int>{await for (var i in nullStream) 1: 1};
}());
asyncExpectThrows<Error>(() async {
<int>{await for (var i in nullStream) 1};
}());
});
}

View file

@ -30,17 +30,28 @@ Future<void> testList() async {
Expect.listEquals(list, <int>[await for (var i in stream(list)) i]);
// Await for at beginning.
Expect.listEquals(list, <int>[await for (var i in stream([1, 2])) i, 3, 4]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, 2])) i,
3,
4
]);
// Await for in middle.
Expect.listEquals(list, <int>[1, await for (var i in stream([2, 3])) i, 4]);
Expect.listEquals(list, <int>[
1,
await for (var i in stream([2, 3])) i,
4
]);
// Await for at end.
Expect.listEquals(list, <int>[1, 2, await for (var i in stream([3, 4])) i]);
Expect.listEquals(list, <int>[
1,
2,
await for (var i in stream([3, 4])) i
]);
// Empty await for.
Expect.listEquals(list,
<int>[1, 2, await for (var i in stream([])) i, 3, 4]);
Expect.listEquals(list, <int>[1, 2, await for (var i in stream([])) i, 3, 4]);
// Multiple await fors.
Expect.listEquals(list, <int>[
@ -50,26 +61,44 @@ Future<void> testList() async {
]);
// Spread inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]]);
Expect.listEquals(list, <int>[
await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]
]);
// If inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i
]);
// Else inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i else i]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i else i
]);
// For inside await for.
Expect.listEquals(list, <int>[
await for (var i in stream([0, 2])) for (var j = 1; j <= 2; j++) i + j
await for (var i in stream([0, 2]))
for (var j = 1; j <= 2; j++) i + j
]);
// Does not flatten nested collection literal.
Expect.listEquals([1], [await for (var i in stream([1])) [i]].first);
Expect.mapEquals({1: 1}, [await for (var i in stream([1])) {i: i}].first);
Expect.setEquals({1}, [await for (var i in stream([1])) {i}].first);
Expect.listEquals(
[1],
[
await for (var i in stream([1])) [i]
].first);
Expect.mapEquals(
{1: 1},
[
await for (var i in stream([1])) {i: i}
].first);
Expect.setEquals(
{1},
[
await for (var i in stream([1])) {i}
].first);
}
Future<void> testMap() async {
@ -77,26 +106,30 @@ Future<void> testMap() async {
Expect.mapEquals(map, <int, int>{await for (var i in stream(list)) i: i});
// Await for at beginning.
Expect.mapEquals(map,
<int, int>{await for (var i in stream([1, 2])) i: i, 3: 3, 4: 4});
// Await for in middle.
Expect.mapEquals(map,
<int, int>{1: 1, await for (var i in stream([2, 3])) i: i, 4: 4});
// Await for at end.
Expect.mapEquals(map,
<int, int>{1: 1, 2: 2, await for (var i in stream([3, 4])) i: i});
// Empty await for.
Expect.mapEquals(map, <int, int>{
1: 1,
await for (var i in stream([])) i: i,
2: 2,
await for (var i in stream([1, 2])) i: i,
3: 3,
4: 4
});
// Await for in middle.
Expect.mapEquals(map, <int, int>{
1: 1,
await for (var i in stream([2, 3])) i: i,
4: 4
});
// Await for at end.
Expect.mapEquals(map, <int, int>{
1: 1,
2: 2,
await for (var i in stream([3, 4])) i: i
});
// Empty await for.
Expect.mapEquals(map,
<int, int>{1: 1, await for (var i in stream([])) i: i, 2: 2, 3: 3, 4: 4});
// Multiple await fors.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1])) i: i,
@ -106,18 +139,22 @@ Future<void> testMap() async {
// Spread inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([0, 2]))
...<int, int>{1 + i: 1 + i, 2 + i: 2 + i}
await for (var i in stream([0, 2])) ...<int, int>{
1 + i: 1 + i,
2 + i: 2 + i
}
});
// If inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i: i
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i: i
});
// Else inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i: -i else i: i
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i: -i else i: i
});
// For inside await for.
@ -132,17 +169,28 @@ Future<void> testSet() async {
Expect.setEquals(set, <int>{await for (var i in stream(list)) i});
// Await for at beginning.
Expect.setEquals(set, <int>{await for (var i in stream([1, 2])) i, 3, 4});
Expect.setEquals(set, <int>{
await for (var i in stream([1, 2])) i,
3,
4
});
// Await for in middle.
Expect.setEquals(set, <int>{1, await for (var i in stream([2, 3])) i, 4});
Expect.setEquals(set, <int>{
1,
await for (var i in stream([2, 3])) i,
4
});
// Await for at end.
Expect.setEquals(set, <int>{1, 2, await for (var i in stream([3, 4])) i});
Expect.setEquals(set, <int>{
1,
2,
await for (var i in stream([3, 4])) i
});
// Empty await for.
Expect.setEquals(set,
<int>{1, await for (var i in stream([])) i, 2, 3, 4});
Expect.setEquals(set, <int>{1, await for (var i in stream([])) i, 2, 3, 4});
// Multiple await fors.
Expect.setEquals(set, <int>{
@ -152,26 +200,44 @@ Future<void> testSet() async {
});
// Spread inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]});
Expect.setEquals(set, <int>{
await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]
});
// If inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i});
Expect.setEquals(set, <int>{
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i
});
// Else inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i else i});
Expect.setEquals(set, <int>{
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i else i
});
// For inside await for.
Expect.setEquals(set, <int>{
await for (var i in stream([0, 2])) for (var j = 1; j <= 2; j++) i + j
await for (var i in stream([0, 2]))
for (var j = 1; j <= 2; j++) i + j
});
// Does not flatten nested collection literal.
Expect.listEquals([1], {await for (var i in stream([1])) [i]}.first);
Expect.mapEquals({1: 1}, {await for (var i in stream([1])) {i: i}}.first);
Expect.setEquals({1}, {await for (var i in stream([1])) {i}}.first);
Expect.listEquals(
[1],
{
await for (var i in stream([1])) [i]
}.first);
Expect.mapEquals(
{1: 1},
{
await for (var i in stream([1])) {i: i}
}.first);
Expect.setEquals(
{1},
{
await for (var i in stream([1])) {i}
}.first);
}
Future<void> testDuplicateKeys() async {
@ -207,28 +273,46 @@ Future<void> testKeyOrder() async {
Expect.equals("1:a,2:a", map.keys.join(","));
Expect.equals("2,4", map.values.join(","));
var set = <Equality>{e1a, await for (var i in stream([0, 1, 2])) keys[i]};
var set = <Equality>{
e1a,
await for (var i in stream([0, 1, 2])) keys[i]
};
Expect.equals("1:a,2:a", set.join(","));
}
Future<void> testRuntimeErrors() async {
// Cast variable.
dynamic nonStream = 3;
asyncExpectThrows<TypeError>(
() async => <int>[await for (int i in nonStream) 1]);
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (int i in nonStream) 1: 1});
asyncExpectThrows<TypeError>(
() async => <int>{await for (int i in nonStream) 1});
asyncExpectThrows<TypeError>(() async {
<int>[await for (int i in nonStream) 1];
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{await for (int i in nonStream) 1: 1};
}());
asyncExpectThrows<TypeError>(() async {
<int>{await for (int i in nonStream) 1};
}());
// Wrong element type.
dynamic nonInt = "string";
asyncExpectThrows<TypeError>(
() async => <int>[await for (var i in stream([1])) nonInt]);
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (var i in stream([1])) nonInt: 1});
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (var i in stream([1])) 1: nonInt});
asyncExpectThrows<TypeError>(
() async => <int>{await for (var i in stream([1])) nonInt});
asyncExpectThrows<TypeError>(() async {
<int>[
await for (var i in stream([1])) nonInt
];
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{
await for (var i in stream([1])) nonInt: 1
};
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{
await for (var i in stream([1])) 1: nonInt
};
}());
asyncExpectThrows<TypeError>(() async {
<int>{
await for (var i in stream([1])) nonInt
};
}());
}

View file

@ -11,11 +11,14 @@ void main() {
asyncTest(() async {
// Null stream.
Stream<int> nullStream = null;
asyncExpectThrows<Error>(
() async => <int>[await for (var i in nullStream) 1]);
asyncExpectThrows<Error>(
() async => <int, int>{await for (var i in nullStream) 1: 1});
asyncExpectThrows<Error>(
() async => <int>{await for (var i in nullStream) 1});
asyncExpectThrows<Error>(() async {
<int>[await for (var i in nullStream) 1];
}());
asyncExpectThrows<Error>(() async {
<int, int>{await for (var i in nullStream) 1: 1};
}());
asyncExpectThrows<Error>(() async {
<int>{await for (var i in nullStream) 1};
}());
});
}

View file

@ -32,17 +32,28 @@ Future<void> testList() async {
Expect.listEquals(list, <int>[await for (var i in stream(list)) i]);
// Await for at beginning.
Expect.listEquals(list, <int>[await for (var i in stream([1, 2])) i, 3, 4]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, 2])) i,
3,
4
]);
// Await for in middle.
Expect.listEquals(list, <int>[1, await for (var i in stream([2, 3])) i, 4]);
Expect.listEquals(list, <int>[
1,
await for (var i in stream([2, 3])) i,
4
]);
// Await for at end.
Expect.listEquals(list, <int>[1, 2, await for (var i in stream([3, 4])) i]);
Expect.listEquals(list, <int>[
1,
2,
await for (var i in stream([3, 4])) i
]);
// Empty await for.
Expect.listEquals(list,
<int>[1, 2, await for (var i in stream([])) i, 3, 4]);
Expect.listEquals(list, <int>[1, 2, await for (var i in stream([])) i, 3, 4]);
// Multiple await fors.
Expect.listEquals(list, <int>[
@ -52,38 +63,58 @@ Future<void> testList() async {
]);
// Spread inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]]);
Expect.listEquals(list, <int>[
await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]
]);
// If inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i
]);
// Else inside await for.
Expect.listEquals(list,
<int>[await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i else i]);
Expect.listEquals(list, <int>[
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i else i
]);
// For inside await for.
Expect.listEquals(list, <int>[
await for (var i in stream([0, 2])) for (var j = 1; j <= 2; j++) i + j
await for (var i in stream([0, 2]))
for (var j = 1; j <= 2; j++) i + j
]);
// Does not flatten nested collection literal.
Expect.listEquals([1], [await for (var i in stream([1])) [i]].first);
Expect.mapEquals({1: 1}, [await for (var i in stream([1])) {i: i}].first);
Expect.setEquals({1}, [await for (var i in stream([1])) {i}].first);
Expect.listEquals(
[1],
[
await for (var i in stream([1])) [i]
].first);
Expect.mapEquals(
{1: 1},
[
await for (var i in stream([1])) {i: i}
].first);
Expect.setEquals(
{1},
[
await for (var i in stream([1])) {i}
].first);
// Downcast stream.
Object obj = stream([1, 2, 3, 4]);
Expect.listEquals(list, <int>[await for (var n in obj) n]);
// Downcast variable.
Expect.listEquals(list,
<int>[await for (int n in numStream([1, 2, 3, 4])) n]);
Expect.listEquals(list, <int>[
await for (int n in numStream([1, 2, 3, 4])) n
]);
// Downcast element.
Expect.listEquals(list,
<int>[await for (num n in numStream([1, 2, 3, 4])) n]);
Expect.listEquals(list, <int>[
await for (num n in numStream([1, 2, 3, 4])) n
]);
}
Future<void> testMap() async {
@ -91,26 +122,30 @@ Future<void> testMap() async {
Expect.mapEquals(map, <int, int>{await for (var i in stream(list)) i: i});
// Await for at beginning.
Expect.mapEquals(map,
<int, int>{await for (var i in stream([1, 2])) i: i, 3: 3, 4: 4});
// Await for in middle.
Expect.mapEquals(map,
<int, int>{1: 1, await for (var i in stream([2, 3])) i: i, 4: 4});
// Await for at end.
Expect.mapEquals(map,
<int, int>{1: 1, 2: 2, await for (var i in stream([3, 4])) i: i});
// Empty await for.
Expect.mapEquals(map, <int, int>{
1: 1,
await for (var i in stream([])) i: i,
2: 2,
await for (var i in stream([1, 2])) i: i,
3: 3,
4: 4
});
// Await for in middle.
Expect.mapEquals(map, <int, int>{
1: 1,
await for (var i in stream([2, 3])) i: i,
4: 4
});
// Await for at end.
Expect.mapEquals(map, <int, int>{
1: 1,
2: 2,
await for (var i in stream([3, 4])) i: i
});
// Empty await for.
Expect.mapEquals(map,
<int, int>{1: 1, await for (var i in stream([])) i: i, 2: 2, 3: 3, 4: 4});
// Multiple await fors.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1])) i: i,
@ -120,18 +155,22 @@ Future<void> testMap() async {
// Spread inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([0, 2]))
...<int, int>{1 + i: 1 + i, 2 + i: 2 + i}
await for (var i in stream([0, 2])) ...<int, int>{
1 + i: 1 + i,
2 + i: 2 + i
}
});
// If inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i: i
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i: i
});
// Else inside await for.
Expect.mapEquals(map, <int, int>{
await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i: -i else i: i
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i: -i else i: i
});
// For inside await for.
@ -145,12 +184,14 @@ Future<void> testMap() async {
Expect.mapEquals(map, <int, int>{await for (var n in obj) n: n});
// Downcast variable.
Expect.mapEquals(map,
<int, int>{await for (int n in numStream([1, 2, 3, 4])) n: n});
Expect.mapEquals(map, <int, int>{
await for (int n in numStream([1, 2, 3, 4])) n: n
});
// Downcast element.
Expect.mapEquals(map,
<int, int>{await for (num n in numStream([1, 2, 3, 4])) n: n});
Expect.mapEquals(map, <int, int>{
await for (num n in numStream([1, 2, 3, 4])) n: n
});
}
Future<void> testSet() async {
@ -158,17 +199,28 @@ Future<void> testSet() async {
Expect.setEquals(set, <int>{await for (var i in stream(list)) i});
// Await for at beginning.
Expect.setEquals(set, <int>{await for (var i in stream([1, 2])) i, 3, 4});
Expect.setEquals(set, <int>{
await for (var i in stream([1, 2])) i,
3,
4
});
// Await for in middle.
Expect.setEquals(set, <int>{1, await for (var i in stream([2, 3])) i, 4});
Expect.setEquals(set, <int>{
1,
await for (var i in stream([2, 3])) i,
4
});
// Await for at end.
Expect.setEquals(set, <int>{1, 2, await for (var i in stream([3, 4])) i});
Expect.setEquals(set, <int>{
1,
2,
await for (var i in stream([3, 4])) i
});
// Empty await for.
Expect.setEquals(set,
<int>{1, await for (var i in stream([])) i, 2, 3, 4});
Expect.setEquals(set, <int>{1, await for (var i in stream([])) i, 2, 3, 4});
// Multiple await fors.
Expect.setEquals(set, <int>{
@ -178,36 +230,58 @@ Future<void> testSet() async {
});
// Spread inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]});
Expect.setEquals(set, <int>{
await for (var i in stream([0, 2])) ...<int>[1 + i, 2 + i]
});
// If inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([1, 9, 2, 3, 9, 4])) if (i != 9) i});
Expect.setEquals(set, <int>{
await for (var i in stream([1, 9, 2, 3, 9, 4]))
if (i != 9) i
});
// Else inside await for.
Expect.setEquals(set,
<int>{await for (var i in stream([1, -2, 3, -4])) if (i < 0) -i else i});
Expect.setEquals(set, <int>{
await for (var i in stream([1, -2, 3, -4]))
if (i < 0) -i else i
});
// For inside await for.
Expect.setEquals(set, <int>{
await for (var i in stream([0, 2])) for (var j = 1; j <= 2; j++) i + j
await for (var i in stream([0, 2]))
for (var j = 1; j <= 2; j++) i + j
});
// Does not flatten nested collection literal.
Expect.listEquals([1], {await for (var i in stream([1])) [i]}.first);
Expect.mapEquals({1: 1}, {await for (var i in stream([1])) {i: i}}.first);
Expect.setEquals({1}, {await for (var i in stream([1])) {i}}.first);
Expect.listEquals(
[1],
{
await for (var i in stream([1])) [i]
}.first);
Expect.mapEquals(
{1: 1},
{
await for (var i in stream([1])) {i: i}
}.first);
Expect.setEquals(
{1},
{
await for (var i in stream([1])) {i}
}.first);
// Downcast stream.
Object obj = stream([1, 2, 3, 4]);
Expect.setEquals(set, <int>{await for (var n in obj) n});
// Downcast variable.
Expect.setEquals(set, <int>{await for (int n in numStream([1, 2, 3, 4])) n});
Expect.setEquals(set, <int>{
await for (int n in numStream([1, 2, 3, 4])) n
});
// Downcast element.
Expect.setEquals(set, <int>{await for (num n in numStream([1, 2, 3, 4])) n});
Expect.setEquals(set, <int>{
await for (num n in numStream([1, 2, 3, 4])) n
});
}
Future<void> testDuplicateKeys() async {
@ -243,28 +317,46 @@ Future<void> testKeyOrder() async {
Expect.equals("1:a,2:a", map.keys.join(","));
Expect.equals("2,4", map.values.join(","));
var set = <Equality>{e1a, await for (var i in stream([0, 1, 2])) keys[i]};
var set = <Equality>{
e1a,
await for (var i in stream([0, 1, 2])) keys[i]
};
Expect.equals("1:a,2:a", set.join(","));
}
Future<void> testRuntimeErrors() async {
// Cast variable.
dynamic nonStream = 3;
asyncExpectThrows<TypeError>(
() async => <int>[await for (int i in nonStream) 1]);
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (int i in nonStream) 1: 1});
asyncExpectThrows<TypeError>(
() async => <int>{await for (int i in nonStream) 1});
asyncExpectThrows<TypeError>(() async {
<int>[await for (int i in nonStream) 1];
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{await for (int i in nonStream) 1: 1};
}());
asyncExpectThrows<TypeError>(() async {
<int>{await for (int i in nonStream) 1};
}());
// Wrong element type.
dynamic nonInt = "string";
asyncExpectThrows<TypeError>(
() async => <int>[await for (var i in stream([1])) nonInt]);
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (var i in stream([1])) nonInt: 1});
asyncExpectThrows<TypeError>(
() async => <int, int>{await for (var i in stream([1])) 1: nonInt});
asyncExpectThrows<TypeError>(
() async => <int>{await for (var i in stream([1])) nonInt});
asyncExpectThrows<TypeError>(() async {
<int>[
await for (var i in stream([1])) nonInt
];
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{
await for (var i in stream([1])) nonInt: 1
};
}());
asyncExpectThrows<TypeError>(() async {
<int, int>{
await for (var i in stream([1])) 1: nonInt
};
}());
asyncExpectThrows<TypeError>(() async {
<int>{
await for (var i in stream([1])) nonInt
};
}());
}

View file

@ -42,8 +42,9 @@ main() {
}
Future<void> testRejectedPromise() async {
asyncExpectThrows<String>(() => js_util.promiseToFuture(rejectedPromise),
(String error) => error == 'rejected');
final String error = await asyncExpectThrows<String>(
js_util.promiseToFuture(rejectedPromise));
expect(error, equals('rejected'));
}
Future<void> testReturnResolvedPromise() async {

View file

@ -44,8 +44,9 @@ main() {
}
Future<void> testRejectedPromise() async {
asyncExpectThrows<String>(() => js_util.promiseToFuture(rejectedPromise),
(String error) => error == 'rejected');
final String error = await asyncExpectThrows<String>(
js_util.promiseToFuture(rejectedPromise));
expect(error, equals('rejected'));
}
Future<void> testReturnResolvedPromise() async {

View file

@ -17,19 +17,15 @@ Future<void> testFormatException() async {
request.response.close();
});
final completer = Completer<void>();
// The character is U+2019 RIGHT SINGLE QUOTATION MARK.
final client = HttpClient()..userAgent = 'Bobs browser';
asyncExpectThrows<FormatException>(() async {
try {
await client.open("CONNECT", "127.0.0.1", server.port, "/");
} finally {
client.close(force: true);
server.close();
completer.complete();
}
});
await completer.future;
try {
await asyncExpectThrows<FormatException>(
client.open("CONNECT", "127.0.0.1", server.port, "/"));
} finally {
client.close(force: true);
server.close();
}
}
main() {

View file

@ -161,17 +161,17 @@ class LinkMock extends FileSystemEntity implements Link {
}
Future<Socket> socketConnect(dynamic host, int port,
{dynamic sourceAddress, int sourcePort = 0, Duration? timeout}) {
{dynamic sourceAddress, int sourcePort = 0, Duration? timeout}) async {
throw "";
}
Future<ConnectionTask<Socket>> socketStartConnect(dynamic host, int port,
{dynamic sourceAddress, int sourcePort = 0}) {
{dynamic sourceAddress, int sourcePort = 0}) async {
throw "";
}
Future<ServerSocket> serverSocketBind(dynamic address, int port,
{int backlog: 0, bool v6Only: false, bool shared: false}) {
{int backlog: 0, bool v6Only: false, bool shared: false}) async {
throw "";
}
@ -217,9 +217,9 @@ Future<Null> ioOverridesRunTest() async {
Expect.identical(
_mockFileSystemEvent, new Directory("directory").watch());
Expect.isTrue(new Link("link") is LinkMock);
asyncExpectThrows(() async => await Socket.connect(null, 0));
asyncExpectThrows(() async => await Socket.startConnect(null, 0));
asyncExpectThrows(() async => await ServerSocket.bind(null, 0));
asyncExpectThrows(Socket.connect(null, 0));
asyncExpectThrows(Socket.startConnect(null, 0));
asyncExpectThrows(ServerSocket.bind(null, 0));
Expect.isTrue(stdin is StdinMock);
Expect.identical(stdout, stdoutMock);
Expect.identical(stderr, stderrMock);

View file

@ -19,19 +19,15 @@ Future<void> testFormatException() async {
request.response.close();
});
final completer = Completer<void>();
// The character is U+2019 RIGHT SINGLE QUOTATION MARK.
final client = HttpClient()..userAgent = 'Bobs browser';
asyncExpectThrows<FormatException>(() async {
try {
await client.open("CONNECT", "127.0.0.1", server.port, "/");
} finally {
client.close(force: true);
server.close();
completer.complete();
}
});
await completer.future;
try {
await asyncExpectThrows<FormatException>(
client.open("CONNECT", "127.0.0.1", server.port, "/"));
} finally {
client.close(force: true);
server.close();
}
}
main() {