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

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

Issue 10836241: Move unittest from lib to pkg. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 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 | « lib/unittest/test_controller.js ('k') | lib/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 * lib/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/lib/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/lib/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/lib/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/lib/unittest/unitest.dart');
78 * #import('dart:dom_deprecated');
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/lib/unittest/unitest.dart');
119 * #import('dart:dom_deprecated');
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 /**
160 * Set the [Configuration] used by the unittest library. Returns any
161 * previous configuration.
162 */
163 Configuration configure(Configuration config) {
164 Configuration _oldConfig = _config;
165 _config = config;
166 return _oldConfig;
167 }
168
169 void logMessage(String message) => _config.log(message);
170
171 /**
172 * Description text of the current test group. If multiple groups are nested,
173 * this will contain all of their text concatenated.
174 */
175 String _currentGroup = '';
176
177 /** Tests executed in this suite. */
178 List<TestCase> _tests;
179
180 /** Get the list of tests. */
181 get testCases() => _tests;
182
183 /**
184 * Callback used to run tests. Entrypoints can replace this with their own
185 * if they want.
186 */
187 Function _testRunner;
188
189 /** Setup function called before each test in a group */
190 Function _testSetup;
191
192 /** Teardown function called after each test in a group */
193 Function _testTeardown;
194
195 /** Current test being executed. */
196 int _currentTest = 0;
197
198 /** Whether the framework is in an initialized state. */
199 bool _initialized = false;
200
201 String _uncaughtErrorMessage = null;
202
203 final _PASS = 'pass';
204 final _FAIL = 'fail';
205 final _ERROR = 'error';
206
207 /** If set, then all other test cases will be ignored. */
208 TestCase _soloTest;
209
210 /**
211 * (Deprecated) Evaluates the [function] and validates that it throws an
212 * exception. If [callback] is provided, then it will be invoked with the
213 * thrown exception. The callback may do any validation it wants. In addition,
214 * if it returns `false`, that also indicates an expectation failure.
215 */
216 void expectThrow(function, [bool callback(exception)]) {
217 bool threw = false;
218 try {
219 function();
220 } catch (var e) {
221 threw = true;
222
223 // Also let the callback look at it.
224 if (callback != null) {
225 var result = callback(e);
226
227 // If the callback explicitly returned false, treat that like an
228 // expectation too. (If it returns null, though, don't.)
229 if (result == false) {
230 _fail('Exception:\n$e\ndid not match expectation.');
231 }
232 }
233 }
234
235 if (threw != true) _fail('An expected exception was not thrown.');
236 }
237
238 /**
239 * The regexp pattern filter which constrains which tests to run
240 * based on their descriptions.
241 */
242
243 String filter = null;
244
245 /**
246 * Creates a new test case with the given description and body. The
247 * description will include the descriptions of any surrounding group()
248 * calls.
249 */
250 void test(String spec, TestFunction body) {
251 ensureInitialized();
252
253 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0));
254 }
255
256 /**
257 * (Deprecated) Creates a new async test case with the given description
258 * and body. The description will include the descriptions of any surrounding
259 * group() calls.
260 */
261 // TODO(sigmund): deprecate this API
262 void asyncTest(String spec, int callbacks, TestFunction body) {
263 ensureInitialized();
264
265 final testCase = new TestCase(
266 _tests.length + 1, _fullSpec(spec), body, callbacks);
267 _tests.add(testCase);
268
269 if (callbacks < 1) {
270 testCase.error(
271 'Async tests must wait for at least one callback ', '');
272 }
273 }
274
275 /**
276 * Creates a new test case with the given description and body. The
277 * description will include the descriptions of any surrounding group()
278 * calls.
279 *
280 * "solo_" means that this will be the only test that is run. All other tests
281 * will be skipped. This is a convenience function to let you quickly isolate
282 * a single test by adding "solo_" before it to temporarily disable all other
283 * tests.
284 */
285 void solo_test(String spec, TestFunction body) {
286 // TODO(rnystrom): Support multiple solos. If more than one test is solo-ed,
287 // all of the solo-ed tests and none of the non-solo-ed ones should run.
288 if (_soloTest != null) {
289 throw new Exception('Only one test can be soloed right now.');
290 }
291
292 ensureInitialized();
293
294 _soloTest = new TestCase(_tests.length + 1, _fullSpec(spec), body, 0);
295 _tests.add(_soloTest);
296 }
297
298 /** Sentinel value for [_SpreadArgsHelper]. */
299 class _Sentinel {
300 const _Sentinel();
301 }
302
303 // TODO(sigmund): make a singleton const field when frog supports passing those
304 // as default values to named arguments.
305 final _sentinel = const _Sentinel();
306
307 /** Simulates spread arguments using named arguments. */
308 // TODO(sigmund): remove this class and simply use a closure with named
309 // arguments (if still applicable).
310 class _SpreadArgsHelper {
311 Function _callback;
312 int _expectedCalls;
313 int _actualCalls = 0;
314 int _testNum;
315 TestCase _testCase;
316 Function _shouldCallBack;
317 Function _isDone;
318
319 _init(Function callback, Function shouldCallBack, Function isDone,
320 [expectedCalls = 0]) {
321 ensureInitialized();
322 assert(_currentTest < _tests.length);
323 _callback = callback;
324 _shouldCallBack = shouldCallBack;
325 _isDone = isDone;
326 _expectedCalls = expectedCalls;
327 _testNum = _currentTest;
328 _testCase = _tests[_currentTest];
329 if (expectedCalls > 0) {
330 _testCase.callbackFunctionsOutstanding++;
331 }
332 }
333
334 _SpreadArgsHelper(callback, shouldCallBack, isDone) {
335 _init(callback, shouldCallBack, isDone);
336 }
337
338 _SpreadArgsHelper.fixedCallCount(callback, expectedCalls) {
339 _init(callback, _checkCallCount, _allCallsDone, expectedCalls);
340 }
341
342 _SpreadArgsHelper.variableCallCount(callback, isDone) {
343 _init(callback, _always, isDone, 1);
344 }
345
346 _SpreadArgsHelper.optionalCalls(callback) {
347 _init(callback, _always, () => false, 0);
348 }
349
350 _after() {
351 if (_isDone()) {
352 _handleCallbackFunctionComplete();
353 }
354 }
355
356 _allCallsDone() => _actualCalls == _expectedCalls;
357
358 _always() {
359 // Always run except if the test is done.
360 if (_testCase.isComplete) {
361 _testCase.error(
362 'Callback called after already being marked as done ($_actualCalls).',
363 '');
364 return false;
365 } else {
366 return true;
367 }
368 }
369
370 invoke([arg0 = _sentinel, arg1 = _sentinel, arg2 = _sentinel,
371 arg3 = _sentinel, arg4 = _sentinel]) {
372 return guardAsync(() {
373 ++_actualCalls;
374 if (!_shouldCallBack()) {
375 return;
376 } else if (arg0 == _sentinel) {
377 return _callback();
378 } else if (arg1 == _sentinel) {
379 return _callback(arg0);
380 } else if (arg2 == _sentinel) {
381 return _callback(arg0, arg1);
382 } else if (arg3 == _sentinel) {
383 return _callback(arg0, arg1, arg2);
384 } else if (arg4 == _sentinel) {
385 return _callback(arg0, arg1, arg2, arg3);
386 } else {
387 _testCase.error(
388 'unittest lib does not support callbacks with more than'
389 ' 4 arguments.',
390 '');
391 }
392 },
393 _after, _testNum);
394 }
395
396 invoke0() {
397 return guardAsync(
398 () {
399 ++_actualCalls;
400 if (_shouldCallBack()) {
401 return _callback();
402 }
403 },
404 _after, _testNum);
405 }
406
407 invoke1(arg1) {
408 return guardAsync(
409 () {
410 ++_actualCalls;
411 if (_shouldCallBack()) {
412 return _callback(arg1);
413 }
414 },
415 _after, _testNum);
416 }
417
418 invoke2(arg1, arg2) {
419 return guardAsync(
420 () {
421 ++_actualCalls;
422 if (_shouldCallBack()) {
423 return _callback(arg1, arg2);
424 }
425 },
426 _after, _testNum);
427 }
428
429 /** Returns false if we exceded the number of expected calls. */
430 bool _checkCallCount() {
431 if (_actualCalls > _expectedCalls) {
432 _testCase.error('Callback called more times than expected '
433 '($_actualCalls > $_expectedCalls).', '');
434 return false;
435 }
436 return true;
437 }
438 }
439
440 /**
441 * Indicate that [callback] is expected to be called a [count] number of times
442 * (by default 1). The unittest framework will wait for the callback to run the
443 * specified [count] times before it continues with the following test. Using
444 * [_expectAsync] will also ensure that errors that occur within [callback] are
445 * tracked and reported. [callback] should take between 0 and 4 positional
446 * arguments (named arguments are not supported here).
447 */
448 Function _expectAsync(Function callback, [int count = 1]) {
449 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke;
450 }
451
452 /**
453 * Indicate that [callback] is expected to be called a [count] number of times
454 * (by default 1). The unittest framework will wait for the callback to run the
455 * specified [count] times before it continues with the following test. Using
456 * [expectAsync0] will also ensure that errors that occur within [callback] are
457 * tracked and reported. [callback] should take 0 positional arguments (named
458 * arguments are not supported).
459 */
460 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
461 Function expectAsync0(Function callback, [int count = 1]) {
462 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke0;
463 }
464
465 /** Like [expectAsync0] but [callback] should take 1 positional argument. */
466 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
467 Function expectAsync1(Function callback, [int count = 1]) {
468 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke1;
469 }
470
471 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */
472 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
473 Function expectAsync2(Function callback, [int count = 1]) {
474 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke2;
475 }
476
477 /**
478 * Indicate that [callback] is expected to be called until [isDone] returns
479 * true. The unittest framework checks [isDone] after each callback and only
480 * when it returns true will it continue with the following test. Using
481 * [expectAsyncUntil] will also ensure that errors that occur within
482 * [callback] are tracked and reported. [callback] should take between 0 and
483 * 4 positional arguments (named arguments are not supported).
484 */
485 Function _expectAsyncUntil(Function callback, Function isDone) {
486 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke;
487 }
488
489 /**
490 * Indicate that [callback] is expected to be called until [isDone] returns
491 * true. The unittest framework check [isDone] after each callback and only
492 * when it returns true will it continue with the following test. Using
493 * [expectAsyncUntil0] will also ensure that errors that occur within
494 * [callback] are tracked and reported. [callback] should take 0 positional
495 * arguments (named arguments are not supported).
496 */
497 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
498 Function expectAsyncUntil0(Function callback, Function isDone) {
499 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke0;
500 }
501
502 /**
503 * Like [expectAsyncUntil0] but [callback] should take 1 positional argument.
504 */
505 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
506 Function expectAsyncUntil1(Function callback, Function isDone) {
507 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke1;
508 }
509
510 /**
511 * Like [expectAsyncUntil0] but [callback] should take 2 positional arguments.
512 */
513 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
514 Function expectAsyncUntil2(Function callback, Function isDone) {
515 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke2;
516 }
517
518 /**
519 * Wraps the [callback] in a new function and returns that function. The new
520 * function will be able to handle exceptions by directing them to the correct
521 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
522 * might optionally be called but may never be called during the test.
523 * [callback] should take between 0 and 4 positional arguments (named arguments
524 * are not supported).
525 */
526 Function _protectAsync(Function callback) {
527 return new _SpreadArgsHelper.optionalCalls(callback).invoke;
528 }
529
530 /**
531 * Wraps the [callback] in a new function and returns that function. The new
532 * function will be able to handle exceptions by directing them to the correct
533 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
534 * might optionally be called but may never be called during the test.
535 * [callback] should take 0 positional arguments (named arguments are not
536 * supported).
537 */
538 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
539 Function protectAsync0(Function callback) {
540 return new _SpreadArgsHelper.optionalCalls(callback).invoke0;
541 }
542
543 /**
544 * Like [protectAsync0] but [callback] should take 1 positional argument.
545 */
546 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
547 Function protectAsync1(Function callback) {
548 return new _SpreadArgsHelper.optionalCalls(callback).invoke1;
549 }
550
551 /**
552 * Like [protectAsync0] but [callback] should take 2 positional arguments.
553 */
554 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
555 Function protectAsync2(Function callback) {
556 return new _SpreadArgsHelper.optionalCalls(callback).invoke2;
557 }
558
559 /**
560 * Creates a new named group of tests. Calls to group() or test() within the
561 * body of the function passed to this will inherit this group's description.
562 */
563 void group(String description, void body()) {
564 ensureInitialized();
565
566 // Concatenate the new group.
567 final parentGroup = _currentGroup;
568 if (_currentGroup != '') {
569 // Add a space.
570 _currentGroup = '$_currentGroup $description';
571 } else {
572 // The first group.
573 _currentGroup = description;
574 }
575
576 // Groups can be nested, so we need to preserve the current
577 // settings for test setup/teardown.
578 Function parentSetup = _testSetup;
579 Function parentTeardown = _testTeardown;
580
581 try {
582 _testSetup = null;
583 _testTeardown = null;
584 body();
585 } catch(var e, var trace) {
586 _reportTestError(e.toString(), trace == null ? '' : trace.toString());
587 } finally {
588 // Now that the group is over, restore the previous one.
589 _currentGroup = parentGroup;
590 _testSetup = parentSetup;
591 _testTeardown = parentTeardown;
592 }
593 }
594
595 /**
596 * Register a [setUp] function for a test [group]. This function will
597 * be called before each test in the group is run. Note that if groups
598 * are nested only the most locally scoped [setUp] function will be run.
599 * [setUp] and [tearDown] should be called within the [group] before any
600 * calls to [test].
601 */
602 void setUp(Function setupTest) {
603 _testSetup = setupTest;
604 }
605
606 /**
607 * Register a [tearDown] function for a test [group]. This function will
608 * be called after each test in the group is run. Note that if groups
609 * are nested only the most locally scoped [tearDown] function will be run.
610 * [setUp] and [tearDown] should be called within the [group] before any
611 * calls to [test].
612 */
613 void tearDown(Function teardownTest) {
614 _testTeardown = teardownTest;
615 }
616
617 /**
618 * Called when one of the callback functions is done with all expected
619 * calls.
620 */
621 void _handleCallbackFunctionComplete() {
622 // TODO (gram): we defer this to give the nextBatch recursive
623 // stack a chance to unwind. This is a temporary hack but
624 // really a bunch of code here needs to be fixed. We have a
625 // single array that is being iterated through by nextBatch(),
626 // which is recursively invoked in the case of async tests that
627 // run synchronously. Bad things can then happen.
628 _defer(() {
629 if (_currentTest < _tests.length) {
630 final testCase = _tests[_currentTest];
631 --testCase.callbackFunctionsOutstanding;
632 if (testCase.callbackFunctionsOutstanding < 0) {
633 // TODO(gram): Check: Can this even happen?
634 testCase.error(
635 'More calls to _handleCallbackFunctionComplete() than expected.',
636 '');
637 } else if (testCase.callbackFunctionsOutstanding == 0) {
638 if (!testCase.isComplete) {
639 testCase.pass();
640 }
641 _nextTestCase();
642 }
643 }
644 });
645 }
646
647 /** Advance to the next test case. */
648 void _nextTestCase() {
649 _currentTest++;
650 _testRunner();
651 }
652
653 /**
654 * Temporary hack: expose old API.
655 * TODO(gram) remove this when WebKit tests are working with new framework
656 */
657 void callbackDone() {
658 _handleCallbackFunctionComplete();
659 }
660
661 /**
662 * Utility function that can be used to notify the test framework that an
663 * error was caught outside of this library.
664 */
665 void _reportTestError(String msg, String trace) {
666 if (_currentTest < _tests.length) {
667 final testCase = _tests[_currentTest];
668 testCase.error(msg, trace);
669 if (testCase.callbackFunctionsOutstanding > 0) {
670 _nextTestCase();
671 }
672 } else {
673 _uncaughtErrorMessage = "$msg: $trace";
674 }
675 }
676
677 /** Runs [callback] at the end of the event loop. */
678 _defer(void callback()) {
679 // Exploit isolate ports as a platform-independent mechanism to queue a
680 // message at the end of the event loop.
681 // TODO(sigmund): expose this functionality somewhere in our libraries.
682 final port = new ReceivePort();
683 port.receive((msg, reply) {
684 callback();
685 port.close();
686 });
687 port.toSendPort().send(null, null);
688 }
689
690 rerunTests() {
691 _uncaughtErrorMessage = null;
692 _initialized = true; // We don't want to reset the test array.
693 runTests();
694 }
695
696 /** Runs all queued tests, one at a time. */
697 runTests() {
698 _currentTest = 0;
699 _currentGroup = '';
700
701 // If we are soloing a test, remove all the others.
702 if (_soloTest != null) {
703 _tests = _tests.filter((t) => t == _soloTest);
704 }
705
706 if (filter != null) {
707 RegExp re = new RegExp(filter);
708 _tests = _tests.filter((t) => re.hasMatch(t.description));
709 }
710
711 _config.onStart();
712
713 _defer(() {
714 _testRunner();
715 });
716 }
717
718 /**
719 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update
720 * the [_currentTest] status accordingly.
721 */
722 guardAsync(tryBody, [finallyBody, testNum = -1]) {
723 if (testNum < 0) testNum = _currentTest;
724 try {
725 return tryBody();
726 } catch (var e, var trace) {
727 _registerException(testNum, e, trace);
728 } finally {
729 if (finallyBody != null) finallyBody();
730 }
731 }
732
733 /**
734 * Registers that an exception was caught for the current test.
735 */
736 registerException(e, [trace]) {
737 _registerException(_currentTest, e, trace);
738 }
739
740 /**
741 * Registers that an exception was caught for the current test.
742 */
743 _registerException(testNum, e, [trace]) {
744 trace = trace == null ? '' : trace.toString();
745 if (_tests[testNum].result == null) {
746 String message = (e is ExpectException) ? e.message : 'Caught $e';
747 _tests[testNum].fail(message, trace);
748 } else {
749 _tests[testNum].error('Caught $e', trace);
750 }
751 if (testNum == _currentTest) {
752 _nextTestCase();
753 }
754 }
755
756 /**
757 * Runs a batch of tests, yielding whenever an asynchronous test starts
758 * running. Tests will resume executing when such asynchronous test calls
759 * [done] or if it fails with an exception.
760 */
761 _nextBatch() {
762 while (_currentTest < _tests.length) {
763 final testCase = _tests[_currentTest];
764 guardAsync(() {
765 testCase.run();
766 if (!testCase.isComplete && testCase.callbackFunctionsOutstanding == 0) {
767 testCase.pass();
768 }
769 }, testNum:_currentTest);
770
771 if (!testCase.isComplete &&
772 testCase.callbackFunctionsOutstanding > 0) return;
773 _currentTest++;
774 }
775
776 _completeTests();
777 }
778
779 /** Publish results on the page and notify controller. */
780 _completeTests() {
781 int testsPassed_ = 0;
782 int testsFailed_ = 0;
783 int testsErrors_ = 0;
784
785 for (TestCase t in _tests) {
786 switch (t.result) {
787 case _PASS: testsPassed_++; break;
788 case _FAIL: testsFailed_++; break;
789 case _ERROR: testsErrors_++; break;
790 }
791 }
792 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests,
793 _uncaughtErrorMessage);
794 _initialized = false;
795 }
796
797 String _fullSpec(String spec) {
798 if (spec === null) return '$_currentGroup';
799 return _currentGroup != '' ? '$_currentGroup $spec' : spec;
800 }
801
802 void _fail(String message) {
803 throw new ExpectException(message);
804 }
805
806 /**
807 * Lazily initializes the test library if not already initialized.
808 */
809 ensureInitialized() {
810 if (_initialized) return;
811 _initialized = true;
812
813 _tests = <TestCase>[];
814 _testRunner = _nextBatch;
815 _uncaughtErrorMessage = null;
816
817 if (_config == null) {
818 _config = new Configuration();
819 }
820 _config.onInit();
821
822 if (_config.autoStart) {
823 // Immediately queue the suite up. It will run after a timeout (i.e. after
824 // main() has returned).
825 _defer(runTests);
826 }
827 }
828
829 /** Select a solo test by ID. */
830 void setSoloTest(int id) {
831 for (var i = 0; i < _tests.length; i++) {
832 if (_tests[i].id == id) {
833 _soloTest = _tests[i];
834 break;
835 }
836 }
837 }
838
839 /** Enable/disable a test by ID. */
840 void _setTestEnabledState(int testId, bool state) {
841 // Try fast path first.
842 if (_tests.length > testId && _tests[testId].id == testId) {
843 _tests[testId].enabled = state;
844 } else {
845 for (var i = 0; i < _tests.length; i++) {
846 if (_tests[i].id == testId) {
847 _tests[i].enabled = state;
848 break;
849 }
850 }
851 }
852 }
853
854 /** Enable a test by ID. */
855 void enableTest(int testId) => _setTestEnabledState(testId, true);
856
857 /** Disable a test by ID. */
858 void disableTest(int testId) => _setTestEnabledState(testId, false);
859
860 /** Signature for a test function. */
861 typedef void TestFunction();
OLDNEW
« no previous file with comments | « lib/unittest/test_controller.js ('k') | lib/unittest/vm_config.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698