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

Side by Side Diff: pkg/unittest/lib/unittest.dart

Issue 142023005: throw when group or test is called while unittest system is running (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: nits Created 6 years, 10 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/unittest/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 int _currentTestCaseIndex = -1;
Siggi Cherem (dart-lang) 2014/01/30 23:39:01 There is a lot of implicit state encoded in 'curre
kevmoo 2014/01/30 23:42:04 I introduced the currentIndex model a while back.
Siggi Cherem (dart-lang) 2014/01/30 23:46:33 I'm not convinced :), but lets at least add some d
kevmoo 2014/01/31 02:27:37 Done.
283 283
284 /** [TestCase] currently being executed. */ 284 /** [TestCase] currently being executed. */
285 TestCase get currentTestCase => 285 TestCase get currentTestCase =>
286 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) 286 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length)
287 ? testCases[_currentTestCaseIndex] 287 ? testCases[_currentTestCaseIndex]
288 : null; 288 : null;
289 289
290 /** Whether the framework is in an initialized state. */ 290 /** Whether the framework is in an initialized state. */
291 bool _initialized = false; 291 bool _initialized = false;
292 292
(...skipping 13 matching lines...) Expand all
306 const FAIL = 'fail'; 306 const FAIL = 'fail';
307 /// Result string for an test case with an error. 307 /// Result string for an test case with an error.
308 const ERROR = 'error'; 308 const ERROR = 'error';
309 309
310 /** 310 /**
311 * Creates a new test case with the given description and body. The 311 * Creates a new test case with the given description and body. The
312 * description will include the descriptions of any surrounding group() 312 * description will include the descriptions of any surrounding group()
313 * calls. 313 * calls.
314 */ 314 */
315 void test(String spec, TestFunction body) { 315 void test(String spec, TestFunction body) {
316 _requireNotRunning();
316 ensureInitialized(); 317 ensureInitialized();
317 if (!_soloTestSeen || _soloNestingLevel > 0) { 318 if (!_soloTestSeen || _soloNestingLevel > 0) {
318 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), 319 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
319 body); 320 body);
320 _testCases.add(testcase); 321 _testCases.add(testcase);
321 } 322 }
322 } 323 }
323 324
324 /** Convenience function for skipping a test. */ 325 /** Convenience function for skipping a test. */
325 void skip_test(String spec, TestFunction body){} 326 void skip_test(String spec, TestFunction body){}
326 327
327 /** 328 /**
328 * Creates a new test case with the given description and body. The 329 * Creates a new test case with the given description and body. The
329 * description will include the descriptions of any surrounding group() 330 * description will include the descriptions of any surrounding group()
330 * calls. 331 * calls.
331 * 332 *
332 * If we use [solo_test] (or [solo_group]) instead of test, then all non-solo 333 * 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 334 * 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 335 * 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 336 * [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 337 * 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 338 * file, all tests that are not inside a [solo_group] will be disabled unless
338 * they are [solo_test]s. 339 * they are [solo_test]s.
339 * 340 *
340 * [skip_test] and [skip_group] take precedence over soloing, by virtue of the 341 * [skip_test] and [skip_group] take precedence over soloing, by virtue of the
341 * fact that they are effectively no-ops. 342 * fact that they are effectively no-ops.
342 */ 343 */
343 void solo_test(String spec, TestFunction body) { 344 void solo_test(String spec, TestFunction body) {
345 _requireNotRunning();
344 ensureInitialized(); 346 ensureInitialized();
345 if (!_soloTestSeen) { 347 if (!_soloTestSeen) {
346 _soloTestSeen = true; 348 _soloTestSeen = true;
347 // This is the first solo-ed test. Discard all tests up to now. 349 // This is the first solo-ed test. Discard all tests up to now.
348 _testCases.clear(); 350 _testCases.clear();
349 } 351 }
350 ++_soloNestingLevel; 352 ++_soloNestingLevel;
351 try { 353 try {
352 test(spec, body); 354 test(spec, body);
353 } finally { 355 } finally {
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 Function protectAsync2(Function callback, {String id}) { 579 Function protectAsync2(Function callback, {String id}) {
578 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2; 580 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2;
579 } 581 }
580 582
581 /** 583 /**
582 * Creates a new named group of tests. Calls to group() or test() within the 584 * 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. 585 * body of the function passed to this will inherit this group's description.
584 */ 586 */
585 void group(String description, void body()) { 587 void group(String description, void body()) {
586 ensureInitialized(); 588 ensureInitialized();
589 _requireNotRunning();
587 _currentContext = new _GroupContext(_currentContext, description); 590 _currentContext = new _GroupContext(_currentContext, description);
588 try { 591 try {
589 body(); 592 body();
590 } catch (e, trace) { 593 } catch (e, trace) {
591 var stack = (trace == null) ? '' : ': ${trace.toString()}'; 594 var stack = (trace == null) ? '' : ': ${trace.toString()}';
592 _uncaughtErrorMessage = "${e.toString()}$stack"; 595 _uncaughtErrorMessage = "${e.toString()}$stack";
593 } finally { 596 } finally {
594 // Now that the group is over, restore the previous one. 597 // Now that the group is over, restore the previous one.
595 _currentContext = _currentContext.parent; 598 _currentContext = _currentContext.parent;
596 } 599 }
597 } 600 }
598 601
599 /** Like [skip_test], but for groups. */ 602 /** Like [skip_test], but for groups. */
600 void skip_group(String description, void body()) {} 603 void skip_group(String description, void body()) {}
601 604
602 /** Like [solo_test], but for groups. */ 605 /** Like [solo_test], but for groups. */
603 void solo_group(String description, void body()) { 606 void solo_group(String description, void body()) {
607 _requireNotRunning();
604 ensureInitialized(); 608 ensureInitialized();
605 if (!_soloTestSeen) { 609 if (!_soloTestSeen) {
606 _soloTestSeen = true; 610 _soloTestSeen = true;
607 // This is the first solo-ed group. Discard all tests up to now. 611 // This is the first solo-ed group. Discard all tests up to now.
608 _testCases.clear(); 612 _testCases.clear();
609 } 613 }
610 ++_soloNestingLevel; 614 ++_soloNestingLevel;
611 try { 615 try {
612 group(description, body); 616 group(description, body);
613 } finally { 617 } finally {
614 --_soloNestingLevel; 618 --_soloNestingLevel;
615 } 619 }
616 } 620 }
617 621
618 /** 622 /**
619 * Register a [setUp] function for a test [group]. This function will 623 * Register a [setUp] function for a test [group]. This function will
620 * be called before each test in the group is run. 624 * be called before each test in the group is run.
621 * [setUp] and [tearDown] should be called within the [group] before any 625 * [setUp] and [tearDown] should be called within the [group] before any
622 * calls to [test]. The [setupTest] function can be asynchronous; in this 626 * calls to [test]. The [setupTest] function can be asynchronous; in this
623 * case it must return a [Future]. 627 * case it must return a [Future].
624 */ 628 */
625 void setUp(Function setupTest) { 629 void setUp(Function setupTest) {
630 _requireNotRunning();
626 _currentContext.testSetup = setupTest; 631 _currentContext.testSetup = setupTest;
627 } 632 }
628 633
629 /** 634 /**
630 * Register a [tearDown] function for a test [group]. This function will 635 * 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 636 * 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. 637 * are nested only the most locally scoped [teardownTest] function will be run.
633 * [setUp] and [tearDown] should be called within the [group] before any 638 * [setUp] and [tearDown] should be called within the [group] before any
634 * calls to [test]. The [teardownTest] function can be asynchronous; in this 639 * calls to [test]. The [teardownTest] function can be asynchronous; in this
635 * case it must return a [Future]. 640 * case it must return a [Future].
636 */ 641 */
637 void tearDown(Function teardownTest) { 642 void tearDown(Function teardownTest) {
643 _requireNotRunning();
638 _currentContext.testTeardown = teardownTest; 644 _currentContext.testTeardown = teardownTest;
639 } 645 }
640 646
641 /** Advance to the next test case. */ 647 /** Advance to the next test case. */
642 void _nextTestCase() { 648 void _nextTestCase() {
643 _currentTestCaseIndex++; 649 _currentTestCaseIndex++;
644 _runTest(); 650 _runTest();
645 } 651 }
646 652
647 /** Handle errors that happen outside the tests. */ 653 /** Handle errors that happen outside the tests. */
(...skipping 28 matching lines...) Expand all
676 } else if (testFilter is RegExp) { 682 } else if (testFilter is RegExp) {
677 filterFunction = (t) => testFilter.hasMatch(t.description); 683 filterFunction = (t) => testFilter.hasMatch(t.description);
678 } else if (testFilter is Function) { 684 } else if (testFilter is Function) {
679 filterFunction = testFilter; 685 filterFunction = testFilter;
680 } 686 }
681 _testCases.retainWhere(filterFunction); 687 _testCases.retainWhere(filterFunction);
682 } 688 }
683 689
684 /** Runs all queued tests, one at a time. */ 690 /** Runs all queued tests, one at a time. */
685 void runTests() { 691 void runTests() {
692 _requireNotRunning();
686 _ensureInitialized(false); 693 _ensureInitialized(false);
687 _currentTestCaseIndex = 0; 694 _currentTestCaseIndex = 0;
688 _config.onStart(); 695 _config.onStart();
689 _runTest(); 696 _runTest();
690 } 697 }
691 698
692 /** 699 /**
693 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is 700 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is
694 * passed to the corresponding test. 701 * passed to the corresponding test.
695 * 702 *
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 } else { 734 } else {
728 testCase.error(message, trace); 735 testCase.error(message, trace);
729 } 736 }
730 } 737 }
731 738
732 /** 739 /**
733 * Runs the next test. 740 * Runs the next test.
734 */ 741 */
735 void _runTest() { 742 void _runTest() {
736 if (_currentTestCaseIndex >= testCases.length) { 743 if (_currentTestCaseIndex >= testCases.length) {
744 assert(_currentTestCaseIndex == testCases.length);
737 _completeTests(); 745 _completeTests();
738 } else { 746 } else {
739 final testCase = testCases[_currentTestCaseIndex]; 747 var testCase = testCases[_currentTestCaseIndex];
740 var f = _guardAsync(testCase._run, null, testCase); 748 Future f = _guardAsync(testCase._run, null, testCase);
Siggi Cherem (dart-lang) 2014/01/30 23:44:30 Future -> var
kevmoo 2014/01/31 02:27:37 This one is intentional. _guardAsync return dynami
749 var timeout = unittestConfiguration.timeout;
750
741 Timer timer; 751 Timer timer;
742 final Duration timeout = unittestConfiguration.timeout;
743 if (timeout != null) { 752 if (timeout != null) {
744 try { 753 try {
745 timer = new Timer(timeout, () { 754 timer = new Timer(timeout, () {
746 testCase.error("Test timed out after ${timeout.inSeconds} seconds."); 755 testCase.error("Test timed out after ${timeout.inSeconds} seconds.");
747 _nextTestCase(); 756 _nextTestCase();
748 }); 757 });
749 } on UnsupportedError catch (e) { 758 } on UnsupportedError catch (e) {
750 if (e.message != "Timer greater than 0.") rethrow; 759 if (e.message != "Timer greater than 0.") rethrow;
751 // Support running on d8 and jsshell which don't support timers. 760 // Support running on d8 and jsshell which don't support timers.
752 } 761 }
(...skipping 22 matching lines...) Expand all
775 switch (t.result) { 784 switch (t.result) {
776 case PASS: passed++; break; 785 case PASS: passed++; break;
777 case FAIL: failed++; break; 786 case FAIL: failed++; break;
778 case ERROR: errors++; break; 787 case ERROR: errors++; break;
779 } 788 }
780 } 789 }
781 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); 790 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage);
782 _config.onDone(passed > 0 && failed == 0 && errors == 0 && 791 _config.onDone(passed > 0 && failed == 0 && errors == 0 &&
783 _uncaughtErrorMessage == null); 792 _uncaughtErrorMessage == null);
784 _initialized = false; 793 _initialized = false;
794 _currentTestCaseIndex = -1;
785 } 795 }
786 796
787 String _fullSpec(String spec) { 797 String _fullSpec(String spec) {
788 var group = '${_currentContext.fullName}'; 798 var group = '${_currentContext.fullName}';
789 if (spec == null) return group; 799 if (spec == null) return group;
790 return group != '' ? '$group$groupSep$spec' : spec; 800 return group != '' ? '$group$groupSep$spec' : spec;
791 } 801 }
792 802
793 /** 803 /**
794 * Lazily initializes the test library if not already initialized. 804 * Lazily initializes the test library if not already initialized.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 * Useful to disable when debugging unittest or matcher customizations. 861 * Useful to disable when debugging unittest or matcher customizations.
852 */ 862 */
853 bool formatStacks = true; 863 bool formatStacks = true;
854 864
855 /** 865 /**
856 * A flag that controls whether we try to filter out irrelevant frames from 866 * A flag that controls whether we try to filter out irrelevant frames from
857 * the stack trace. Requires formatStacks to be set. 867 * the stack trace. Requires formatStacks to be set.
858 */ 868 */
859 bool filterStacks = true; 869 bool filterStacks = true;
860 870
871 void _requireNotRunning() {
872 if(_currentTestCaseIndex != -1) {
873 throw new StateError('Not allowed when tests are running.');
874 }
875 }
876
861 /** 877 /**
862 * Returns a Trace object from a StackTrace object or a String, or the 878 * Returns a Trace object from a StackTrace object or a String, or the
863 * unchanged input if formatStacks is false; 879 * unchanged input if formatStacks is false;
864 */ 880 */
865 Trace _getTrace(stack) { 881 Trace _getTrace(stack) {
866 Trace trace; 882 Trace trace;
867 if (stack == null || !formatStacks) return null; 883 if (stack == null || !formatStacks) return null;
868 if (stack is String) { 884 if (stack is String) {
869 trace = new Trace.parse(stack); 885 trace = new Trace.parse(stack);
870 } else if (stack is StackTrace) { 886 } else if (stack is StackTrace) {
871 trace = new Trace.from(stack); 887 trace = new Trace.from(stack);
872 } else { 888 } else {
873 throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.'); 889 throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.');
874 } 890 }
875 891
876 if (!filterStacks) return trace; 892 if (!filterStacks) return trace;
877 893
878 // Format the stack trace by removing everything above TestCase._runTest, 894 // Format the stack trace by removing everything above TestCase._runTest,
879 // which is usually going to be irrelevant. Also fold together unittest and 895 // 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. 896 // core library calls so only the function the user called is visible.
881 return new Trace(trace.frames.takeWhile((frame) { 897 return new Trace(trace.frames.takeWhile((frame) {
882 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; 898 return frame.package != 'unittest' || frame.member != 'TestCase._runTest';
883 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); 899 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore);
884 } 900 }
OLDNEW
« no previous file with comments | « no previous file | pkg/unittest/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698