Files
sdk/pkg/async_helper/lib/async_minitest.dart
T
Robert Nystrom d9bb487ca8 Treat the expect and async_helper packages as opted in to NNBD.
This should enable strong mode tests to be fully NNBD opted in. At the
same time, legacy tests when run with the experiment off should
hopefully be able to still consume these libraries because they don't
actually use any NNBD features.

To do this, I changed the script that generates the SDK repo's package
config to not put in a language version for any package whose pubspec
has no SDK version. According to language versioning, that means the
package should be considered to be at the "current" version of the SDK
running the code.

In NNBD, that's opted in. With the experiment off, that is (presumably)
"opted out" in the sense that NNBD doesn't exist.

In order to *not* opt in some of the other packages that currently
lack SDK constraints, I put those in and pinned them to "^2.7.0" which
was what the package config script used to implicitly fill in for them.

I see a bunch of other changes in the generated package config too. The
update script probably hasn't been run in a while.

Change-Id: I55193d42eac0696a6b0105546551efa45a1f3252
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144305
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Bob Nystrom <rnystrom@google.com>
2020-04-27 21:04:56 +00:00

334 lines
7.6 KiB
Dart

// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// A minimal, dependency-free emulation layer for a subset of the
/// unittest/test API used by the language and core library.
///
/// Compared with `minitest.dart`, this library supports and expects
/// asynchronous tests. It uses a `Zone` per test to associate a test name with
/// the failure.
///
/// It does not support `setUp` or `tearDown` methods,
/// and matchers are severely restricted.
///
/// A number of our language and core library tests were written against the
/// unittest package, which is now deprecated in favor of the new test package.
/// The latter is much better feature-wise, but is also quite complex and has
/// many dependencies. For low-level language and core library tests, we don't
/// want to have to pull in a large number of dependencies and be able to run
/// them correctly in order to run a test, so we want to test them against
/// something simpler.
///
/// When possible, we just use the tiny expect library. But to avoid rewriting
/// all of the existing tests that use unittest, they can instead use this,
/// which shims the unittest API with as little code as possible and calls into
/// expect.
///
/// Eventually, it would be good to refactor those tests to use the expect
/// package directly and remove this.
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
void group(String name, body()) {
var oldName = _pushName(name);
try {
body();
} finally {
_popName(oldName);
}
}
void test(String name, body()) {
var oldName = _pushName(name);
asyncStart();
var result = runZoned(body, zoneValues: {_testToken: _currentName});
if (result is Future) {
result.then((_) {
asyncEnd();
});
} else {
// Ensure all tests get to be set up first.
scheduleMicrotask(asyncEnd);
}
_popName(oldName);
}
void expect(dynamic value, dynamic matcher, {String reason = ""}) {
Matcher m;
if (matcher is _Matcher) {
m = matcher.call;
} else if (matcher is! Matcher) {
m = equals(matcher);
} else {
m = matcher;
}
m(value);
}
R Function() expectAsync0<R>(R Function() f, {int count = 1}) {
asyncStart(count);
return () {
var result = f();
asyncEnd();
return result;
};
}
R Function(A) expectAsync1<R, A>(R Function(A) f, {int count = 1}) {
asyncStart(count);
return (A a) {
var result = f(a);
asyncEnd();
return result;
};
}
R Function(A, B) expectAsync2<R, A, B>(R Function(A, B) f, {int count = 1}) {
asyncStart(count);
return (A a, B b) {
var result = f(a, b);
asyncEnd();
return result;
};
}
dynamic expectAsync(Function f, {int count = 1}) {
var f2 = f; // Avoid type-promoting f, we want dynamic invocations.
if (f2 is Function(Never, Never, Never, Never, Never)) {
asyncStart(count);
return ([a, b, c, d, e]) {
var result = f(a, b, c, d, e);
asyncEnd();
return result;
};
}
if (f2 is Function(Never, Never, Never, Never)) {
asyncStart(count);
return ([a, b, c, d]) {
var result = f(a, b, c, d);
asyncEnd();
return result;
};
}
if (f2 is Function(Never, Never, Never)) {
asyncStart(count);
return ([a, b, c]) {
var result = f(a, b, c);
asyncEnd();
return result;
};
}
if (f2 is Function(Never, Never)) {
asyncStart(count);
return ([a, b]) {
var result = f(a, b);
asyncEnd();
return result;
};
}
if (f2 is Function(Never)) {
asyncStart(count);
return ([a]) {
var result = f(a);
asyncEnd();
return result;
};
}
if (f2 is Function()) {
asyncStart(count);
return () {
var result = f();
asyncEnd();
return result;
};
}
throw new UnsupportedError(
"expectAsync only accepts up to five argument functions");
}
// Matchers
typedef Matcher = void Function(dynamic);
Matcher same(dynamic o) => (v) {
Expect.identical(o, v);
};
Matcher equals(dynamic o) => (v) {
Expect.deepEquals(o, v);
};
Matcher greaterThan(num n) => (dynamic v) {
Expect.type<num>(v);
num value = v;
if (value > n) return;
Expect.fail("$v is not greater than $n");
};
Matcher greaterThanOrEqualTo(num n) => (dynamic v) {
Expect.type<num>(v);
num value = v;
if (value >= n) return;
Expect.fail("$v is not greater than $n");
};
Matcher lessThan(num n) => (dynamic v) {
Expect.type<num>(v);
num value = v;
if (value < n) return;
Expect.fail("$v is not less than $n");
};
Matcher lessThanOrEqualTo(num n) => (dynamic v) {
Expect.type<num>(v);
num value = v;
if (value <= n) return;
Expect.fail("$v is not less than $n");
};
Matcher predicate(bool fn(dynamic value), [String description = ""]) =>
(dynamic v) {
Expect.isTrue(fn(v), description);
};
Matcher anyOf(List<String> expected) => (dynamic actual) {
for (var string in expected) {
if (actual == string) return;
}
Expect.fail("Expected $actual to be one of $expected.");
};
void isTrue(dynamic v) {
Expect.isTrue(v);
}
void isFalse(dynamic v) {
Expect.isFalse(v);
}
void isNull(dynamic o) {
Expect.isNull(o);
}
void _checkThrow<T>(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);
asyncEnd();
});
return;
}
Expect.throws<T>(v, (e) {
onError(e);
return true;
});
}
void returnsNormally(dynamic o) {
try {
Expect.type<Function()>(o);
o();
} catch (error, trace) {
Expect.fail(
"Expected function to return normally, but threw:\n$error\n\n$trace");
}
}
void throws(dynamic v) {
_checkThrow<Object>(v, (_) {});
}
Matcher throwsA(matcher) => (dynamic o) {
_checkThrow<Object>(o, (error) {
expect(error, matcher);
});
};
Matcher completion(matcher) => (dynamic o) {
Expect.type<Future>(o);
Future future = o;
asyncStart();
future.then((value) {
expect(value, matcher);
asyncEnd();
});
};
void completes(dynamic o) {
Expect.type<Future>(o);
Future future = o;
asyncStart();
future.then(asyncSuccess);
}
void isMap(dynamic o) {
Expect.type<Map>(o);
}
void isList(dynamic o) {
Expect.type<List>(o);
}
void isNotNull(dynamic o) {
Expect.isNotNull(o);
}
abstract class _Matcher {
void call(dynamic o);
}
class isInstanceOf<T> implements _Matcher {
void call(dynamic o) {
Expect.type<T>(o);
}
}
void throwsArgumentError(dynamic v) {
_checkThrow<ArgumentError>(v, (_) {});
}
void throwsStateError(dynamic v) {
_checkThrow<StateError>(v, (_) {});
}
void fail(String message) {
Expect.fail("$message");
}
/// Key for zone value holding current test name.
final _testToken = Object();
bool _initializedTestNameCallback = false;
/// The current combined name of the nesting [group] or [test].
String _currentName = "";
String _pushName(String newName) {
// Look up the current test name from the zone created for the test.
if (!_initializedTestNameCallback) {
ExpectException.setTestNameCallback(() => Zone.current[_testToken]);
_initializedTestNameCallback = true;
}
var oldName = _currentName;
if (oldName == "") {
_currentName = newName;
} else {
_currentName = "$oldName $newName";
}
return oldName;
}
void _popName(String oldName) {
_currentName = oldName;
}