Chromium Code Reviews| Index: pkg/unittest/lib/src/test_case.dart |
| =================================================================== |
| --- pkg/unittest/lib/src/test_case.dart (revision 18267) |
| +++ pkg/unittest/lib/src/test_case.dart (working copy) |
| @@ -60,6 +60,8 @@ |
| bool _doneTeardown = false; |
| + Completer _testComplete; |
| + |
| TestCase(this.id, this.description, this.test, |
| this.callbackFunctionsOutstanding) |
| : currentGroup = _currentGroup, |
| @@ -68,21 +70,70 @@ |
| bool get isComplete => !enabled || result != null; |
| - void run() { |
| - if (enabled) { |
| - result = stackTrace = null; |
| - message = ''; |
| - _doneTeardown = false; |
| - if (_setUp != null) { |
| - _setUp(); |
| + void _prepTest() { |
| + _config.onTestStart(this); |
| + startTime = new DateTime.now(); |
| + runningTime = null; |
| + } |
| + |
| + Future _runTest() { |
| + _prepTest(); |
| + test(); |
| + if (result == null && callbackFunctionsOutstanding == 0) { |
| + pass(); |
| + } |
| + return null; |
|
Siggi Cherem (dart-lang)
2013/02/11 23:14:18
if this always returns null, shouldn't this functi
gram
2013/02/11 23:50:24
Yes, my bad, it had some other code in before that
|
| + } |
| + |
| + /** |
| + * Perform any associated [setUp] function and run the test. Returns |
| + * a [Future] that can be used to schedule the next test. If the test runs |
| + * to completion synchronously, or is disabled, we return null, to |
| + * tell unittest to schedule the next test immediately. |
| + */ |
| + Future run() { |
| + if (!enabled) { |
| + return null; |
| + } |
|
Siggi Cherem (dart-lang)
2013/02/11 23:14:18
fyi - john and I have grown to like the style wher
gram
2013/02/11 23:50:24
Done.
|
| + |
| + result = stackTrace = null; |
| + message = ''; |
| + _doneTeardown = false; |
| + if (_setUp != null) { |
| + var rtn = _setUp(); |
|
Siggi Cherem (dart-lang)
2013/02/11 23:14:18
nit: consider merging a few of these branches, for
|
| + if (rtn is Future) { |
| + rtn.then(expectAsync1((_) { |
|
Siggi Cherem (dart-lang)
2013/02/11 23:14:18
nit: consider using =>
rtn.then(expectAsync1((_)
gram
2013/02/11 23:50:24
Done.
|
| + _runTest(); |
| + }, id: '[Async setUp completion handler]')) |
| + .catchError((e) { |
| + _prepTest(); |
| + // Calling error() will result in the tearDown being done. |
| + // One could debate whether tearDown should be done after |
| + // a failed setUp. There is no right answer, but doing it |
| + // seems to be the more conservative approach, because |
| + // unittest will not stop at a test failure. |
| + error("$description: Test setup failed: ${e.error}"); |
| + }); |
| + } else { |
| + _runTest(); |
| } |
| - _config.onTestStart(this); |
| - startTime = new DateTime.now(); |
| - runningTime = null; |
| - test(); |
| + } else { |
| + _runTest(); |
| } |
| + if (result == null) { // Not complete. |
| + _testComplete = new Completer(); |
| + return _testComplete.future; |
| + } |
| + return null; |
| } |
| + void _nextTest() { |
|
Siggi Cherem (dart-lang)
2013/02/11 23:14:18
nit: rename, '_markComplete'?
gram
2013/02/11 23:50:24
I went for _notifyComplete
|
| + if (_testComplete != null) { |
| + _testComplete.complete(this); |
| + _testComplete = null; |
| + } |
| + } |
| + |
| void _complete() { |
| if (runningTime == null) { |
| // TODO(gram): currently the duration measurement code is blocked |
| @@ -91,12 +142,37 @@ |
| runningTime = new Duration(milliseconds: 0); |
| } |
| if (!_doneTeardown) { |
| + _doneTeardown = true; |
| if (_tearDown != null) { |
| - _tearDown(); |
| + var rtn = _tearDown(); |
| + if (rtn is Future) { |
| + rtn.then(expectAsync1((_) { |
| + if (result == null) { |
| + // The test passed. In some cases we will already |
| + // have set this result (e.g. if the test was async |
| + // and all callbacks completed). If not, we do it here. |
| + pass(); |
| + } else { |
| + // The test has already been marked as pass/fail. |
| + // Just report the updated result. |
| + _config.onTestResult(this); |
| + } |
| + _nextTest(); |
| + }, id: '[Async tearDown completion handler]')) |
| + .catchError((e) { |
| + // We don't call fail() as that will potentially result in |
| + // spurious messages like 'test failed more than once'. |
| + result = ERROR; |
| + message = "$description: Test teardown failed: ${e.error}"; |
| + _config.onTestResult(this); |
| + _nextTest(); |
| + }); |
| + return; |
| + } |
| } |
| - _doneTeardown = true; |
| } |
| _config.onTestResult(this); |
| + _nextTest(); |
| } |
| void pass() { |