dart-sdk/pkg/expect/lib/minitest.dart
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

210 lines
6.5 KiB
Dart

// Copyright (c) 2016, 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 (especially HTML)
/// tests.
///
/// 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:expect/expect.dart';
typedef dynamic _Action();
typedef void _ExpectationFunction(dynamic actual);
final List<_Group> _groups = [new _Group()];
final Object isFalse = new _Expectation(Expect.isFalse);
final Object isNotNull = new _Expectation(Expect.isNotNull);
final Object isNull = new _Expectation(Expect.isNull);
final Object isTrue = new _Expectation(Expect.isTrue);
final Object returnsNormally = new _Expectation((actual) {
try {
(actual as _Action)();
} catch (error) {
Expect.fail("Expected function to return normally, but threw:\n$error");
}
});
final Object throws = new _Expectation((actual) {
Expect.throws(actual as _Action);
});
final Object throwsArgumentError = new _Expectation((actual) {
Expect.throws(actual as _Action, (error) => error is ArgumentError);
});
final Object throwsNoSuchMethodError = new _Expectation((actual) {
Expect.throws(actual as _Action, (error) => error is NoSuchMethodError);
});
final Object throwsRangeError = new _Expectation((actual) {
Expect.throws(actual as _Action, (error) => error is RangeError);
});
final Object throwsStateError = new _Expectation((actual) {
Expect.throws(actual as _Action, (error) => error is StateError);
});
final Object throwsUnsupportedError = new _Expectation((actual) {
Expect.throws(actual as _Action, (error) => error is UnsupportedError);
});
/// The test runner should call this once after running a test file.
void finishTests() {
_groups.clear();
_groups.add(new _Group());
}
void group(String description, body()) {
// TODO(rnystrom): Do something useful with the description.
_groups.add(new _Group());
try {
var result = body();
if (result is Future) {
Expect.testError("group() does not support asynchronous functions.");
}
} finally {
_groups.removeLast();
}
}
void test(String description, body()) {
// TODO(rnystrom): Do something useful with the description.
for (var group in _groups) {
var result = group.setUpFunction();
if (result is Future) {
Expect.testError("setUp() does not support asynchronous functions.");
}
}
try {
var result = body();
if (result is Future) {
Expect.testError("test() does not support asynchronous functions.");
}
} finally {
for (var i = _groups.length - 1; i >= 0; i--) {
var group = _groups[i];
var result = group.tearDownFunction();
if (result is Future) {
Expect.testError("tearDown() does not support asynchronous functions.");
}
}
}
}
void setUp(body()) {
// Can't define multiple setUps at the same level.
assert(_groups.last.setUpFunction == _defaultAction);
_groups.last.setUpFunction = body;
}
void tearDown(body()) {
// Can't define multiple tearDowns at the same level.
assert(_groups.last.tearDownFunction == _defaultAction);
_groups.last.tearDownFunction = body;
}
void expect(dynamic actual, dynamic expected, {String reason = ""}) {
// TODO(rnystrom): Do something useful with reason.
if (expected is! _Expectation) {
expected = equals(expected);
}
var expectation = expected as _Expectation;
expectation.function(actual);
}
void fail(String message) {
Expect.fail(message);
}
Object equals(dynamic value) => new _Expectation((actual) {
Expect.deepEquals(value, actual);
});
Object notEquals(dynamic value) => new _Expectation((actual) {
Expect.notEquals(value, actual);
});
Object unorderedEquals(dynamic value) => new _Expectation((actual) {
Expect.setEquals(value as Iterable, actual as Iterable);
});
Object predicate(bool fn(dynamic value), [String description = ""]) =>
new _Expectation((actual) {
Expect.isTrue(fn(actual), description);
});
Object inInclusiveRange(num min, num max) => new _Expectation((actual) {
var actualNum = actual as num;
if (actualNum < min || actualNum > max) {
fail("Expected $actualNum to be in the inclusive range [$min, $max].");
}
});
Object greaterThan(num value) => new _Expectation((actual) {
var actualNum = actual as num;
if (actualNum <= value) {
fail("Expected $actualNum to be greater than $value.");
}
});
Object same(dynamic value) => new _Expectation((actual) {
Expect.identical(value, actual);
});
Object closeTo(num value, num tolerance) => new _Expectation((actual) {
Expect.approxEquals(value, actual as num, tolerance);
});
/// Succeeds if the actual value is any of the given strings. Unlike matcher's
/// [anyOf], this only works with strings and requires an explicit list.
Object anyOf(List<String> expected) => new _Expectation((actual) {
for (var string in expected) {
if (actual == string) return;
}
fail("Expected $actual to be one of $expected.");
});
_defaultAction() {}
/// One level of group() nesting to track an optional [setUp()] and [tearDown()]
/// function for the group.
///
/// There is also an implicit top level group.
class _Group {
_Action setUpFunction = _defaultAction;
_Action tearDownFunction = _defaultAction;
}
/// A wrapper around an expectation function.
///
/// This function is passed the actual value and should throw an
/// [ExpectException] if the value doesn't match the expectation.
class _Expectation {
final _ExpectationFunction function;
_Expectation(this.function);
}