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

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 /**
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
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
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
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
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
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 }
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