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

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