OLD | NEW |
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 * Support for writing Dart unit tests. | 6 * Support for writing Dart unit tests. |
7 * | 7 * |
8 * For information on installing and importing this library, see the | 8 * For information on installing and importing this library, see the |
9 * [unittest package on pub.dartlang.org] | 9 * [unittest package on pub.dartlang.org] |
10 * (http://pub.dartlang.org/packages/unittest). | 10 * (http://pub.dartlang.org/packages/unittest). |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 _testCases.clear(); | 292 _testCases.clear(); |
293 } | 293 } |
294 ++_soloNestingLevel; | 294 ++_soloNestingLevel; |
295 try { | 295 try { |
296 test(spec, body); | 296 test(spec, body); |
297 } finally { | 297 } finally { |
298 --_soloNestingLevel; | 298 --_soloNestingLevel; |
299 } | 299 } |
300 } | 300 } |
301 | 301 |
302 /** Sentinel value for [_SpreadArgsHelper]. */ | |
303 class _Sentinel { | |
304 const _Sentinel(); | |
305 } | |
306 | |
307 /** | 302 /** |
308 * Indicate that [callback] is expected to be called a [count] number of times | 303 * Indicate that [callback] is expected to be called a [count] number of times |
309 * (by default 1). The unittest framework will wait for the callback to run the | 304 * (by default 1). The unittest framework will wait for the callback to run the |
310 * specified [count] times before it continues with the following test. Using | 305 * specified [count] times before it continues with the following test. Using |
311 * [expectAsync0] will also ensure that errors that occur within [callback] are | 306 * [expectAsync0] will also ensure that errors that occur within [callback] are |
312 * tracked and reported. [callback] should take 0 positional arguments (named | 307 * tracked and reported. [callback] should take 0 positional arguments (named |
313 * arguments are not supported). [id] can be used to provide more | 308 * arguments are not supported). [id] can be used to provide more |
314 * descriptive error messages if the callback is called more often than | 309 * descriptive error messages if the callback is called more often than |
315 * expected. [max] can be used to specify an upper bound on the number of | 310 * expected. [max] can be used to specify an upper bound on the number of |
316 * calls; if this is exceeded the test will fail (or be marked as in error if | 311 * calls; if this is exceeded the test will fail (or be marked as in error if |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 | 359 |
365 /** | 360 /** |
366 * Like [expectAsyncUntil0] but [callback] should take 2 positional arguments. | 361 * Like [expectAsyncUntil0] but [callback] should take 2 positional arguments. |
367 */ | 362 */ |
368 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 363 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
369 Function expectAsyncUntil2(Function callback, Function isDone, {String id}) { | 364 Function expectAsyncUntil2(Function callback, Function isDone, {String id}) { |
370 return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2; | 365 return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2; |
371 } | 366 } |
372 | 367 |
373 /** | 368 /** |
374 * Wraps the [callback] in a new function and returns that function. The new | 369 * *Deprecated* |
375 * function will be able to handle exceptions by directing them to the correct | 370 * |
376 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that | 371 * All tests are now run an isolated [Zone]. |
377 * might optionally be called but may never be called during the test. | 372 * |
378 * [callback] should take 0 positional arguments (named arguments are not | 373 * You can safely remove calls to this method. |
379 * supported). [id] can be used to identify the callback in error | |
380 * messages (for example if it is called after the test case is complete). | |
381 */ | 374 */ |
382 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 375 @deprecated |
383 Function protectAsync0(Function callback, {String id}) { | 376 Function protectAsync0(Function callback, {String id}) { |
384 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0; | 377 return callback; |
385 } | 378 } |
386 | 379 |
387 /** | 380 /** |
388 * Like [protectAsync0] but [callback] should take 1 positional argument. | 381 * *Deprecated* |
| 382 * |
| 383 * All tests are now run an isolated [Zone]. |
| 384 * |
| 385 * You can safely remove calls to this method. |
389 */ | 386 */ |
390 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 387 @deprecated |
391 Function protectAsync1(Function callback, {String id}) { | 388 Function protectAsync1(Function callback, {String id}) { |
392 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke1; | 389 return callback; |
393 } | 390 } |
394 | 391 |
395 /** | 392 /** |
396 * Like [protectAsync0] but [callback] should take 2 positional arguments. | 393 * *Deprecated* |
| 394 * |
| 395 * All tests are now run an isolated [Zone]. |
| 396 * |
| 397 * You can safely remove calls to this method. |
397 */ | 398 */ |
398 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 399 @deprecated |
399 Function protectAsync2(Function callback, {String id}) { | 400 Function protectAsync2(Function callback, {String id}) { |
400 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2; | 401 return callback; |
401 } | 402 } |
402 | 403 |
403 /** | 404 /** |
404 * Creates a new named group of tests. Calls to group() or test() within the | 405 * Creates a new named group of tests. Calls to group() or test() within the |
405 * body of the function passed to this will inherit this group's description. | 406 * body of the function passed to this will inherit this group's description. |
406 */ | 407 */ |
407 void group(String description, void body()) { | 408 void group(String description, void body()) { |
408 ensureInitialized(); | 409 ensureInitialized(); |
409 _requireNotRunning(); | 410 _requireNotRunning(); |
410 _currentContext = new _GroupContext(_currentContext, description); | 411 _currentContext = new _GroupContext(_currentContext, description); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 void handleExternalError(e, String message, [stack]) { | 477 void handleExternalError(e, String message, [stack]) { |
477 var msg = '$message\nCaught $e'; | 478 var msg = '$message\nCaught $e'; |
478 | 479 |
479 if (currentTestCase != null) { | 480 if (currentTestCase != null) { |
480 currentTestCase._error(msg, stack); | 481 currentTestCase._error(msg, stack); |
481 } else { | 482 } else { |
482 _uncaughtErrorMessage = "$msg: $stack"; | 483 _uncaughtErrorMessage = "$msg: $stack"; |
483 } | 484 } |
484 } | 485 } |
485 | 486 |
486 void rerunTests() { | |
487 _uncaughtErrorMessage = null; | |
488 _initialized = true; // We don't want to reset the test array. | |
489 runTests(); | |
490 } | |
491 | |
492 /** | 487 /** |
493 * Filter the tests. [testFilter] can be a [RegExp], a [String] or a | 488 * Filter the tests. [testFilter] can be a [RegExp], a [String] or a |
494 * predicate function. This is different to enabling/disabling tests | 489 * predicate function. This is different to enabling/disabling tests |
495 * in that it removes the tests completely. | 490 * in that it removes the tests completely. |
496 */ | 491 */ |
497 void filterTests(testFilter) { | 492 void filterTests(testFilter) { |
498 var filterFunction; | 493 var filterFunction; |
499 if (testFilter is String) { | 494 if (testFilter is String) { |
500 RegExp re = new RegExp(testFilter); | 495 RegExp re = new RegExp(testFilter); |
501 filterFunction = (t) => re.hasMatch(t.description); | 496 filterFunction = (t) => re.hasMatch(t.description); |
502 } else if (testFilter is RegExp) { | 497 } else if (testFilter is RegExp) { |
503 filterFunction = (t) => testFilter.hasMatch(t.description); | 498 filterFunction = (t) => testFilter.hasMatch(t.description); |
504 } else if (testFilter is Function) { | 499 } else if (testFilter is Function) { |
505 filterFunction = testFilter; | 500 filterFunction = testFilter; |
506 } | 501 } |
507 _testCases.retainWhere(filterFunction); | 502 _testCases.retainWhere(filterFunction); |
508 } | 503 } |
509 | 504 |
510 /** Runs all queued tests, one at a time. */ | 505 /** Runs all queued tests, one at a time. */ |
511 void runTests() { | 506 void runTests() { |
512 _requireNotRunning(); | 507 _requireNotRunning(); |
513 _ensureInitialized(false); | 508 _ensureInitialized(false); |
514 _currentTestCaseIndex = 0; | 509 _currentTestCaseIndex = 0; |
515 _config.onStart(); | 510 _config.onStart(); |
516 _runTest(); | 511 _runTest(); |
517 } | 512 } |
518 | 513 |
519 /** | 514 /** |
520 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is | 515 * *Deprecated* |
521 * passed to the corresponding test. | |
522 * | 516 * |
523 * The value returned by [tryBody] (if any) is returned by [guardAsync]. | 517 * All tests are now run an isolated [Zone]. |
| 518 * |
| 519 * You can safely remove calls to this method. |
524 */ | 520 */ |
| 521 @deprecated |
525 guardAsync(Function tryBody) { | 522 guardAsync(Function tryBody) { |
526 return _guardAsync(tryBody, null, currentTestCase); | 523 return tryBody(); |
527 } | |
528 | |
529 _guardAsync(Function tryBody, Function finallyBody, TestCase testCase) { | |
530 assert(testCase != null); | |
531 try { | |
532 return tryBody(); | |
533 } catch (e, trace) { | |
534 _registerException(testCase, e, trace); | |
535 } finally { | |
536 if (finallyBody != null) finallyBody(); | |
537 } | |
538 } | 524 } |
539 | 525 |
540 /** | 526 /** |
541 * Registers that an exception was caught for the current test. | 527 * Registers that an exception was caught for the current test. |
542 */ | 528 */ |
543 void registerException(e, [trace]) { | 529 void registerException(e, [trace]) { |
544 _registerException(currentTestCase, e, trace); | 530 _registerException(currentTestCase, e, trace); |
545 } | 531 } |
546 | 532 |
547 /** | 533 /** |
(...skipping 10 matching lines...) Expand all Loading... |
558 | 544 |
559 /** | 545 /** |
560 * Runs the next test. | 546 * Runs the next test. |
561 */ | 547 */ |
562 void _runTest() { | 548 void _runTest() { |
563 if (_currentTestCaseIndex >= testCases.length) { | 549 if (_currentTestCaseIndex >= testCases.length) { |
564 assert(_currentTestCaseIndex == testCases.length); | 550 assert(_currentTestCaseIndex == testCases.length); |
565 _completeTests(); | 551 _completeTests(); |
566 } else { | 552 } else { |
567 var testCase = testCases[_currentTestCaseIndex]; | 553 var testCase = testCases[_currentTestCaseIndex]; |
568 Future f = _guardAsync(testCase._run, null, testCase); | 554 Future f = runZoned(testCase._run, onError: (error, stack) { |
| 555 // TODO(kevmoo) Do a better job of flagging these are async errors. |
| 556 // https://code.google.com/p/dart/issues/detail?id=16530 |
| 557 _registerException(testCase, error, stack); |
| 558 }); |
| 559 |
569 var timeout = unittestConfiguration.timeout; | 560 var timeout = unittestConfiguration.timeout; |
570 | 561 |
571 Timer timer; | 562 Timer timer; |
572 if (timeout != null) { | 563 if (timeout != null) { |
573 try { | 564 try { |
574 timer = new Timer(timeout, () { | 565 timer = new Timer(timeout, () { |
575 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); | 566 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); |
576 _nextTestCase(); | 567 _nextTestCase(); |
577 }); | 568 }); |
578 } on UnsupportedError catch (e) { | 569 } on UnsupportedError catch (e) { |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
711 | 702 |
712 if (!filterStacks) return trace; | 703 if (!filterStacks) return trace; |
713 | 704 |
714 // Format the stack trace by removing everything above TestCase._runTest, | 705 // Format the stack trace by removing everything above TestCase._runTest, |
715 // which is usually going to be irrelevant. Also fold together unittest and | 706 // which is usually going to be irrelevant. Also fold together unittest and |
716 // core library calls so only the function the user called is visible. | 707 // core library calls so only the function the user called is visible. |
717 return new Trace(trace.frames.takeWhile((frame) { | 708 return new Trace(trace.frames.takeWhile((frame) { |
718 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; | 709 return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; |
719 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); | 710 })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); |
720 } | 711 } |
OLD | NEW |