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

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.
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;
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) {
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
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 test(spec, body);
kevmoo-old 2013/04/25 21:56:34 DBR: try...finally?
gram 2013/04/25 22:01:16 Done.
351 368 --_solo_level;
352 _soloTest = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
353 body);
354 _testCases.add(_soloTest);
355 } 369 }
356 370
357 /** Sentinel value for [_SpreadArgsHelper]. */ 371 /** Sentinel value for [_SpreadArgsHelper]. */
358 class _Sentinel { 372 class _Sentinel {
359 const _Sentinel(); 373 const _Sentinel();
360 } 374 }
361 375
362 /** Simulates spread arguments using named arguments. */ 376 /** Simulates spread arguments using named arguments. */
363 // TODO(sigmund): remove this class and simply use a closure with named 377 // TODO(sigmund): remove this class and simply use a closure with named
364 // arguments (if still applicable). 378 // arguments (if still applicable).
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 body(); 602 body();
589 } catch (e, trace) { 603 } catch (e, trace) {
590 var stack = (trace == null) ? '' : ': ${trace.toString()}'; 604 var stack = (trace == null) ? '' : ': ${trace.toString()}';
591 _uncaughtErrorMessage = "${e.toString()}$stack"; 605 _uncaughtErrorMessage = "${e.toString()}$stack";
592 } finally { 606 } finally {
593 // Now that the group is over, restore the previous one. 607 // Now that the group is over, restore the previous one.
594 _currentContext = _currentContext.parent; 608 _currentContext = _currentContext.parent;
595 } 609 }
596 } 610 }
597 611
612 /** Like [skip_test], but for groups. */
613 void skip_group(String description, void body()) {}
614
615 /** Like [solo_test], but for groups. */
616 void solo_group(String description, void body()) {
617 ensureInitialized();
618 if (_solo_level < 0) {
619 _solo_level = 0;
620 // This is the first solo-ed group. Discard all tests up to now.
621 _testCases.clear();
622 }
623 ++_solo_level;
624 group(description, body);
kevmoo-old 2013/04/25 21:56:34 DBR: try...finally?
gram 2013/04/25 22:01:16 Done.
625 --_solo_level;
626 }
627
598 /** 628 /**
599 * Register a [setUp] function for a test [group]. This function will 629 * Register a [setUp] function for a test [group]. This function will
600 * be called before each test in the group is run. 630 * be called before each test in the group is run.
601 * [setUp] and [tearDown] should be called within the [group] before any 631 * [setUp] and [tearDown] should be called within the [group] before any
602 * calls to [test]. The [setupTest] function can be asynchronous; in this 632 * calls to [test]. The [setupTest] function can be asynchronous; in this
603 * case it must return a [Future]. 633 * case it must return a [Future].
604 */ 634 */
605 void setUp(Function setupTest) { 635 void setUp(Function setupTest) {
606 _currentContext.testSetup = setupTest; 636 _currentContext.testSetup = setupTest;
607 } 637 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 filterFunction = testFilter; 691 filterFunction = testFilter;
662 } 692 }
663 _testCases.retainWhere(filterFunction); 693 _testCases.retainWhere(filterFunction);
664 } 694 }
665 695
666 /** Runs all queued tests, one at a time. */ 696 /** Runs all queued tests, one at a time. */
667 void runTests() { 697 void runTests() {
668 _ensureInitialized(false); 698 _ensureInitialized(false);
669 _currentTestCaseIndex = 0; 699 _currentTestCaseIndex = 0;
670 700
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(); 701 _config.onStart();
677 702
678 runAsync(() { 703 runAsync(() {
679 _nextBatch(); 704 _nextBatch();
680 }); 705 });
681 } 706 }
682 707
683 /** 708 /**
684 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is 709 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is
685 * passed to the corresponding test. 710 * passed to the corresponding test.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 // Immediately queue the suite up. It will run after a timeout (i.e. after 821 // Immediately queue the suite up. It will run after a timeout (i.e. after
797 // main() has returned). 822 // main() has returned).
798 runAsync(runTests); 823 runAsync(runTests);
799 } 824 }
800 } 825 }
801 826
802 /** Select a solo test by ID. */ 827 /** Select a solo test by ID. */
803 void setSoloTest(int id) { 828 void setSoloTest(int id) {
804 for (var i = 0; i < testCases.length; i++) { 829 for (var i = 0; i < testCases.length; i++) {
805 if (testCases[i].id == id) { 830 if (testCases[i].id == id) {
806 _soloTest = testCases[i]; 831 var testCase = testCases[i];
832 _testCases.clear();
833 _testCases.add(testCase);
807 break; 834 break;
808 } 835 }
809 } 836 }
810 } 837 }
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