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

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

Issue 10917275: Update unittest to new package layout. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 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 | « pkg/unittest/test_controller.js ('k') | pkg/unittest/vm_config.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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.
4
5 /**
6 * A library for writing dart unit tests.
7 *
8 * To import this library, specify the relative path to
9 * pkg/unittest/unittest.dart.
10 *
11 * ##Concepts##
12 *
13 * * Tests: Tests are specified via the top-level function [test], they can be
14 * organized together using [group].
15 * * Checks: Test expectations can be specified via [expect]
16 * * Matchers: [expect] assertions are written declaratively using [Matcher]s
17 * * Configuration: The framework can be adapted by calling [configure] with a
18 * [Configuration]. Common configurations can be found in this package
19 * under: 'dom\_config.dart' (deprecated), 'html\_config.dart' (for running
20 * tests compiled to Javascript in a browser), and 'vm\_config.dart' (for
21 * running native Dart tests on the VM).
22 *
23 * ##Examples##
24 *
25 * A trivial test:
26 *
27 * #import('path-to-dart/pkg/unittest/unitest.dart');
28 * main() {
29 * test('this is a test', () {
30 * int x = 2 + 3;
31 * expect(x, equals(5));
32 * });
33 * }
34 *
35 * Multiple tests:
36 *
37 * #import('path-to-dart/pkg/unittest/unitest.dart');
38 * main() {
39 * test('this is a test', () {
40 * int x = 2 + 3;
41 * expect(x, equals(5));
42 * });
43 * test('this is another test', () {
44 * int x = 2 + 3;
45 * expect(x, equals(5));
46 * });
47 * }
48 *
49 * Multiple tests, grouped by category:
50 *
51 * #import('path-to-dart/pkg/unittest/unitest.dart');
52 * main() {
53 * group('group A', () {
54 * test('test A.1', () {
55 * int x = 2 + 3;
56 * expect(x, equals(5));
57 * });
58 * test('test A.2', () {
59 * int x = 2 + 3;
60 * expect(x, equals(5));
61 * });
62 * });
63 * group('group B', () {
64 * test('this B.1', () {
65 * int x = 2 + 3;
66 * expect(x, equals(5));
67 * });
68 * });
69 * }
70 *
71 * Asynchronous tests: if callbacks expect between 0 and 2 positional arguments,
72 * depending on the suffix of expectAsyncX(). expectAsyncX() will wrap a
73 * function into a new callback and will not consider the test complete until
74 * that callback is run. A count argument can be provided to specify the number
75 * of times the callback should be called (the default is 1).
76 *
77 * #import('path-to-dart/pkg/unittest/unitest.dart');
78 * #import('dart:html');
79 * main() {
80 * test('calllback is executed once', () {
81 * // wrap the callback of an asynchronous call with [expectAsync0] if
82 * // the callback takes 0 arguments...
83 * window.setTimeout(expectAsync0(() {
84 * int x = 2 + 3;
85 * expect(x, equals(5));
86 * }), 0);
87 * });
88 *
89 * test('calllback is executed twice', () {
90 * var callback = expectAsync0(() {
91 * int x = 2 + 3;
92 * expect(x, equals(5));
93 * }, count: 2); // <-- we can indicate multiplicity to [expectAsync0]
94 * window.setTimeout(callback, 0);
95 * window.setTimeout(callback, 0);
96 * });
97 * }
98 *
99 * expectAsyncX() will wrap the callback code in a try/catch handler to handle
100 * exceptions (treated as test failures). There may be times when the number of
101 * times a callback should be called is non-deterministic. In this case a dummy
102 * callback can be created with expectAsync0((){}) and this can be called from
103 * the real callback when it is finally complete. In this case the body of the
104 * callback should be protected within a call to guardAsync(); this will ensure
105 * that exceptions are properly handled.
106 *
107 * Note: due to some language limitations we have to use different functions
108 * depending on the number of positional arguments of the callback. In the
109 * future, we plan to expose a single `expectAsync` function that can be used
110 * regardless of the number of positional arguments. This requires new langauge
111 * features or fixes to the current spec (e.g. see
112 * [Issue 2706](http://dartbug.com/2706)).
113 *
114 * Meanwhile, we plan to add this alternative API for callbacks of more than 2
115 * arguments or that take named parameters. (this is not implemented yet,
116 * but will be coming here soon).
117 *
118 * #import('path-to-dart/pkg/unittest/unitest.dart');
119 * #import('dart:html');
120 * main() {
121 * test('calllback is executed', () {
122 * // indicate ahead of time that an async callback is expected.
123 * var async = startAsync();
124 * window.setTimeout(() {
125 * // Guard the body of the callback, so errors are propagated
126 * // correctly
127 * guardAsync(() {
128 * int x = 2 + 3;
129 * expect(x, equals(5));
130 * });
131 * // indicate that the asynchronous callback was invoked.
132 * async.complete();
133 * }), 0);
134 * });
135 *
136 */
137 #library('unittest');
138
139 #import('dart:isolate');
140
141 #source('collection_matchers.dart');
142 #source('config.dart');
143 #source('core_matchers.dart');
144 #source('description.dart');
145 #source('expect.dart');
146 #source('future_matchers.dart');
147 #source('interfaces.dart');
148 #source('map_matchers.dart');
149 #source('matcher.dart');
150 #source('mock.dart');
151 #source('numeric_matchers.dart');
152 #source('operator_matchers.dart');
153 #source('string_matchers.dart');
154 #source('test_case.dart');
155
156 /** [Configuration] used by the unittest library. */
157 Configuration _config = null;
158
159 Configuration get config => _config;
160
161 /**
162 * Set the [Configuration] used by the unittest library. Returns any
163 * previous configuration.
164 * TODO: consider deprecating in favor of a setter now we have a getter.
165 */
166 Configuration configure(Configuration config) {
167 Configuration _oldConfig = _config;
168 _config = config;
169 return _oldConfig;
170 }
171
172 void logMessage(String message) => _config.logMessage(message);
173
174 /**
175 * Description text of the current test group. If multiple groups are nested,
176 * this will contain all of their text concatenated.
177 */
178 String _currentGroup = '';
179
180 /** Separator used between group names and test names. */
181 String groupSep = ' ';
182
183 /** Tests executed in this suite. */
184 List<TestCase> _tests;
185
186 /** Get the list of tests. */
187 get testCases => _tests;
188
189 /**
190 * Callback used to run tests. Entrypoints can replace this with their own
191 * if they want.
192 */
193 Function _testRunner;
194
195 /** Setup function called before each test in a group */
196 Function _testSetup;
197
198 /** Teardown function called after each test in a group */
199 Function _testTeardown;
200
201 /** Current test being executed. */
202 int _currentTest = 0;
203
204 /** Whether the framework is in an initialized state. */
205 bool _initialized = false;
206
207 String _uncaughtErrorMessage = null;
208
209 const _PASS = 'pass';
210 const _FAIL = 'fail';
211 const _ERROR = 'error';
212
213 /** If set, then all other test cases will be ignored. */
214 TestCase _soloTest;
215
216 /**
217 * (Deprecated) Evaluates the [function] and validates that it throws an
218 * exception. If [callback] is provided, then it will be invoked with the
219 * thrown exception. The callback may do any validation it wants. In addition,
220 * if it returns `false`, that also indicates an expectation failure.
221 */
222 void expectThrow(function, [bool callback(exception)]) {
223 bool threw = false;
224 try {
225 function();
226 } catch (e) {
227 threw = true;
228
229 // Also let the callback look at it.
230 if (callback != null) {
231 var result = callback(e);
232
233 // If the callback explicitly returned false, treat that like an
234 // expectation too. (If it returns null, though, don't.)
235 if (result == false) {
236 _fail('Exception:\n$e\ndid not match expectation.');
237 }
238 }
239 }
240
241 if (threw != true) _fail('An expected exception was not thrown.');
242 }
243
244 /**
245 * Creates a new test case with the given description and body. The
246 * description will include the descriptions of any surrounding group()
247 * calls.
248 */
249 void test(String spec, TestFunction body) {
250 ensureInitialized();
251 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0));
252 }
253
254 /**
255 * (Deprecated) Creates a new async test case with the given description
256 * and body. The description will include the descriptions of any surrounding
257 * group() calls.
258 */
259 // TODO(sigmund): deprecate this API
260 void asyncTest(String spec, int callbacks, TestFunction body) {
261 ensureInitialized();
262
263 final testCase = new TestCase(
264 _tests.length + 1, _fullSpec(spec), body, callbacks);
265 _tests.add(testCase);
266
267 if (callbacks < 1) {
268 testCase.error(
269 'Async tests must wait for at least one callback ', '');
270 }
271 }
272
273 /**
274 * Creates a new test case with the given description and body. The
275 * description will include the descriptions of any surrounding group()
276 * calls.
277 *
278 * "solo_" means that this will be the only test that is run. All other tests
279 * will be skipped. This is a convenience function to let you quickly isolate
280 * a single test by adding "solo_" before it to temporarily disable all other
281 * tests.
282 */
283 void solo_test(String spec, TestFunction body) {
284 // TODO(rnystrom): Support multiple solos. If more than one test is solo-ed,
285 // all of the solo-ed tests and none of the non-solo-ed ones should run.
286 if (_soloTest != null) {
287 throw new Exception('Only one test can be soloed right now.');
288 }
289
290 ensureInitialized();
291
292 _soloTest = new TestCase(_tests.length + 1, _fullSpec(spec), body, 0);
293 _tests.add(_soloTest);
294 }
295
296 /** Sentinel value for [_SpreadArgsHelper]. */
297 class _Sentinel {
298 const _Sentinel();
299 }
300
301 // TODO(sigmund): make a singleton const field when frog supports passing those
302 // as default values to named arguments.
303 const _sentinel = const _Sentinel();
304
305 /** Simulates spread arguments using named arguments. */
306 // TODO(sigmund): remove this class and simply use a closure with named
307 // arguments (if still applicable).
308 class _SpreadArgsHelper {
309 Function _callback;
310 int _expectedCalls;
311 int _actualCalls = 0;
312 int _testNum;
313 TestCase _testCase;
314 Function _shouldCallBack;
315 Function _isDone;
316
317 _init(Function callback, Function shouldCallBack, Function isDone,
318 [expectedCalls = 0]) {
319 ensureInitialized();
320 assert(_currentTest < _tests.length);
321 _callback = callback;
322 _shouldCallBack = shouldCallBack;
323 _isDone = isDone;
324 _expectedCalls = expectedCalls;
325 _testNum = _currentTest;
326 _testCase = _tests[_currentTest];
327 if (expectedCalls > 0) {
328 _testCase.callbackFunctionsOutstanding++;
329 }
330 }
331
332 _SpreadArgsHelper(callback, shouldCallBack, isDone) {
333 _init(callback, shouldCallBack, isDone);
334 }
335
336 _SpreadArgsHelper.fixedCallCount(callback, expectedCalls) {
337 _init(callback, _checkCallCount, _allCallsDone, expectedCalls);
338 }
339
340 _SpreadArgsHelper.variableCallCount(callback, isDone) {
341 _init(callback, _always, isDone, 1);
342 }
343
344 _SpreadArgsHelper.optionalCalls(callback) {
345 _init(callback, _always, () => false, 0);
346 }
347
348 _after() {
349 if (_isDone()) {
350 _handleCallbackFunctionComplete();
351 }
352 }
353
354 _allCallsDone() => _actualCalls == _expectedCalls;
355
356 _always() {
357 // Always run except if the test is done.
358 if (_testCase.isComplete) {
359 _testCase.error(
360 'Callback called after already being marked as done ($_actualCalls).',
361 '');
362 return false;
363 } else {
364 return true;
365 }
366 }
367
368 invoke([arg0 = _sentinel, arg1 = _sentinel, arg2 = _sentinel,
369 arg3 = _sentinel, arg4 = _sentinel]) {
370 return guardAsync(() {
371 ++_actualCalls;
372 if (!_shouldCallBack()) {
373 return;
374 } else if (arg0 == _sentinel) {
375 return _callback();
376 } else if (arg1 == _sentinel) {
377 return _callback(arg0);
378 } else if (arg2 == _sentinel) {
379 return _callback(arg0, arg1);
380 } else if (arg3 == _sentinel) {
381 return _callback(arg0, arg1, arg2);
382 } else if (arg4 == _sentinel) {
383 return _callback(arg0, arg1, arg2, arg3);
384 } else {
385 _testCase.error(
386 'unittest lib does not support callbacks with more than'
387 ' 4 arguments.',
388 '');
389 }
390 },
391 _after, _testNum);
392 }
393
394 invoke0() {
395 return guardAsync(
396 () {
397 ++_actualCalls;
398 if (_shouldCallBack()) {
399 return _callback();
400 }
401 },
402 _after, _testNum);
403 }
404
405 invoke1(arg1) {
406 return guardAsync(
407 () {
408 ++_actualCalls;
409 if (_shouldCallBack()) {
410 return _callback(arg1);
411 }
412 },
413 _after, _testNum);
414 }
415
416 invoke2(arg1, arg2) {
417 return guardAsync(
418 () {
419 ++_actualCalls;
420 if (_shouldCallBack()) {
421 return _callback(arg1, arg2);
422 }
423 },
424 _after, _testNum);
425 }
426
427 /** Returns false if we exceded the number of expected calls. */
428 bool _checkCallCount() {
429 if (_actualCalls > _expectedCalls) {
430 _testCase.error('Callback called more times than expected '
431 '($_actualCalls > $_expectedCalls).', '');
432 return false;
433 }
434 return true;
435 }
436 }
437
438 /**
439 * Indicate that [callback] is expected to be called a [count] number of times
440 * (by default 1). The unittest framework will wait for the callback to run the
441 * specified [count] times before it continues with the following test. Using
442 * [_expectAsync] will also ensure that errors that occur within [callback] are
443 * tracked and reported. [callback] should take between 0 and 4 positional
444 * arguments (named arguments are not supported here).
445 */
446 Function _expectAsync(Function callback, [int count = 1]) {
447 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke;
448 }
449
450 /**
451 * Indicate that [callback] is expected to be called a [count] number of times
452 * (by default 1). The unittest framework will wait for the callback to run the
453 * specified [count] times before it continues with the following test. Using
454 * [expectAsync0] will also ensure that errors that occur within [callback] are
455 * tracked and reported. [callback] should take 0 positional arguments (named
456 * arguments are not supported).
457 */
458 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
459 Function expectAsync0(Function callback, [int count = 1]) {
460 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke0;
461 }
462
463 /** Like [expectAsync0] but [callback] should take 1 positional argument. */
464 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
465 Function expectAsync1(Function callback, [int count = 1]) {
466 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke1;
467 }
468
469 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */
470 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
471 Function expectAsync2(Function callback, [int count = 1]) {
472 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke2;
473 }
474
475 /**
476 * Indicate that [callback] is expected to be called until [isDone] returns
477 * true. The unittest framework checks [isDone] after each callback and only
478 * when it returns true will it continue with the following test. Using
479 * [expectAsyncUntil] will also ensure that errors that occur within
480 * [callback] are tracked and reported. [callback] should take between 0 and
481 * 4 positional arguments (named arguments are not supported).
482 */
483 Function _expectAsyncUntil(Function callback, Function isDone) {
484 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke;
485 }
486
487 /**
488 * Indicate that [callback] is expected to be called until [isDone] returns
489 * true. The unittest framework check [isDone] after each callback and only
490 * when it returns true will it continue with the following test. Using
491 * [expectAsyncUntil0] will also ensure that errors that occur within
492 * [callback] are tracked and reported. [callback] should take 0 positional
493 * arguments (named arguments are not supported).
494 */
495 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
496 Function expectAsyncUntil0(Function callback, Function isDone) {
497 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke0;
498 }
499
500 /**
501 * Like [expectAsyncUntil0] but [callback] should take 1 positional argument.
502 */
503 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
504 Function expectAsyncUntil1(Function callback, Function isDone) {
505 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke1;
506 }
507
508 /**
509 * Like [expectAsyncUntil0] but [callback] should take 2 positional arguments.
510 */
511 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
512 Function expectAsyncUntil2(Function callback, Function isDone) {
513 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke2;
514 }
515
516 /**
517 * Wraps the [callback] in a new function and returns that function. The new
518 * function will be able to handle exceptions by directing them to the correct
519 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
520 * might optionally be called but may never be called during the test.
521 * [callback] should take between 0 and 4 positional arguments (named arguments
522 * are not supported).
523 */
524 Function _protectAsync(Function callback) {
525 return new _SpreadArgsHelper.optionalCalls(callback).invoke;
526 }
527
528 /**
529 * Wraps the [callback] in a new function and returns that function. The new
530 * function will be able to handle exceptions by directing them to the correct
531 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
532 * might optionally be called but may never be called during the test.
533 * [callback] should take 0 positional arguments (named arguments are not
534 * supported).
535 */
536 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
537 Function protectAsync0(Function callback) {
538 return new _SpreadArgsHelper.optionalCalls(callback).invoke0;
539 }
540
541 /**
542 * Like [protectAsync0] but [callback] should take 1 positional argument.
543 */
544 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
545 Function protectAsync1(Function callback) {
546 return new _SpreadArgsHelper.optionalCalls(callback).invoke1;
547 }
548
549 /**
550 * Like [protectAsync0] but [callback] should take 2 positional arguments.
551 */
552 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
553 Function protectAsync2(Function callback) {
554 return new _SpreadArgsHelper.optionalCalls(callback).invoke2;
555 }
556
557 /**
558 * Creates a new named group of tests. Calls to group() or test() within the
559 * body of the function passed to this will inherit this group's description.
560 */
561 void group(String description, void body()) {
562 ensureInitialized();
563 // Concatenate the new group.
564 final parentGroup = _currentGroup;
565 if (_currentGroup != '') {
566 // Add a space.
567 _currentGroup = '$_currentGroup$groupSep$description';
568 } else {
569 // The first group.
570 _currentGroup = description;
571 }
572
573 // Groups can be nested, so we need to preserve the current
574 // settings for test setup/teardown.
575 Function parentSetup = _testSetup;
576 Function parentTeardown = _testTeardown;
577
578 try {
579 _testSetup = null;
580 _testTeardown = null;
581 body();
582 } catch (e, trace) {
583 var stack = (trace == null) ? '' : ': ${trace.toString()}';
584 _uncaughtErrorMessage = "${e.toString()}$stack";
585 } finally {
586 // Now that the group is over, restore the previous one.
587 _currentGroup = parentGroup;
588 _testSetup = parentSetup;
589 _testTeardown = parentTeardown;
590 }
591 }
592
593 /**
594 * Register a [setUp] function for a test [group]. This function will
595 * be called before each test in the group is run. Note that if groups
596 * are nested only the most locally scoped [setUp] function will be run.
597 * [setUp] and [tearDown] should be called within the [group] before any
598 * calls to [test].
599 */
600 void setUp(Function setupTest) {
601 _testSetup = setupTest;
602 }
603
604 /**
605 * Register a [tearDown] function for a test [group]. This function will
606 * be called after each test in the group is run. Note that if groups
607 * are nested only the most locally scoped [tearDown] function will be run.
608 * [setUp] and [tearDown] should be called within the [group] before any
609 * calls to [test].
610 */
611 void tearDown(Function teardownTest) {
612 _testTeardown = teardownTest;
613 }
614
615 /**
616 * Called when one of the callback functions is done with all expected
617 * calls.
618 */
619 void _handleCallbackFunctionComplete() {
620 // TODO (gram): we defer this to give the nextBatch recursive
621 // stack a chance to unwind. This is a temporary hack but
622 // really a bunch of code here needs to be fixed. We have a
623 // single array that is being iterated through by nextBatch(),
624 // which is recursively invoked in the case of async tests that
625 // run synchronously. Bad things can then happen.
626 _defer(() {
627 if (_currentTest < _tests.length) {
628 final testCase = _tests[_currentTest];
629 --testCase.callbackFunctionsOutstanding;
630 if (testCase.callbackFunctionsOutstanding < 0) {
631 // TODO(gram): Check: Can this even happen?
632 testCase.error(
633 'More calls to _handleCallbackFunctionComplete() than expected.',
634 '');
635 } else if (testCase.callbackFunctionsOutstanding == 0) {
636 if (!testCase.isComplete) {
637 testCase.pass();
638 }
639 _nextTestCase();
640 }
641 }
642 });
643 }
644
645 /** Advance to the next test case. */
646 void _nextTestCase() {
647 _currentTest++;
648 _testRunner();
649 }
650
651 /**
652 * Temporary hack: expose old API.
653 * TODO(gram) remove this when WebKit tests are working with new framework
654 */
655 void callbackDone() {
656 _handleCallbackFunctionComplete();
657 }
658
659 /**
660 * Utility function that can be used to notify the test framework that an
661 * error was caught outside of this library.
662 */
663 void _reportTestError(String msg, String trace) {
664 if (_currentTest < _tests.length) {
665 final testCase = _tests[_currentTest];
666 testCase.error(msg, trace);
667 if (testCase.callbackFunctionsOutstanding > 0) {
668 _nextTestCase();
669 }
670 } else {
671 _uncaughtErrorMessage = "$msg: $trace";
672 }
673 }
674
675 /** Runs [callback] at the end of the event loop. */
676 _defer(void callback()) {
677 // Exploit isolate ports as a platform-independent mechanism to queue a
678 // message at the end of the event loop.
679 // TODO(sigmund): expose this functionality somewhere in our libraries.
680 final port = new ReceivePort();
681 port.receive((msg, reply) {
682 callback();
683 port.close();
684 });
685 port.toSendPort().send(null, null);
686 }
687
688 rerunTests() {
689 _uncaughtErrorMessage = null;
690 _initialized = true; // We don't want to reset the test array.
691 runTests();
692 }
693
694 /**
695 * Filter the tests. [testFilter] can be a [RegExp], a [String] or a
696 * predicate function. This is different to enabling/disabling tests
697 * in that it removes the tests completely.
698 */
699 void filterTests(testFilter) {
700 var filterFunction;
701 if (testFilter is String) {
702 RegExp re = new RegExp(testFilter);
703 filterFunction = (t) => re.hasMatch(t.description);
704 } else if (testFilter is RegExp) {
705 filterFunction = (t) => testFilter.hasMatch(t.description);
706 } else if (testFilter is Function) {
707 filterFunction = testFilter;
708 }
709 _tests = _tests.filter(filterFunction);
710 }
711
712 /** Runs all queued tests, one at a time. */
713 runTests() {
714 _currentTest = 0;
715 _currentGroup = '';
716
717 // If we are soloing a test, remove all the others.
718 if (_soloTest != null) {
719 filterTests((t) => t == _soloTest);
720 }
721
722 _config.onStart();
723
724 _defer(() {
725 _testRunner();
726 });
727 }
728
729 /**
730 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update
731 * the [_currentTest] status accordingly.
732 */
733 guardAsync(tryBody, [finallyBody, testNum = -1]) {
734 if (testNum < 0) testNum = _currentTest;
735 try {
736 return tryBody();
737 } catch (e, trace) {
738 _registerException(testNum, e, trace);
739 } finally {
740 if (finallyBody != null) finallyBody();
741 }
742 }
743
744 /**
745 * Registers that an exception was caught for the current test.
746 */
747 registerException(e, [trace]) {
748 _registerException(_currentTest, e, trace);
749 }
750
751 /**
752 * Registers that an exception was caught for the current test.
753 */
754 _registerException(testNum, e, [trace]) {
755 trace = trace == null ? '' : trace.toString();
756 if (_tests[testNum].result == null) {
757 String message = (e is ExpectException) ? e.message : 'Caught $e';
758 _tests[testNum].fail(message, trace);
759 } else {
760 _tests[testNum].error('Caught $e', trace);
761 }
762 if (testNum == _currentTest) {
763 _nextTestCase();
764 }
765 }
766
767 /**
768 * Runs a batch of tests, yielding whenever an asynchronous test starts
769 * running. Tests will resume executing when such asynchronous test calls
770 * [done] or if it fails with an exception.
771 */
772 _nextBatch() {
773 while (_currentTest < _tests.length) {
774 final testCase = _tests[_currentTest];
775 guardAsync(() {
776 testCase.run();
777 if (!testCase.isComplete && testCase.callbackFunctionsOutstanding == 0) {
778 testCase.pass();
779 }
780 }, testNum:_currentTest);
781
782 if (!testCase.isComplete &&
783 testCase.callbackFunctionsOutstanding > 0) return;
784 _currentTest++;
785 }
786
787 _completeTests();
788 }
789
790 /** Publish results on the page and notify controller. */
791 _completeTests() {
792 int testsPassed_ = 0;
793 int testsFailed_ = 0;
794 int testsErrors_ = 0;
795
796 for (TestCase t in _tests) {
797 switch (t.result) {
798 case _PASS: testsPassed_++; break;
799 case _FAIL: testsFailed_++; break;
800 case _ERROR: testsErrors_++; break;
801 }
802 }
803 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests,
804 _uncaughtErrorMessage);
805 _initialized = false;
806 }
807
808 String _fullSpec(String spec) {
809 if (spec === null) return '$_currentGroup';
810 return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec;
811 }
812
813 void _fail(String message) {
814 throw new ExpectException(message);
815 }
816
817 /**
818 * Lazily initializes the test library if not already initialized.
819 */
820 ensureInitialized() {
821 if (_initialized) {
822 return;
823 }
824 _initialized = true;
825
826 _tests = <TestCase>[];
827 _testRunner = _nextBatch;
828 _uncaughtErrorMessage = null;
829
830 if (_config == null) {
831 _config = new Configuration();
832 }
833 _config.onInit();
834
835 if (_config.autoStart) {
836 // Immediately queue the suite up. It will run after a timeout (i.e. after
837 // main() has returned).
838 _defer(runTests);
839 }
840 }
841
842 /** Select a solo test by ID. */
843 void setSoloTest(int id) {
844 for (var i = 0; i < _tests.length; i++) {
845 if (_tests[i].id == id) {
846 _soloTest = _tests[i];
847 break;
848 }
849 }
850 }
851
852 /** Enable/disable a test by ID. */
853 void _setTestEnabledState(int testId, bool state) {
854 // Try fast path first.
855 if (_tests.length > testId && _tests[testId].id == testId) {
856 _tests[testId].enabled = state;
857 } else {
858 for (var i = 0; i < _tests.length; i++) {
859 if (_tests[i].id == testId) {
860 _tests[i].enabled = state;
861 break;
862 }
863 }
864 }
865 }
866
867 /** Enable a test by ID. */
868 void enableTest(int testId) => _setTestEnabledState(testId, true);
869
870 /** Disable a test by ID. */
871 void disableTest(int testId) => _setTestEnabledState(testId, false);
872
873 /** Signature for a test function. */
874 typedef void TestFunction();
OLDNEW
« no previous file with comments | « pkg/unittest/test_controller.js ('k') | pkg/unittest/vm_config.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698