Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * A library for writing dart unit tests. | 6 * A library for writing dart unit tests. |
| 7 * | 7 * |
| 8 * ## Installing ## | 8 * ## Installing ## |
| 9 * | 9 * |
| 10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` | 10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 | 193 |
| 194 /** Separator used between group names and test names. */ | 194 /** Separator used between group names and test names. */ |
| 195 String groupSep = ' '; | 195 String groupSep = ' '; |
| 196 | 196 |
| 197 final List<TestCase> _testCases = new List<TestCase>(); | 197 final List<TestCase> _testCases = new List<TestCase>(); |
| 198 | 198 |
| 199 /** Tests executed in this suite. */ | 199 /** Tests executed in this suite. */ |
| 200 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases); | 200 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases); |
| 201 | 201 |
| 202 /** | 202 /** |
| 203 * Interval (in msecs) after which synchronous tests will insert an async | |
| 204 * delay to allow DOM or other updates. | |
| 205 */ | |
| 206 const int BREATH_INTERVAL = 200; | |
| 207 | |
| 208 /** | |
| 203 * The set of tests to run can be restricted by using [solo_test] and | 209 * The set of tests to run can be restricted by using [solo_test] and |
| 204 * [solo_group]. | 210 * [solo_group]. |
| 205 * As groups can be nested we use a counter to keep track of the nest level | 211 * As groups can be nested we use a counter to keep track of the nest level |
| 206 * of soloing, and a flag to tell if we have seen any solo tests. | 212 * of soloing, and a flag to tell if we have seen any solo tests. |
| 207 */ | 213 */ |
| 208 int _soloNestingLevel = 0; | 214 int _soloNestingLevel = 0; |
| 209 bool _soloTestSeen = false; | 215 bool _soloTestSeen = false; |
| 210 | 216 |
| 211 /** | 217 /** |
| 212 * Setup and teardown functions for a group and its parents, the latter | 218 * Setup and teardown functions for a group and its parents, the latter |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 TestCase get currentTestCase => | 292 TestCase get currentTestCase => |
| 287 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) | 293 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) |
| 288 ? testCases[_currentTestCaseIndex] | 294 ? testCases[_currentTestCaseIndex] |
| 289 : null; | 295 : null; |
| 290 | 296 |
| 291 /** Whether the framework is in an initialized state. */ | 297 /** Whether the framework is in an initialized state. */ |
| 292 bool _initialized = false; | 298 bool _initialized = false; |
| 293 | 299 |
| 294 String _uncaughtErrorMessage = null; | 300 String _uncaughtErrorMessage = null; |
| 295 | 301 |
| 302 /** Time since we last gave non-sync code a chance to be scheduled. */ | |
| 303 int _lastBreath = new DateTime.now().millisecondsSinceEpoch; | |
| 304 | |
| 296 /** Test case result strings. */ | 305 /** Test case result strings. */ |
| 297 // TODO(gram) we should change these constants to use a different string | 306 // TODO(gram) we should change these constants to use a different string |
| 298 // (so that writing 'FAIL' in the middle of a test doesn't | 307 // (so that writing 'FAIL' in the middle of a test doesn't |
| 299 // imply that the test fails). We can't do it without also changing | 308 // imply that the test fails). We can't do it without also changing |
| 300 // the testrunner and test.dart though. | 309 // the testrunner and test.dart though. |
| 301 const PASS = 'pass'; | 310 const PASS = 'pass'; |
| 302 const FAIL = 'fail'; | 311 const FAIL = 'fail'; |
| 303 const ERROR = 'error'; | 312 const ERROR = 'error'; |
| 304 | 313 |
| 305 /** | 314 /** |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 * case it must return a [Future]. | 648 * case it must return a [Future]. |
| 640 */ | 649 */ |
| 641 void tearDown(Function teardownTest) { | 650 void tearDown(Function teardownTest) { |
| 642 _currentContext.testTeardown = teardownTest; | 651 _currentContext.testTeardown = teardownTest; |
| 643 } | 652 } |
| 644 | 653 |
| 645 /** Advance to the next test case. */ | 654 /** Advance to the next test case. */ |
| 646 void _nextTestCase() { | 655 void _nextTestCase() { |
| 647 runAsync(() { | 656 runAsync(() { |
| 648 _currentTestCaseIndex++; | 657 _currentTestCaseIndex++; |
| 649 _nextBatch(); | 658 _nextTest(); |
| 650 }); | 659 }); |
| 651 } | 660 } |
| 652 | 661 |
| 653 /** | 662 /** |
| 654 * Utility function that can be used to notify the test framework that an | 663 * Utility function that can be used to notify the test framework that an |
| 655 * error was caught outside of this library. | 664 * error was caught outside of this library. |
| 656 */ | 665 */ |
| 657 void _reportTestError(String msg, trace) { | 666 void _reportTestError(String msg, trace) { |
| 658 if (_currentTestCaseIndex < testCases.length) { | 667 if (_currentTestCaseIndex < testCases.length) { |
| 659 final testCase = testCases[_currentTestCaseIndex]; | 668 final testCase = testCases[_currentTestCaseIndex]; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 688 } | 697 } |
| 689 | 698 |
| 690 /** Runs all queued tests, one at a time. */ | 699 /** Runs all queued tests, one at a time. */ |
| 691 void runTests() { | 700 void runTests() { |
| 692 _ensureInitialized(false); | 701 _ensureInitialized(false); |
| 693 _currentTestCaseIndex = 0; | 702 _currentTestCaseIndex = 0; |
| 694 | 703 |
| 695 _config.onStart(); | 704 _config.onStart(); |
| 696 | 705 |
| 697 runAsync(() { | 706 runAsync(() { |
| 698 _nextBatch(); | 707 _nextTest(); |
| 699 }); | 708 }); |
| 700 } | 709 } |
| 701 | 710 |
| 702 /** | 711 /** |
| 703 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is | 712 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is |
| 704 * passed to the corresponding test. | 713 * passed to the corresponding test. |
| 705 * | 714 * |
| 706 * The value returned by [tryBody] (if any) is returned by [guardAsync]. | 715 * The value returned by [tryBody] (if any) is returned by [guardAsync]. |
| 707 */ | 716 */ |
| 708 guardAsync(Function tryBody) { | 717 guardAsync(Function tryBody) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 733 void _registerException(TestCase testCase, e, [trace]) { | 742 void _registerException(TestCase testCase, e, [trace]) { |
| 734 String message = (e is TestFailure) ? e.message : 'Caught $e'; | 743 String message = (e is TestFailure) ? e.message : 'Caught $e'; |
| 735 if (testCase.result == null) { | 744 if (testCase.result == null) { |
| 736 testCase.fail(message, trace); | 745 testCase.fail(message, trace); |
| 737 } else { | 746 } else { |
| 738 testCase.error(message, trace); | 747 testCase.error(message, trace); |
| 739 } | 748 } |
| 740 } | 749 } |
| 741 | 750 |
| 742 /** | 751 /** |
| 743 * Runs a batch of tests, yielding whenever an asynchronous test starts | 752 * Runs the next test. |
| 744 * running. Tests will resume executing when such asynchronous test calls | |
| 745 * [done] or if it fails with an exception. | |
| 746 */ | 753 */ |
| 747 void _nextBatch() { | 754 void _nextTest() { |
| 748 while (true) { | 755 if (_currentTestCaseIndex >= testCases.length) { |
| 749 if (_currentTestCaseIndex >= testCases.length) { | 756 _completeTests(); |
| 750 _completeTests(); | 757 } else { |
| 751 break; | |
| 752 } | |
| 753 final testCase = testCases[_currentTestCaseIndex]; | 758 final testCase = testCases[_currentTestCaseIndex]; |
| 754 var f = _guardAsync(testCase._run, null, testCase); | 759 var f = _guardAsync(testCase._run, null, testCase); |
| 755 if (f != null) { | 760 f.whenComplete(() { |
| 756 f.whenComplete(() { | 761 var now = new DateTime.now().millisecondsSinceEpoch; |
| 762 if ((now - _lastBreath) >= BREATH_INTERVAL) { | |
|
Siggi Cherem (dart-lang)
2013/07/24 23:34:06
consider moving this test up to _nextTestCase? the
gram
2013/07/24 23:54:52
_nextTestCase first increments the counter so ther
Siggi Cherem (dart-lang)
2013/07/25 00:13:09
basically it seems strange that we do runAsync on
gram
2013/07/25 00:33:22
Done.
| |
| 763 _lastBreath = now; | |
| 764 new Future(_nextTestCase); | |
|
Siggi Cherem (dart-lang)
2013/07/24 23:34:06
isn't this the same as runAsync(_nextTestCase).
I
gram
2013/07/24 23:54:52
Done.
| |
| 765 } else { | |
| 757 _nextTestCase(); // Schedule the next test. | 766 _nextTestCase(); // Schedule the next test. |
| 758 }); | 767 } |
| 759 break; | 768 }); |
| 760 } | |
| 761 _currentTestCaseIndex++; | |
| 762 } | 769 } |
| 763 } | 770 } |
| 764 | 771 |
| 765 /** Publish results on the page and notify controller. */ | 772 /** Publish results on the page and notify controller. */ |
| 766 void _completeTests() { | 773 void _completeTests() { |
| 767 if (!_initialized) return; | 774 if (!_initialized) return; |
| 768 int passed = 0; | 775 int passed = 0; |
| 769 int failed = 0; | 776 int failed = 0; |
| 770 int errors = 0; | 777 int errors = 0; |
| 771 | 778 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 864 | 871 |
| 865 if (!formatStacks) return trace; | 872 if (!formatStacks) return trace; |
| 866 | 873 |
| 867 // Format the stack trace by removing everything above TestCase._runTest, | 874 // Format the stack trace by removing everything above TestCase._runTest, |
| 868 // which is usually going to be irrelevant. Also fold together unittest and | 875 // which is usually going to be irrelevant. Also fold together unittest and |
| 869 // core library calls so only the function the user called is visible. | 876 // core library calls so only the function the user called is visible. |
| 870 return new Trace(trace.frames.takeWhile((frame) { | 877 return new Trace(trace.frames.takeWhile((frame) { |
| 871 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; | 878 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; |
| 872 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); | 879 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); |
| 873 } | 880 } |
| OLD | NEW |