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 * Support for writing Dart unit tests. | 6 * Support for writing Dart unit tests. |
7 * | 7 * |
8 * For information on installing and importing this library, see the | 8 * For information on installing and importing this library, see the |
9 * [unittest package on pub.dartlang.org] | 9 * [unittest package on pub.dartlang.org] |
10 * (http://pub.dartlang.org/packages/unittest). | 10 * (http://pub.dartlang.org/packages/unittest). |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 _testTeardown = parentTeardown; | 272 _testTeardown = parentTeardown; |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 // We use a 'dummy' context for the top level to eliminate null | 276 // We use a 'dummy' context for the top level to eliminate null |
277 // checks when querying the context. This allows us to easily | 277 // checks when querying the context. This allows us to easily |
278 // support top-level setUp/tearDown functions as well. | 278 // support top-level setUp/tearDown functions as well. |
279 final _rootContext = new _GroupContext(); | 279 final _rootContext = new _GroupContext(); |
280 _GroupContext _currentContext = _rootContext; | 280 _GroupContext _currentContext = _rootContext; |
281 | 281 |
282 int _currentTestCaseIndex = 0; | 282 /** |
| 283 * Represents the index of the currently running test case |
| 284 * == -1 implies the test system is not running |
| 285 * == [number of test cases] is a short-lived state flagging that the last test |
| 286 * has completed |
| 287 */ |
| 288 int _currentTestCaseIndex = -1; |
283 | 289 |
284 /** [TestCase] currently being executed. */ | 290 /** [TestCase] currently being executed. */ |
285 TestCase get currentTestCase => | 291 TestCase get currentTestCase => |
286 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) | 292 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) |
287 ? testCases[_currentTestCaseIndex] | 293 ? testCases[_currentTestCaseIndex] |
288 : null; | 294 : null; |
289 | 295 |
290 /** Whether the framework is in an initialized state. */ | 296 /** Whether the framework is in an initialized state. */ |
291 bool _initialized = false; | 297 bool _initialized = false; |
292 | 298 |
293 String _uncaughtErrorMessage = null; | 299 String _uncaughtErrorMessage = null; |
294 | 300 |
295 /** Time since we last gave non-sync code a chance to be scheduled. */ | 301 /** Time since we last gave non-sync code a chance to be scheduled. */ |
296 var _lastBreath = new DateTime.now().millisecondsSinceEpoch; | 302 int _lastBreath = new DateTime.now().millisecondsSinceEpoch; |
297 | 303 |
298 /* Test case result strings. */ | 304 /* Test case result strings. */ |
299 // TODO(gram) we should change these constants to use a different string | 305 // TODO(gram) we should change these constants to use a different string |
300 // (so that writing 'FAIL' in the middle of a test doesn't | 306 // (so that writing 'FAIL' in the middle of a test doesn't |
301 // imply that the test fails). We can't do it without also changing | 307 // imply that the test fails). We can't do it without also changing |
302 // the testrunner and test.dart though. | 308 // the testrunner and test.dart though. |
303 /// Result string for a passing test case. | 309 /// Result string for a passing test case. |
304 const PASS = 'pass'; | 310 const PASS = 'pass'; |
305 /// Result string for a failing test case. | 311 /// Result string for a failing test case. |
306 const FAIL = 'fail'; | 312 const FAIL = 'fail'; |
307 /// Result string for an test case with an error. | 313 /// Result string for an test case with an error. |
308 const ERROR = 'error'; | 314 const ERROR = 'error'; |
309 | 315 |
310 /** | 316 /** |
311 * Creates a new test case with the given description and body. The | 317 * Creates a new test case with the given description and body. The |
312 * description will include the descriptions of any surrounding group() | 318 * description will include the descriptions of any surrounding group() |
313 * calls. | 319 * calls. |
314 */ | 320 */ |
315 void test(String spec, TestFunction body) { | 321 void test(String spec, TestFunction body) { |
| 322 _requireNotRunning(); |
316 ensureInitialized(); | 323 ensureInitialized(); |
317 if (!_soloTestSeen || _soloNestingLevel > 0) { | 324 if (!_soloTestSeen || _soloNestingLevel > 0) { |
318 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), | 325 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), |
319 body); | 326 body); |
320 _testCases.add(testcase); | 327 _testCases.add(testcase); |
321 } | 328 } |
322 } | 329 } |
323 | 330 |
324 /** Convenience function for skipping a test. */ | 331 /** Convenience function for skipping a test. */ |
325 void skip_test(String spec, TestFunction body){} | 332 void skip_test(String spec, TestFunction body){} |
326 | 333 |
327 /** | 334 /** |
328 * Creates a new test case with the given description and body. The | 335 * Creates a new test case with the given description and body. The |
329 * description will include the descriptions of any surrounding group() | 336 * description will include the descriptions of any surrounding group() |
330 * calls. | 337 * calls. |
331 * | 338 * |
332 * If we use [solo_test] (or [solo_group]) instead of test, then all non-solo | 339 * If we use [solo_test] (or [solo_group]) instead of test, then all non-solo |
333 * tests will be disabled. Note that if we use [solo_group], all tests in | 340 * tests will be disabled. Note that if we use [solo_group], all tests in |
334 * the group will be enabled, regardless of whether they use [test] or | 341 * the group will be enabled, regardless of whether they use [test] or |
335 * [solo_test], or whether they are in a nested [group] vs [solo_group]. Put | 342 * [solo_test], or whether they are in a nested [group] vs [solo_group]. Put |
336 * another way, if there are any calls to [solo_test] or [solo_group] in a test | 343 * another way, if there are any calls to [solo_test] or [solo_group] in a test |
337 * file, all tests that are not inside a [solo_group] will be disabled unless | 344 * file, all tests that are not inside a [solo_group] will be disabled unless |
338 * they are [solo_test]s. | 345 * they are [solo_test]s. |
339 * | 346 * |
340 * [skip_test] and [skip_group] take precedence over soloing, by virtue of the | 347 * [skip_test] and [skip_group] take precedence over soloing, by virtue of the |
341 * fact that they are effectively no-ops. | 348 * fact that they are effectively no-ops. |
342 */ | 349 */ |
343 void solo_test(String spec, TestFunction body) { | 350 void solo_test(String spec, TestFunction body) { |
| 351 _requireNotRunning(); |
344 ensureInitialized(); | 352 ensureInitialized(); |
345 if (!_soloTestSeen) { | 353 if (!_soloTestSeen) { |
346 _soloTestSeen = true; | 354 _soloTestSeen = true; |
347 // This is the first solo-ed test. Discard all tests up to now. | 355 // This is the first solo-ed test. Discard all tests up to now. |
348 _testCases.clear(); | 356 _testCases.clear(); |
349 } | 357 } |
350 ++_soloNestingLevel; | 358 ++_soloNestingLevel; |
351 try { | 359 try { |
352 test(spec, body); | 360 test(spec, body); |
353 } finally { | 361 } finally { |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 Function protectAsync2(Function callback, {String id}) { | 585 Function protectAsync2(Function callback, {String id}) { |
578 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2; | 586 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2; |
579 } | 587 } |
580 | 588 |
581 /** | 589 /** |
582 * Creates a new named group of tests. Calls to group() or test() within the | 590 * Creates a new named group of tests. Calls to group() or test() within the |
583 * body of the function passed to this will inherit this group's description. | 591 * body of the function passed to this will inherit this group's description. |
584 */ | 592 */ |
585 void group(String description, void body()) { | 593 void group(String description, void body()) { |
586 ensureInitialized(); | 594 ensureInitialized(); |
| 595 _requireNotRunning(); |
587 _currentContext = new _GroupContext(_currentContext, description); | 596 _currentContext = new _GroupContext(_currentContext, description); |
588 try { | 597 try { |
589 body(); | 598 body(); |
590 } catch (e, trace) { | 599 } catch (e, trace) { |
591 var stack = (trace == null) ? '' : ': ${trace.toString()}'; | 600 var stack = (trace == null) ? '' : ': ${trace.toString()}'; |
592 _uncaughtErrorMessage = "${e.toString()}$stack"; | 601 _uncaughtErrorMessage = "${e.toString()}$stack"; |
593 } finally { | 602 } finally { |
594 // Now that the group is over, restore the previous one. | 603 // Now that the group is over, restore the previous one. |
595 _currentContext = _currentContext.parent; | 604 _currentContext = _currentContext.parent; |
596 } | 605 } |
597 } | 606 } |
598 | 607 |
599 /** Like [skip_test], but for groups. */ | 608 /** Like [skip_test], but for groups. */ |
600 void skip_group(String description, void body()) {} | 609 void skip_group(String description, void body()) {} |
601 | 610 |
602 /** Like [solo_test], but for groups. */ | 611 /** Like [solo_test], but for groups. */ |
603 void solo_group(String description, void body()) { | 612 void solo_group(String description, void body()) { |
| 613 _requireNotRunning(); |
604 ensureInitialized(); | 614 ensureInitialized(); |
605 if (!_soloTestSeen) { | 615 if (!_soloTestSeen) { |
606 _soloTestSeen = true; | 616 _soloTestSeen = true; |
607 // This is the first solo-ed group. Discard all tests up to now. | 617 // This is the first solo-ed group. Discard all tests up to now. |
608 _testCases.clear(); | 618 _testCases.clear(); |
609 } | 619 } |
610 ++_soloNestingLevel; | 620 ++_soloNestingLevel; |
611 try { | 621 try { |
612 group(description, body); | 622 group(description, body); |
613 } finally { | 623 } finally { |
614 --_soloNestingLevel; | 624 --_soloNestingLevel; |
615 } | 625 } |
616 } | 626 } |
617 | 627 |
618 /** | 628 /** |
619 * Register a [setUp] function for a test [group]. This function will | 629 * Register a [setUp] function for a test [group]. This function will |
620 * be called before each test in the group is run. | 630 * be called before each test in the group is run. |
621 * [setUp] and [tearDown] should be called within the [group] before any | 631 * [setUp] and [tearDown] should be called within the [group] before any |
622 * calls to [test]. The [setupTest] function can be asynchronous; in this | 632 * calls to [test]. The [setupTest] function can be asynchronous; in this |
623 * case it must return a [Future]. | 633 * case it must return a [Future]. |
624 */ | 634 */ |
625 void setUp(Function setupTest) { | 635 void setUp(Function setupTest) { |
| 636 _requireNotRunning(); |
626 _currentContext.testSetup = setupTest; | 637 _currentContext.testSetup = setupTest; |
627 } | 638 } |
628 | 639 |
629 /** | 640 /** |
630 * Register a [tearDown] function for a test [group]. This function will | 641 * Register a [tearDown] function for a test [group]. This function will |
631 * be called after each test in the group is run. Note that if groups | 642 * be called after each test in the group is run. Note that if groups |
632 * are nested only the most locally scoped [teardownTest] function will be run. | 643 * are nested only the most locally scoped [teardownTest] function will be run. |
633 * [setUp] and [tearDown] should be called within the [group] before any | 644 * [setUp] and [tearDown] should be called within the [group] before any |
634 * calls to [test]. The [teardownTest] function can be asynchronous; in this | 645 * calls to [test]. The [teardownTest] function can be asynchronous; in this |
635 * case it must return a [Future]. | 646 * case it must return a [Future]. |
636 */ | 647 */ |
637 void tearDown(Function teardownTest) { | 648 void tearDown(Function teardownTest) { |
| 649 _requireNotRunning(); |
638 _currentContext.testTeardown = teardownTest; | 650 _currentContext.testTeardown = teardownTest; |
639 } | 651 } |
640 | 652 |
641 /** Advance to the next test case. */ | 653 /** Advance to the next test case. */ |
642 void _nextTestCase() { | 654 void _nextTestCase() { |
643 _currentTestCaseIndex++; | 655 _currentTestCaseIndex++; |
644 _runTest(); | 656 _runTest(); |
645 } | 657 } |
646 | 658 |
647 /** Handle errors that happen outside the tests. */ | 659 /** Handle errors that happen outside the tests. */ |
(...skipping 28 matching lines...) Expand all Loading... |
676 } else if (testFilter is RegExp) { | 688 } else if (testFilter is RegExp) { |
677 filterFunction = (t) => testFilter.hasMatch(t.description); | 689 filterFunction = (t) => testFilter.hasMatch(t.description); |
678 } else if (testFilter is Function) { | 690 } else if (testFilter is Function) { |
679 filterFunction = testFilter; | 691 filterFunction = testFilter; |
680 } | 692 } |
681 _testCases.retainWhere(filterFunction); | 693 _testCases.retainWhere(filterFunction); |
682 } | 694 } |
683 | 695 |
684 /** Runs all queued tests, one at a time. */ | 696 /** Runs all queued tests, one at a time. */ |
685 void runTests() { | 697 void runTests() { |
| 698 _requireNotRunning(); |
686 _ensureInitialized(false); | 699 _ensureInitialized(false); |
687 _currentTestCaseIndex = 0; | 700 _currentTestCaseIndex = 0; |
688 _config.onStart(); | 701 _config.onStart(); |
689 _runTest(); | 702 _runTest(); |
690 } | 703 } |
691 | 704 |
692 /** | 705 /** |
693 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is | 706 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is |
694 * passed to the corresponding test. | 707 * passed to the corresponding test. |
695 * | 708 * |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } else { | 740 } else { |
728 testCase.error(message, trace); | 741 testCase.error(message, trace); |
729 } | 742 } |
730 } | 743 } |
731 | 744 |
732 /** | 745 /** |
733 * Runs the next test. | 746 * Runs the next test. |
734 */ | 747 */ |
735 void _runTest() { | 748 void _runTest() { |
736 if (_currentTestCaseIndex >= testCases.length) { | 749 if (_currentTestCaseIndex >= testCases.length) { |
| 750 assert(_currentTestCaseIndex == testCases.length); |
737 _completeTests(); | 751 _completeTests(); |
738 } else { | 752 } else { |
739 final testCase = testCases[_currentTestCaseIndex]; | 753 var testCase = testCases[_currentTestCaseIndex]; |
740 var f = _guardAsync(testCase._run, null, testCase); | 754 Future f = _guardAsync(testCase._run, null, testCase); |
| 755 var timeout = unittestConfiguration.timeout; |
| 756 |
741 Timer timer; | 757 Timer timer; |
742 final Duration timeout = unittestConfiguration.timeout; | |
743 if (timeout != null) { | 758 if (timeout != null) { |
744 try { | 759 try { |
745 timer = new Timer(timeout, () { | 760 timer = new Timer(timeout, () { |
746 testCase.error("Test timed out after ${timeout.inSeconds} seconds."); | 761 testCase.error("Test timed out after ${timeout.inSeconds} seconds."); |
747 _nextTestCase(); | 762 _nextTestCase(); |
748 }); | 763 }); |
749 } on UnsupportedError catch (e) { | 764 } on UnsupportedError catch (e) { |
750 if (e.message != "Timer greater than 0.") rethrow; | 765 if (e.message != "Timer greater than 0.") rethrow; |
751 // Support running on d8 and jsshell which don't support timers. | 766 // Support running on d8 and jsshell which don't support timers. |
752 } | 767 } |
(...skipping 22 matching lines...) Expand all Loading... |
775 switch (t.result) { | 790 switch (t.result) { |
776 case PASS: passed++; break; | 791 case PASS: passed++; break; |
777 case FAIL: failed++; break; | 792 case FAIL: failed++; break; |
778 case ERROR: errors++; break; | 793 case ERROR: errors++; break; |
779 } | 794 } |
780 } | 795 } |
781 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); | 796 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); |
782 _config.onDone(passed > 0 && failed == 0 && errors == 0 && | 797 _config.onDone(passed > 0 && failed == 0 && errors == 0 && |
783 _uncaughtErrorMessage == null); | 798 _uncaughtErrorMessage == null); |
784 _initialized = false; | 799 _initialized = false; |
| 800 _currentTestCaseIndex = -1; |
785 } | 801 } |
786 | 802 |
787 String _fullSpec(String spec) { | 803 String _fullSpec(String spec) { |
788 var group = '${_currentContext.fullName}'; | 804 var group = '${_currentContext.fullName}'; |
789 if (spec == null) return group; | 805 if (spec == null) return group; |
790 return group != '' ? '$group$groupSep$spec' : spec; | 806 return group != '' ? '$group$groupSep$spec' : spec; |
791 } | 807 } |
792 | 808 |
793 /** | 809 /** |
794 * Lazily initializes the test library if not already initialized. | 810 * Lazily initializes the test library if not already initialized. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 * Useful to disable when debugging unittest or matcher customizations. | 867 * Useful to disable when debugging unittest or matcher customizations. |
852 */ | 868 */ |
853 bool formatStacks = true; | 869 bool formatStacks = true; |
854 | 870 |
855 /** | 871 /** |
856 * A flag that controls whether we try to filter out irrelevant frames from | 872 * A flag that controls whether we try to filter out irrelevant frames from |
857 * the stack trace. Requires formatStacks to be set. | 873 * the stack trace. Requires formatStacks to be set. |
858 */ | 874 */ |
859 bool filterStacks = true; | 875 bool filterStacks = true; |
860 | 876 |
| 877 void _requireNotRunning() { |
| 878 if(_currentTestCaseIndex != -1) { |
| 879 throw new StateError('Not allowed when tests are running.'); |
| 880 } |
| 881 } |
| 882 |
861 /** | 883 /** |
862 * Returns a Trace object from a StackTrace object or a String, or the | 884 * Returns a Trace object from a StackTrace object or a String, or the |
863 * unchanged input if formatStacks is false; | 885 * unchanged input if formatStacks is false; |
864 */ | 886 */ |
865 Trace _getTrace(stack) { | 887 Trace _getTrace(stack) { |
866 Trace trace; | 888 Trace trace; |
867 if (stack == null || !formatStacks) return null; | 889 if (stack == null || !formatStacks) return null; |
868 if (stack is String) { | 890 if (stack is String) { |
869 trace = new Trace.parse(stack); | 891 trace = new Trace.parse(stack); |
870 } else if (stack is StackTrace) { | 892 } else if (stack is StackTrace) { |
871 trace = new Trace.from(stack); | 893 trace = new Trace.from(stack); |
872 } else { | 894 } else { |
873 throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.'); | 895 throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.'); |
874 } | 896 } |
875 | 897 |
876 if (!filterStacks) return trace; | 898 if (!filterStacks) return trace; |
877 | 899 |
878 // Format the stack trace by removing everything above TestCase._runTest, | 900 // Format the stack trace by removing everything above TestCase._runTest, |
879 // which is usually going to be irrelevant. Also fold together unittest and | 901 // which is usually going to be irrelevant. Also fold together unittest and |
880 // core library calls so only the function the user called is visible. | 902 // core library calls so only the function the user called is visible. |
881 return new Trace(trace.frames.takeWhile((frame) { | 903 return new Trace(trace.frames.takeWhile((frame) { |
882 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; | 904 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; |
883 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); | 905 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); |
884 } | 906 } |
OLD | NEW |