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

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

Issue 14180015: Added support for solo groups, multiple solo tests, and (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 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/test/unittest_test.dart » ('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 * 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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 207
208 /** Separator used between group names and test names. */ 208 /** Separator used between group names and test names. */
209 String groupSep = ' '; 209 String groupSep = ' ';
210 210
211 final List<TestCase> _testCases = new List<TestCase>(); 211 final List<TestCase> _testCases = new List<TestCase>();
212 212
213 /** Tests executed in this suite. */ 213 /** Tests executed in this suite. */
214 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases); 214 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases);
215 215
216 /** 216 /**
217 * The set of tests to run can be restricted by using [solo_test] and
218 * [solo_group].
219 * As groups can be nested we use a counter to keep track of the nest level
220 * of soloing, and a flag to tell if we have seen any solo tests.
221 */
222 int _soloNestingLevel = 0;
223 bool _soloTestSeen = false;
224
225 /**
217 * Setup and teardown functions for a group and its parents, the latter 226 * Setup and teardown functions for a group and its parents, the latter
218 * for chaining. 227 * for chaining.
219 */ 228 */
220 class GroupContext { 229 class GroupContext {
221 final GroupContext parent; 230 final GroupContext parent;
222 231
223 /** Description text of the current test group. */ 232 /** Description text of the current test group. */
224 final String _name; 233 final String _name;
225 234
226 /** Setup function called before each test in a group. */ 235 /** Setup function called before each test in a group. */
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 309
301 /** Test case result strings. */ 310 /** Test case result strings. */
302 // TODO(gram) we should change these constants to use a different string 311 // TODO(gram) we should change these constants to use a different string
303 // (so that writing 'FAIL' in the middle of a test doesn't 312 // (so that writing 'FAIL' in the middle of a test doesn't
304 // imply that the test fails). We can't do it without also changing 313 // imply that the test fails). We can't do it without also changing
305 // the testrunner and test.dart though. 314 // the testrunner and test.dart though.
306 const PASS = 'pass'; 315 const PASS = 'pass';
307 const FAIL = 'fail'; 316 const FAIL = 'fail';
308 const ERROR = 'error'; 317 const ERROR = 'error';
309 318
310 /** If set, then all other test cases will be ignored. */
311 TestCase _soloTest;
312
313 /** 319 /**
314 * A map that can be used to communicate state between a test driver 320 * A map that can be used to communicate state between a test driver
315 * or main() function and the tests, particularly when these two 321 * or main() function and the tests, particularly when these two
316 * are otherwise independent. For example, a test driver that starts 322 * are otherwise independent. For example, a test driver that starts
317 * an HTTP server and then runs tests that access that server could use 323 * an HTTP server and then runs tests that access that server could use
318 * this as a way of communicating the server port to the tests. 324 * this as a way of communicating the server port to the tests.
319 */ 325 */
320 Map testState = {}; 326 Map testState = {};
321 327
322 /** 328 /**
323 * 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
324 * description will include the descriptions of any surrounding group() 330 * description will include the descriptions of any surrounding group()
325 * calls. 331 * calls.
326 */ 332 */
327 void test(String spec, TestFunction body) { 333 void test(String spec, TestFunction body) {
328 ensureInitialized(); 334 ensureInitialized();
329 _testCases.add(new TestCase._internal(testCases.length + 1, _fullSpec(spec), 335 if (!_soloTestSeen || _soloNestingLevel > 0) {
330 body)); 336 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
337 body);
Siggi Cherem (dart-lang) 2013/04/26 18:53:47 nit: fix indentation (should just be +4) given th
338 _testCases.add(testcase);
339 }
331 } 340 }
332 341
342 /** Convenience function for skipping a test. */
343 void skip_test(String spec, TestFunction body){}
344
333 /** 345 /**
334 * Creates a new test case with the given description and body. The 346 * Creates a new test case with the given description and body. The
335 * description will include the descriptions of any surrounding group() 347 * description will include the descriptions of any surrounding group()
336 * calls. 348 * calls.
337 * 349 *
338 * "solo_" means that this will be the only test that is run. All other tests 350 * If we use [solo_test] (or [solo_group]) instead of test, then all non-solo
339 * will be skipped. This is a convenience function to let you quickly isolate 351 * tests will be disabled. Note that if we use [solo_group], all tests in
340 * a single test by adding "solo_" before it to temporarily disable all other 352 * the group will be enabled, regardless of whether they use [test] or
341 * tests. 353 * [solo_test], or whether they are in a nested [group] vs [solo_group]. Put
354 * another way, if there are any calls to [solo_test] or [solo_group] in a test
355 * file, all tests that are not inside a [solo_group] will be disabled unless
356 * they are [solo_test]s.
357 *
358 * [skip_test] and [skip_group] take precedence over soloing, by virtue of the
359 * fact that they are effectively no-ops.
342 */ 360 */
343 void solo_test(String spec, TestFunction body) { 361 void solo_test(String spec, TestFunction body) {
344 // TODO(rnystrom): Support multiple solos. If more than one test is solo-ed, 362 ensureInitialized();
345 // all of the solo-ed tests and none of the non-solo-ed ones should run. 363 if (!_soloTestSeen) {
346 if (_soloTest != null) { 364 _soloTestSeen = true;
347 throw new Exception('Only one test can be soloed right now.'); 365 // This is the first solo-ed test. Discard all tests up to now.
366 _testCases.clear();
348 } 367 }
349 368 ++_soloNestingLevel;
350 ensureInitialized(); 369 try {
351 370 test(spec, body);
352 _soloTest = new TestCase._internal(testCases.length + 1, _fullSpec(spec), 371 } finally {
353 body); 372 --_soloNestingLevel;
354 _testCases.add(_soloTest); 373 }
355 } 374 }
356 375
357 /** Sentinel value for [_SpreadArgsHelper]. */ 376 /** Sentinel value for [_SpreadArgsHelper]. */
358 class _Sentinel { 377 class _Sentinel {
359 const _Sentinel(); 378 const _Sentinel();
360 } 379 }
361 380
362 /** Simulates spread arguments using named arguments. */ 381 /** Simulates spread arguments using named arguments. */
363 // TODO(sigmund): remove this class and simply use a closure with named 382 // TODO(sigmund): remove this class and simply use a closure with named
364 // arguments (if still applicable). 383 // arguments (if still applicable).
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 body(); 607 body();
589 } catch (e, trace) { 608 } catch (e, trace) {
590 var stack = (trace == null) ? '' : ': ${trace.toString()}'; 609 var stack = (trace == null) ? '' : ': ${trace.toString()}';
591 _uncaughtErrorMessage = "${e.toString()}$stack"; 610 _uncaughtErrorMessage = "${e.toString()}$stack";
592 } finally { 611 } finally {
593 // Now that the group is over, restore the previous one. 612 // Now that the group is over, restore the previous one.
594 _currentContext = _currentContext.parent; 613 _currentContext = _currentContext.parent;
595 } 614 }
596 } 615 }
597 616
617 /** Like [skip_test], but for groups. */
618 void skip_group(String description, void body()) {}
619
620 /** Like [solo_test], but for groups. */
621 void solo_group(String description, void body()) {
622 ensureInitialized();
623 if (!_soloTestSeen) {
624 _soloTestSeen = true;
625 // This is the first solo-ed group. Discard all tests up to now.
626 _testCases.clear();
627 }
628 ++_soloNestingLevel;
629 try {
630 group(description, body);
631 } finally {
632 --_soloNestingLevel;
633 }
634 }
635
598 /** 636 /**
599 * Register a [setUp] function for a test [group]. This function will 637 * Register a [setUp] function for a test [group]. This function will
600 * be called before each test in the group is run. 638 * be called before each test in the group is run.
601 * [setUp] and [tearDown] should be called within the [group] before any 639 * [setUp] and [tearDown] should be called within the [group] before any
602 * calls to [test]. The [setupTest] function can be asynchronous; in this 640 * calls to [test]. The [setupTest] function can be asynchronous; in this
603 * case it must return a [Future]. 641 * case it must return a [Future].
604 */ 642 */
605 void setUp(Function setupTest) { 643 void setUp(Function setupTest) {
606 _currentContext.testSetup = setupTest; 644 _currentContext.testSetup = setupTest;
607 } 645 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 filterFunction = testFilter; 699 filterFunction = testFilter;
662 } 700 }
663 _testCases.retainWhere(filterFunction); 701 _testCases.retainWhere(filterFunction);
664 } 702 }
665 703
666 /** Runs all queued tests, one at a time. */ 704 /** Runs all queued tests, one at a time. */
667 void runTests() { 705 void runTests() {
668 _ensureInitialized(false); 706 _ensureInitialized(false);
669 _currentTestCaseIndex = 0; 707 _currentTestCaseIndex = 0;
670 708
671 // If we are soloing a test, remove all the others.
672 if (_soloTest != null) {
673 filterTests((t) => t == _soloTest);
674 }
675
676 _config.onStart(); 709 _config.onStart();
677 710
678 runAsync(() { 711 runAsync(() {
679 _nextBatch(); 712 _nextBatch();
680 }); 713 });
681 } 714 }
682 715
683 /** 716 /**
684 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is 717 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is
685 * passed to the corresponding test. 718 * passed to the corresponding test.
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 _config.onInit(); 826 _config.onInit();
794 827
795 if (configAutoStart && _config.autoStart) { 828 if (configAutoStart && _config.autoStart) {
796 // Immediately queue the suite up. It will run after a timeout (i.e. after 829 // Immediately queue the suite up. It will run after a timeout (i.e. after
797 // main() has returned). 830 // main() has returned).
798 runAsync(runTests); 831 runAsync(runTests);
799 } 832 }
800 } 833 }
801 834
802 /** Select a solo test by ID. */ 835 /** Select a solo test by ID. */
803 void setSoloTest(int id) { 836 void setSoloTest(int id) =>
804 for (var i = 0; i < testCases.length; i++) { 837 _testCases.retainWhere((t) => t.id == id);
805 if (testCases[i].id == id) {
806 _soloTest = testCases[i];
807 break;
808 }
809 }
810 }
811 838
812 /** Enable/disable a test by ID. */ 839 /** Enable/disable a test by ID. */
813 void _setTestEnabledState(int testId, bool state) { 840 void _setTestEnabledState(int testId, bool state) {
814 // Try fast path first. 841 // Try fast path first.
815 if (testCases.length > testId && testCases[testId].id == testId) { 842 if (testCases.length > testId && testCases[testId].id == testId) {
816 testCases[testId].enabled = state; 843 testCases[testId].enabled = state;
817 } else { 844 } else {
818 for (var i = 0; i < testCases.length; i++) { 845 for (var i = 0; i < testCases.length; i++) {
819 if (testCases[i].id == testId) { 846 if (testCases[i].id == testId) {
820 testCases[i].enabled = state; 847 testCases[i].enabled = state;
821 break; 848 break;
822 } 849 }
823 } 850 }
824 } 851 }
825 } 852 }
826 853
827 /** Enable a test by ID. */ 854 /** Enable a test by ID. */
828 void enableTest(int testId) => _setTestEnabledState(testId, true); 855 void enableTest(int testId) => _setTestEnabledState(testId, true);
829 856
830 /** Disable a test by ID. */ 857 /** Disable a test by ID. */
831 void disableTest(int testId) => _setTestEnabledState(testId, false); 858 void disableTest(int testId) => _setTestEnabledState(testId, false);
832 859
833 /** Signature for a test function. */ 860 /** Signature for a test function. */
834 typedef dynamic TestFunction(); 861 typedef dynamic TestFunction();
OLDNEW
« no previous file with comments | « no previous file | pkg/unittest/test/unittest_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698