Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1145)

Unified Diff: pkg/unittest/lib/unittest.dart

Issue 13464020: unittest: big cleanup, tightened test semantics (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fixed json_test again Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/lib/json/json_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/unittest/lib/unittest.dart
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index 50d308b8d26c0d27b8b81441d1db82c5b0f4b929..c71d9ddc45e40aa9a8d3b41806d27251b773a48d 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -211,13 +211,10 @@ Function _testSetup;
/** Teardown function called after each test in a group */
Function _testTeardown;
-int _currentTestCaseIndex = 0;
+TestCase _currentTestCase = null;
/** [TestCase] currently being executed. */
-TestCase get currentTestCase =>
- (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length)
- ? testCases[_currentTestCaseIndex]
- : null;
+TestCase get currentTestCase => _currentTestCase;
/** Whether the framework is in an initialized state. */
bool _initialized = false;
@@ -292,10 +289,9 @@ class _SpreadArgsHelper {
final int minExpectedCalls;
final int maxExpectedCalls;
final Function isDone;
- final int testNum;
+ final TestCase testCase;
final String id;
int actualCalls = 0;
- TestCase testCase;
bool complete;
static const sentinel = const _Sentinel();
@@ -307,19 +303,13 @@ class _SpreadArgsHelper {
? minExpected
: maxExpected,
this.isDone = isDone,
- testNum = _currentTestCaseIndex,
+ this.testCase = currentTestCase,
this.id = _makeCallbackId(id, callback) {
- ensureInitialized();
- if (!(_currentTestCaseIndex >= 0 &&
- _currentTestCaseIndex < testCases.length &&
- testCases[_currentTestCaseIndex] != null)) {
- print("No valid test, did you forget to run your test inside a call "
- "to test()?");
+ if(testCase == null) {
+ throw new StateError("No valid test, did you forget to run your test "
+ "inside a call to test()?");
}
- assert(_currentTestCaseIndex >= 0 &&
- _currentTestCaseIndex < testCases.length &&
- testCases[_currentTestCaseIndex] != null);
- testCase = testCases[_currentTestCaseIndex];
+
if (isDone != null || minExpected > 0) {
testCase._callbackFunctionsOutstanding++;
complete = false;
@@ -403,7 +393,7 @@ class _SpreadArgsHelper {
'');
}
},
- after, testNum);
+ after, testCase);
}
invoke0() {
@@ -413,7 +403,7 @@ class _SpreadArgsHelper {
return callback();
}
},
- after, testNum);
+ after, testCase);
}
invoke1(arg1) {
@@ -423,7 +413,7 @@ class _SpreadArgsHelper {
return callback(arg1);
}
},
- after, testNum);
+ after, testCase);
}
invoke2(arg1, arg2) {
@@ -433,7 +423,7 @@ class _SpreadArgsHelper {
return callback(arg1, arg2);
}
},
- after, testNum);
+ after, testCase);
}
}
@@ -441,21 +431,6 @@ class _SpreadArgsHelper {
* Indicate that [callback] is expected to be called a [count] number of times
* (by default 1). The unittest framework will wait for the callback to run the
* specified [count] times before it continues with the following test. Using
- * [_expectAsync] will also ensure that errors that occur within [callback] are
- * tracked and reported. [callback] should take between 0 and 4 positional
- * arguments (named arguments are not supported here). [id] can be used
- * to provide more descriptive error messages if the callback is called more
- * often than expected.
- */
-Function _expectAsync(Function callback,
- {int count: 1, int max: 0, String id}) {
- return new _SpreadArgsHelper(callback, count, max, null, id).invoke;
-}
-
-/**
- * Indicate that [callback] is expected to be called a [count] number of times
- * (by default 1). The unittest framework will wait for the callback to run the
- * specified [count] times before it continues with the following test. Using
* [expectAsync0] will also ensure that errors that occur within [callback] are
* tracked and reported. [callback] should take 0 positional arguments (named
* arguments are not supported). [id] can be used to provide more
@@ -489,20 +464,6 @@ Function expectAsync2(Function callback,
/**
* Indicate that [callback] is expected to be called until [isDone] returns
- * true. The unittest framework checks [isDone] after each callback and only
- * when it returns true will it continue with the following test. Using
- * [expectAsyncUntil] will also ensure that errors that occur within
- * [callback] are tracked and reported. [callback] should take between 0 and
- * 4 positional arguments (named arguments are not supported). [id] can be
- * used to identify the callback in error messages (for example if it is called
- * after the test case is complete).
- */
-Function _expectAsyncUntil(Function callback, Function isDone, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke;
-}
-
-/**
- * Indicate that [callback] is expected to be called until [isDone] returns
* true. The unittest framework check [isDone] after each callback and only
* when it returns true will it continue with the following test. Using
* [expectAsyncUntil0] will also ensure that errors that occur within
@@ -537,19 +498,6 @@ Function expectAsyncUntil2(Function callback, Function isDone, {String id}) {
* function will be able to handle exceptions by directing them to the correct
* test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
* might optionally be called but may never be called during the test.
- * [callback] should take between 0 and 4 positional arguments (named arguments
- * are not supported). [id] can be used to identify the callback in error
- * messages (for example if it is called after the test case is complete).
- */
-Function _protectAsync(Function callback, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke;
-}
-
-/**
- * Wraps the [callback] in a new function and returns that function. The new
- * function will be able to handle exceptions by directing them to the correct
- * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
- * might optionally be called but may never be called during the test.
* [callback] should take 0 positional arguments (named arguments are not
* supported). [id] can be used to identify the callback in error
* messages (for example if it is called after the test case is complete).
@@ -620,6 +568,7 @@ void group(String description, void body()) {
* case it must return a [Future].
*/
void setUp(Function setupTest) {
+ _requireNotRunning();
_testSetup = setupTest;
}
@@ -632,46 +581,24 @@ void setUp(Function setupTest) {
* case it must return a [Future].
*/
void tearDown(Function teardownTest) {
+ _requireNotRunning();
_testTeardown = teardownTest;
}
-/** Advance to the next test case. */
-void _nextTestCase() {
- _defer(() {
- _currentTestCaseIndex++;
- _nextBatch();
- });
-}
-
/**
* Utility function that can be used to notify the test framework that an
* error was caught outside of this library.
*/
void _reportTestError(String msg, String trace) {
- if (_currentTestCaseIndex < testCases.length) {
- final testCase = testCases[_currentTestCaseIndex];
- testCase.error(msg, trace);
+ if (currentTestCase != null) {
+ currentTestCase.error(msg, trace);
} else {
_uncaughtErrorMessage = "$msg: $trace";
}
}
-/**
- * Runs [callback] at the end of the event loop. Note that we don't wrap
- * the callback in guardAsync; this is for test framework functions which
- * should not be throwing unexpected exceptions that end up failing test
- * cases! Furthermore, we need the final exception to be thrown but not
- * caught by the test framework if any test cases failed. However, tests
- * that make use of a similar defer function *should* wrap the callback
- * (as we do in unitttest_test.dart).
- */
-_defer(void callback()) {
- (new Future.value()).then((_) => callback());
-}
-
void rerunTests() {
- _uncaughtErrorMessage = null;
- _initialized = true; // We don't want to reset the test array.
+ assert(_uncaughtErrorMessage == null);
runTests();
}
@@ -681,7 +608,8 @@ void rerunTests() {
* in that it removes the tests completely.
*/
void filterTests(testFilter) {
- var filterFunction;
+ _requireNotRunning();
+ Function filterFunction;
if (testFilter is String) {
RegExp re = new RegExp(testFilter);
filterFunction = (t) => re.hasMatch(t.description);
@@ -696,7 +624,8 @@ void filterTests(testFilter) {
/** Runs all queued tests, one at a time. */
void runTests() {
_ensureInitialized(false);
- _currentTestCaseIndex = 0;
+ assert(_currentTestCase == null);
+
_currentGroup = '';
// If we are soloing a test, remove all the others.
@@ -706,9 +635,7 @@ void runTests() {
_config.onStart();
- _defer(() {
- _nextBatch();
- });
+ new Future(_nextBatch);
}
/**
@@ -718,15 +645,15 @@ void runTests() {
* The value returned by [tryBody] (if any) is returned by [guardAsync].
*/
guardAsync(Function tryBody) {
- return _guardAsync(tryBody, null, _currentTestCaseIndex);
+ return _guardAsync(tryBody, null, currentTestCase);
}
-_guardAsync(Function tryBody, Function finallyBody, int testNum) {
- assert(testNum >= 0);
+_guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
+ assert(testCase != null);
try {
return tryBody();
} catch (e, trace) {
- _registerException(testNum, e, trace);
+ _registerException(testCase, e, trace);
} finally {
if (finallyBody != null) finallyBody();
}
@@ -736,48 +663,50 @@ _guardAsync(Function tryBody, Function finallyBody, int testNum) {
* Registers that an exception was caught for the current test.
*/
void registerException(e, [trace]) {
- _registerException(_currentTestCaseIndex, e, trace);
+ _registerException(currentTestCase, e, trace);
}
/**
* Registers that an exception was caught for the current test.
*/
-void _registerException(testNum, e, [trace]) {
+void _registerException(TestCase testCase, e, [trace]) {
+ assert(testCase != null);
trace = trace == null ? '' : trace.toString();
String message = (e is TestFailure) ? e.message : 'Caught $e';
- if (testCases[testNum].result == null) {
- testCases[testNum].fail(message, trace);
+ if (testCase.result == null) {
+ testCase.fail(message, trace);
} else {
- testCases[testNum].error(message, trace);
+ testCase.error(message, trace);
}
}
/**
- * Runs a batch of tests, yielding whenever an asynchronous test starts
- * running. Tests will resume executing when such asynchronous test calls
- * [done] or if it fails with an exception.
+ * Executes tests in order starting with the provided index.
+ * If a test is synchronous, the following test is executed immediately
+ * For asynchronous tests, a Future is returned which completes with _nextBatch
+ * starting at the next index.
+ * Future.forEach is explicitly not used because it slows down synchronous tests
+ * noticeably
*/
-void _nextBatch() {
- while (true) {
- if (_currentTestCaseIndex >= testCases.length) {
- _completeTests();
- break;
- }
- final testCase = testCases[_currentTestCaseIndex];
- var f = _guardAsync(testCase._run, null, _currentTestCaseIndex);
- if (f != null) {
- f.whenComplete(() {
- _nextTestCase(); // Schedule the next test.
- });
- break;
+Future _nextBatch([int index = 0]) {
+ for(int i = index; i < testCases.length; i++) {
+ _currentTestCase = testCases[i];
+
+ Future f = guardAsync(_currentTestCase._run);
+
+ if(f != null) {
+ return f.then((_) => _nextBatch(i + 1));
}
- _currentTestCaseIndex++;
}
+ _currentTestCase = null;
+ return new Future(_completeTests);
}
/** Publish results on the page and notify controller. */
void _completeTests() {
- if (!_initialized) return;
+ assert(_initialized);
+ assert(_currentTestCase == null);
+
int passed = 0;
int failed = 0;
int errors = 0;
@@ -792,7 +721,8 @@ void _completeTests() {
_config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage);
_config.onDone(passed > 0 && failed == 0 && errors == 0 &&
_uncaughtErrorMessage == null);
- _initialized = false;
+
+ _uncaughtErrorMessage = null;
}
String _fullSpec(String spec) {
@@ -807,7 +737,15 @@ void ensureInitialized() {
_ensureInitialized(true);
}
+void _requireNotRunning() {
+ if(_currentTestCase != null) {
+ throw new StateError("A forbidden operation occured "
+ "while tests were running");
+ }
+}
+
void _ensureInitialized(bool configAutoStart) {
+ _requireNotRunning();
if (_initialized) {
return;
}
@@ -825,7 +763,7 @@ void _ensureInitialized(bool configAutoStart) {
if (configAutoStart && _config.autoStart) {
// Immediately queue the suite up. It will run after a timeout (i.e. after
// main() has returned).
- _defer(runTests);
+ new Future(runTests);
}
}
« no previous file with comments | « no previous file | tests/lib/json/json_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698