56d59dd967
Change-Id: If8e2ec2ca1ac4f533dcb56b0c95d55e4a13e0598 Reviewed-on: https://dart-review.googlesource.com/39881 Reviewed-by: Paul Berry <paulberry@google.com>
213 lines
6.5 KiB
Dart
213 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(Object 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) {
|
|
if (group.setUpFunction != null) {
|
|
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];
|
|
if (group.tearDownFunction != null) {
|
|
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 == null);
|
|
_groups.last.setUpFunction = body;
|
|
}
|
|
|
|
void tearDown(body()) {
|
|
// Can't define multiple tearDowns at the same level.
|
|
assert(_groups.last.tearDownFunction == null);
|
|
_groups.last.tearDownFunction = body;
|
|
}
|
|
|
|
void expect(Object actual, Object 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(Object value) => new _Expectation((actual) {
|
|
Expect.deepEquals(value, actual);
|
|
});
|
|
|
|
Object notEquals(Object value) => new _Expectation((actual) {
|
|
Expect.notEquals(value, actual);
|
|
});
|
|
|
|
Object unorderedEquals(Object value) => new _Expectation((actual) {
|
|
Expect.setEquals(value, actual);
|
|
});
|
|
|
|
Object predicate(bool fn(Object 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(Object value) => new _Expectation((actual) {
|
|
Expect.identical(value, actual);
|
|
});
|
|
|
|
Object closeTo(num value, num tolerance) => new _Expectation((actual) {
|
|
Expect.approxEquals(value, actual, 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.");
|
|
});
|
|
|
|
/// 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;
|
|
_Action tearDownFunction;
|
|
}
|
|
|
|
/// 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);
|
|
}
|