| 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 * A library for writing dart unit tests. | 6 * A library for writing dart unit tests. |
| 7 * | 7 * |
| 8 * To import this library, install the | 8 * To import this library, install the |
| 9 * [unittest package](http://pub.dartlang.org/packages/unittest) via the pub | 9 * [unittest package](http://pub.dartlang.org/packages/unittest) via the pub |
| 10 * package manager. See the [Getting Started](http://pub.dartlang.org/doc) | 10 * package manager. See the [Getting Started](http://pub.dartlang.org/doc) |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 // TODO(nweiz): present an unmodifiable view of this once issue 8321 is fixed. | 204 // TODO(nweiz): present an unmodifiable view of this once issue 8321 is fixed. |
| 205 /** Tests executed in this suite. */ | 205 /** Tests executed in this suite. */ |
| 206 final List<TestCase> testCases = new List<TestCase>(); | 206 final List<TestCase> testCases = new List<TestCase>(); |
| 207 | 207 |
| 208 /** Setup function called before each test in a group */ | 208 /** Setup function called before each test in a group */ |
| 209 Function _testSetup; | 209 Function _testSetup; |
| 210 | 210 |
| 211 /** Teardown function called after each test in a group */ | 211 /** Teardown function called after each test in a group */ |
| 212 Function _testTeardown; | 212 Function _testTeardown; |
| 213 | 213 |
| 214 int _currentTestCaseIndex = 0; | 214 TestCase _currentTestCase = null; |
| 215 | 215 |
| 216 /** [TestCase] currently being executed. */ | 216 /** [TestCase] currently being executed. */ |
| 217 TestCase get currentTestCase => | 217 TestCase get currentTestCase => _currentTestCase; |
| 218 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) | |
| 219 ? testCases[_currentTestCaseIndex] | |
| 220 : null; | |
| 221 | 218 |
| 222 /** Whether the framework is in an initialized state. */ | 219 /** Whether the framework is in an initialized state. */ |
| 223 bool _initialized = false; | 220 bool _initialized = false; |
| 224 | 221 |
| 225 String _uncaughtErrorMessage = null; | 222 String _uncaughtErrorMessage = null; |
| 226 | 223 |
| 227 /** Test case result strings. */ | 224 /** Test case result strings. */ |
| 228 // TODO(gram) we should change these constants to use a different string | 225 // TODO(gram) we should change these constants to use a different string |
| 229 // (so that writing 'FAIL' in the middle of a test doesn't | 226 // (so that writing 'FAIL' in the middle of a test doesn't |
| 230 // imply that the test fails). We can't do it without also changing | 227 // imply that the test fails). We can't do it without also changing |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 } | 282 } |
| 286 | 283 |
| 287 /** Simulates spread arguments using named arguments. */ | 284 /** Simulates spread arguments using named arguments. */ |
| 288 // TODO(sigmund): remove this class and simply use a closure with named | 285 // TODO(sigmund): remove this class and simply use a closure with named |
| 289 // arguments (if still applicable). | 286 // arguments (if still applicable). |
| 290 class _SpreadArgsHelper { | 287 class _SpreadArgsHelper { |
| 291 final Function callback; | 288 final Function callback; |
| 292 final int minExpectedCalls; | 289 final int minExpectedCalls; |
| 293 final int maxExpectedCalls; | 290 final int maxExpectedCalls; |
| 294 final Function isDone; | 291 final Function isDone; |
| 295 final int testNum; | 292 final TestCase testCase; |
| 296 final String id; | 293 final String id; |
| 297 int actualCalls = 0; | 294 int actualCalls = 0; |
| 298 TestCase testCase; | |
| 299 bool complete; | 295 bool complete; |
| 300 static const sentinel = const _Sentinel(); | 296 static const sentinel = const _Sentinel(); |
| 301 | 297 |
| 302 _SpreadArgsHelper(Function callback, int minExpected, int maxExpected, | 298 _SpreadArgsHelper(Function callback, int minExpected, int maxExpected, |
| 303 Function isDone, String id) | 299 Function isDone, String id) |
| 304 : this.callback = callback, | 300 : this.callback = callback, |
| 305 minExpectedCalls = minExpected, | 301 minExpectedCalls = minExpected, |
| 306 maxExpectedCalls = (maxExpected == 0 && minExpected > 0) | 302 maxExpectedCalls = (maxExpected == 0 && minExpected > 0) |
| 307 ? minExpected | 303 ? minExpected |
| 308 : maxExpected, | 304 : maxExpected, |
| 309 this.isDone = isDone, | 305 this.isDone = isDone, |
| 310 testNum = _currentTestCaseIndex, | 306 this.testCase = currentTestCase, |
| 311 this.id = _makeCallbackId(id, callback) { | 307 this.id = _makeCallbackId(id, callback) { |
| 312 ensureInitialized(); | 308 if(testCase == null) { |
| 313 if (!(_currentTestCaseIndex >= 0 && | 309 throw new StateError("No valid test, did you forget to run your test " |
| 314 _currentTestCaseIndex < testCases.length && | 310 "inside a call to test()?"); |
| 315 testCases[_currentTestCaseIndex] != null)) { | |
| 316 print("No valid test, did you forget to run your test inside a call " | |
| 317 "to test()?"); | |
| 318 } | 311 } |
| 319 assert(_currentTestCaseIndex >= 0 && | 312 |
| 320 _currentTestCaseIndex < testCases.length && | |
| 321 testCases[_currentTestCaseIndex] != null); | |
| 322 testCase = testCases[_currentTestCaseIndex]; | |
| 323 if (isDone != null || minExpected > 0) { | 313 if (isDone != null || minExpected > 0) { |
| 324 testCase._callbackFunctionsOutstanding++; | 314 testCase._callbackFunctionsOutstanding++; |
| 325 complete = false; | 315 complete = false; |
| 326 } else { | 316 } else { |
| 327 complete = true; | 317 complete = true; |
| 328 } | 318 } |
| 329 } | 319 } |
| 330 | 320 |
| 331 static _makeCallbackId(String id, Function callback) { | 321 static _makeCallbackId(String id, Function callback) { |
| 332 // Try to create a reasonable id. | 322 // Try to create a reasonable id. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 return callback(arg0, arg1, arg2); | 386 return callback(arg0, arg1, arg2); |
| 397 } else if (arg4 == sentinel) { | 387 } else if (arg4 == sentinel) { |
| 398 return callback(arg0, arg1, arg2, arg3); | 388 return callback(arg0, arg1, arg2, arg3); |
| 399 } else { | 389 } else { |
| 400 testCase.error( | 390 testCase.error( |
| 401 'unittest lib does not support callbacks with more than' | 391 'unittest lib does not support callbacks with more than' |
| 402 ' 4 arguments.', | 392 ' 4 arguments.', |
| 403 ''); | 393 ''); |
| 404 } | 394 } |
| 405 }, | 395 }, |
| 406 after, testNum); | 396 after, testCase); |
| 407 } | 397 } |
| 408 | 398 |
| 409 invoke0() { | 399 invoke0() { |
| 410 return _guardAsync( | 400 return _guardAsync( |
| 411 () { | 401 () { |
| 412 if (shouldCallBack()) { | 402 if (shouldCallBack()) { |
| 413 return callback(); | 403 return callback(); |
| 414 } | 404 } |
| 415 }, | 405 }, |
| 416 after, testNum); | 406 after, testCase); |
| 417 } | 407 } |
| 418 | 408 |
| 419 invoke1(arg1) { | 409 invoke1(arg1) { |
| 420 return _guardAsync( | 410 return _guardAsync( |
| 421 () { | 411 () { |
| 422 if (shouldCallBack()) { | 412 if (shouldCallBack()) { |
| 423 return callback(arg1); | 413 return callback(arg1); |
| 424 } | 414 } |
| 425 }, | 415 }, |
| 426 after, testNum); | 416 after, testCase); |
| 427 } | 417 } |
| 428 | 418 |
| 429 invoke2(arg1, arg2) { | 419 invoke2(arg1, arg2) { |
| 430 return _guardAsync( | 420 return _guardAsync( |
| 431 () { | 421 () { |
| 432 if (shouldCallBack()) { | 422 if (shouldCallBack()) { |
| 433 return callback(arg1, arg2); | 423 return callback(arg1, arg2); |
| 434 } | 424 } |
| 435 }, | 425 }, |
| 436 after, testNum); | 426 after, testCase); |
| 437 } | 427 } |
| 438 } | 428 } |
| 439 | 429 |
| 440 /** | 430 /** |
| 441 * Indicate that [callback] is expected to be called a [count] number of times | 431 * 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 | 432 * (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 | 433 * 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). [id] can be used | |
| 447 * to provide more descriptive error messages if the callback is called more | |
| 448 * often than expected. | |
| 449 */ | |
| 450 Function _expectAsync(Function callback, | |
| 451 {int count: 1, int max: 0, String id}) { | |
| 452 return new _SpreadArgsHelper(callback, count, max, null, id).invoke; | |
| 453 } | |
| 454 | |
| 455 /** | |
| 456 * Indicate that [callback] is expected to be called a [count] number of times | |
| 457 * (by default 1). The unittest framework will wait for the callback to run the | |
| 458 * specified [count] times before it continues with the following test. Using | |
| 459 * [expectAsync0] will also ensure that errors that occur within [callback] are | 434 * [expectAsync0] will also ensure that errors that occur within [callback] are |
| 460 * tracked and reported. [callback] should take 0 positional arguments (named | 435 * tracked and reported. [callback] should take 0 positional arguments (named |
| 461 * arguments are not supported). [id] can be used to provide more | 436 * arguments are not supported). [id] can be used to provide more |
| 462 * descriptive error messages if the callback is called more often than | 437 * descriptive error messages if the callback is called more often than |
| 463 * expected. [max] can be used to specify an upper bound on the number of | 438 * expected. [max] can be used to specify an upper bound on the number of |
| 464 * calls; if this is exceeded the test will fail (or be marked as in error if | 439 * calls; if this is exceeded the test will fail (or be marked as in error if |
| 465 * it was already complete). A value of 0 for [max] (the default) will set | 440 * it was already complete). A value of 0 for [max] (the default) will set |
| 466 * the upper bound to the same value as [count]; i.e. the callback should be | 441 * the upper bound to the same value as [count]; i.e. the callback should be |
| 467 * called exactly [count] times. A value of -1 for [max] will mean no upper | 442 * called exactly [count] times. A value of -1 for [max] will mean no upper |
| 468 * bound. | 443 * bound. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 482 | 457 |
| 483 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */ | 458 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */ |
| 484 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 459 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 485 Function expectAsync2(Function callback, | 460 Function expectAsync2(Function callback, |
| 486 {int count: 1, int max: 0, String id}) { | 461 {int count: 1, int max: 0, String id}) { |
| 487 return new _SpreadArgsHelper(callback, count, max, null, id).invoke2; | 462 return new _SpreadArgsHelper(callback, count, max, null, id).invoke2; |
| 488 } | 463 } |
| 489 | 464 |
| 490 /** | 465 /** |
| 491 * Indicate that [callback] is expected to be called until [isDone] returns | 466 * Indicate that [callback] is expected to be called until [isDone] returns |
| 492 * true. The unittest framework checks [isDone] after each callback and only | |
| 493 * when it returns true will it continue with the following test. Using | |
| 494 * [expectAsyncUntil] will also ensure that errors that occur within | |
| 495 * [callback] are tracked and reported. [callback] should take between 0 and | |
| 496 * 4 positional arguments (named arguments are not supported). [id] can be | |
| 497 * used to identify the callback in error messages (for example if it is called | |
| 498 * after the test case is complete). | |
| 499 */ | |
| 500 Function _expectAsyncUntil(Function callback, Function isDone, {String id}) { | |
| 501 return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke; | |
| 502 } | |
| 503 | |
| 504 /** | |
| 505 * Indicate that [callback] is expected to be called until [isDone] returns | |
| 506 * true. The unittest framework check [isDone] after each callback and only | 467 * true. The unittest framework check [isDone] after each callback and only |
| 507 * when it returns true will it continue with the following test. Using | 468 * when it returns true will it continue with the following test. Using |
| 508 * [expectAsyncUntil0] will also ensure that errors that occur within | 469 * [expectAsyncUntil0] will also ensure that errors that occur within |
| 509 * [callback] are tracked and reported. [callback] should take 0 positional | 470 * [callback] are tracked and reported. [callback] should take 0 positional |
| 510 * arguments (named arguments are not supported). [id] can be used to | 471 * arguments (named arguments are not supported). [id] can be used to |
| 511 * identify the callback in error messages (for example if it is called | 472 * identify the callback in error messages (for example if it is called |
| 512 * after the test case is complete). | 473 * after the test case is complete). |
| 513 */ | 474 */ |
| 514 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 475 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 515 Function expectAsyncUntil0(Function callback, Function isDone, {String id}) { | 476 Function expectAsyncUntil0(Function callback, Function isDone, {String id}) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 530 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 491 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 531 Function expectAsyncUntil2(Function callback, Function isDone, {String id}) { | 492 Function expectAsyncUntil2(Function callback, Function isDone, {String id}) { |
| 532 return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2; | 493 return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2; |
| 533 } | 494 } |
| 534 | 495 |
| 535 /** | 496 /** |
| 536 * Wraps the [callback] in a new function and returns that function. The new | 497 * Wraps the [callback] in a new function and returns that function. The new |
| 537 * function will be able to handle exceptions by directing them to the correct | 498 * function will be able to handle exceptions by directing them to the correct |
| 538 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that | 499 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that |
| 539 * might optionally be called but may never be called during the test. | 500 * might optionally be called but may never be called during the test. |
| 540 * [callback] should take between 0 and 4 positional arguments (named arguments | |
| 541 * are not supported). [id] can be used to identify the callback in error | |
| 542 * messages (for example if it is called after the test case is complete). | |
| 543 */ | |
| 544 Function _protectAsync(Function callback, {String id}) { | |
| 545 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke; | |
| 546 } | |
| 547 | |
| 548 /** | |
| 549 * Wraps the [callback] in a new function and returns that function. The new | |
| 550 * function will be able to handle exceptions by directing them to the correct | |
| 551 * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that | |
| 552 * might optionally be called but may never be called during the test. | |
| 553 * [callback] should take 0 positional arguments (named arguments are not | 501 * [callback] should take 0 positional arguments (named arguments are not |
| 554 * supported). [id] can be used to identify the callback in error | 502 * supported). [id] can be used to identify the callback in error |
| 555 * messages (for example if it is called after the test case is complete). | 503 * messages (for example if it is called after the test case is complete). |
| 556 */ | 504 */ |
| 557 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 505 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 558 Function protectAsync0(Function callback, {String id}) { | 506 Function protectAsync0(Function callback, {String id}) { |
| 559 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0; | 507 return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0; |
| 560 } | 508 } |
| 561 | 509 |
| 562 /** | 510 /** |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 | 561 |
| 614 /** | 562 /** |
| 615 * Register a [setUp] function for a test [group]. This function will | 563 * Register a [setUp] function for a test [group]. This function will |
| 616 * be called before each test in the group is run. Note that if groups | 564 * be called before each test in the group is run. Note that if groups |
| 617 * are nested only the most locally scoped [setUpTest] function will be run. | 565 * are nested only the most locally scoped [setUpTest] function will be run. |
| 618 * [setUp] and [tearDown] should be called within the [group] before any | 566 * [setUp] and [tearDown] should be called within the [group] before any |
| 619 * calls to [test]. The [setupTest] function can be asynchronous; in this | 567 * calls to [test]. The [setupTest] function can be asynchronous; in this |
| 620 * case it must return a [Future]. | 568 * case it must return a [Future]. |
| 621 */ | 569 */ |
| 622 void setUp(Function setupTest) { | 570 void setUp(Function setupTest) { |
| 571 _requireNotRunning(); |
| 623 _testSetup = setupTest; | 572 _testSetup = setupTest; |
| 624 } | 573 } |
| 625 | 574 |
| 626 /** | 575 /** |
| 627 * Register a [tearDown] function for a test [group]. This function will | 576 * Register a [tearDown] function for a test [group]. This function will |
| 628 * be called after each test in the group is run. Note that if groups | 577 * be called after each test in the group is run. Note that if groups |
| 629 * are nested only the most locally scoped [teardownTest] function will be run. | 578 * are nested only the most locally scoped [teardownTest] function will be run. |
| 630 * [setUp] and [tearDown] should be called within the [group] before any | 579 * [setUp] and [tearDown] should be called within the [group] before any |
| 631 * calls to [test]. The [teardownTest] function can be asynchronous; in this | 580 * calls to [test]. The [teardownTest] function can be asynchronous; in this |
| 632 * case it must return a [Future]. | 581 * case it must return a [Future]. |
| 633 */ | 582 */ |
| 634 void tearDown(Function teardownTest) { | 583 void tearDown(Function teardownTest) { |
| 584 _requireNotRunning(); |
| 635 _testTeardown = teardownTest; | 585 _testTeardown = teardownTest; |
| 636 } | 586 } |
| 637 | 587 |
| 638 /** Advance to the next test case. */ | |
| 639 void _nextTestCase() { | |
| 640 _defer(() { | |
| 641 _currentTestCaseIndex++; | |
| 642 _nextBatch(); | |
| 643 }); | |
| 644 } | |
| 645 | |
| 646 /** | 588 /** |
| 647 * Utility function that can be used to notify the test framework that an | 589 * Utility function that can be used to notify the test framework that an |
| 648 * error was caught outside of this library. | 590 * error was caught outside of this library. |
| 649 */ | 591 */ |
| 650 void _reportTestError(String msg, String trace) { | 592 void _reportTestError(String msg, String trace) { |
| 651 if (_currentTestCaseIndex < testCases.length) { | 593 if (currentTestCase != null) { |
| 652 final testCase = testCases[_currentTestCaseIndex]; | 594 currentTestCase.error(msg, trace); |
| 653 testCase.error(msg, trace); | |
| 654 } else { | 595 } else { |
| 655 _uncaughtErrorMessage = "$msg: $trace"; | 596 _uncaughtErrorMessage = "$msg: $trace"; |
| 656 } | 597 } |
| 657 } | 598 } |
| 658 | 599 |
| 659 /** | |
| 660 * Runs [callback] at the end of the event loop. Note that we don't wrap | |
| 661 * the callback in guardAsync; this is for test framework functions which | |
| 662 * should not be throwing unexpected exceptions that end up failing test | |
| 663 * cases! Furthermore, we need the final exception to be thrown but not | |
| 664 * caught by the test framework if any test cases failed. However, tests | |
| 665 * that make use of a similar defer function *should* wrap the callback | |
| 666 * (as we do in unitttest_test.dart). | |
| 667 */ | |
| 668 _defer(void callback()) { | |
| 669 (new Future.value()).then((_) => callback()); | |
| 670 } | |
| 671 | |
| 672 void rerunTests() { | 600 void rerunTests() { |
| 673 _uncaughtErrorMessage = null; | 601 assert(_uncaughtErrorMessage == null); |
| 674 _initialized = true; // We don't want to reset the test array. | |
| 675 runTests(); | 602 runTests(); |
| 676 } | 603 } |
| 677 | 604 |
| 678 /** | 605 /** |
| 679 * Filter the tests. [testFilter] can be a [RegExp], a [String] or a | 606 * Filter the tests. [testFilter] can be a [RegExp], a [String] or a |
| 680 * predicate function. This is different to enabling/disabling tests | 607 * predicate function. This is different to enabling/disabling tests |
| 681 * in that it removes the tests completely. | 608 * in that it removes the tests completely. |
| 682 */ | 609 */ |
| 683 void filterTests(testFilter) { | 610 void filterTests(testFilter) { |
| 684 var filterFunction; | 611 _requireNotRunning(); |
| 612 Function filterFunction; |
| 685 if (testFilter is String) { | 613 if (testFilter is String) { |
| 686 RegExp re = new RegExp(testFilter); | 614 RegExp re = new RegExp(testFilter); |
| 687 filterFunction = (t) => re.hasMatch(t.description); | 615 filterFunction = (t) => re.hasMatch(t.description); |
| 688 } else if (testFilter is RegExp) { | 616 } else if (testFilter is RegExp) { |
| 689 filterFunction = (t) => testFilter.hasMatch(t.description); | 617 filterFunction = (t) => testFilter.hasMatch(t.description); |
| 690 } else if (testFilter is Function) { | 618 } else if (testFilter is Function) { |
| 691 filterFunction = testFilter; | 619 filterFunction = testFilter; |
| 692 } | 620 } |
| 693 testCases.retainWhere(filterFunction); | 621 testCases.retainWhere(filterFunction); |
| 694 } | 622 } |
| 695 | 623 |
| 696 /** Runs all queued tests, one at a time. */ | 624 /** Runs all queued tests, one at a time. */ |
| 697 void runTests() { | 625 void runTests() { |
| 698 _ensureInitialized(false); | 626 _ensureInitialized(false); |
| 699 _currentTestCaseIndex = 0; | 627 assert(_currentTestCase == null); |
| 628 |
| 700 _currentGroup = ''; | 629 _currentGroup = ''; |
| 701 | 630 |
| 702 // If we are soloing a test, remove all the others. | 631 // If we are soloing a test, remove all the others. |
| 703 if (_soloTest != null) { | 632 if (_soloTest != null) { |
| 704 filterTests((t) => t == _soloTest); | 633 filterTests((t) => t == _soloTest); |
| 705 } | 634 } |
| 706 | 635 |
| 707 _config.onStart(); | 636 _config.onStart(); |
| 708 | 637 |
| 709 _defer(() { | 638 new Future(_nextBatch); |
| 710 _nextBatch(); | |
| 711 }); | |
| 712 } | 639 } |
| 713 | 640 |
| 714 /** | 641 /** |
| 715 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is | 642 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is |
| 716 * passed to the corresponding test. | 643 * passed to the corresponding test. |
| 717 * | 644 * |
| 718 * The value returned by [tryBody] (if any) is returned by [guardAsync]. | 645 * The value returned by [tryBody] (if any) is returned by [guardAsync]. |
| 719 */ | 646 */ |
| 720 guardAsync(Function tryBody) { | 647 guardAsync(Function tryBody) { |
| 721 return _guardAsync(tryBody, null, _currentTestCaseIndex); | 648 return _guardAsync(tryBody, null, currentTestCase); |
| 722 } | 649 } |
| 723 | 650 |
| 724 _guardAsync(Function tryBody, Function finallyBody, int testNum) { | 651 _guardAsync(Function tryBody, Function finallyBody, TestCase testCase) { |
| 725 assert(testNum >= 0); | 652 assert(testCase != null); |
| 726 try { | 653 try { |
| 727 return tryBody(); | 654 return tryBody(); |
| 728 } catch (e, trace) { | 655 } catch (e, trace) { |
| 729 _registerException(testNum, e, trace); | 656 _registerException(testCase, e, trace); |
| 730 } finally { | 657 } finally { |
| 731 if (finallyBody != null) finallyBody(); | 658 if (finallyBody != null) finallyBody(); |
| 732 } | 659 } |
| 733 } | 660 } |
| 734 | 661 |
| 735 /** | 662 /** |
| 736 * Registers that an exception was caught for the current test. | 663 * Registers that an exception was caught for the current test. |
| 737 */ | 664 */ |
| 738 void registerException(e, [trace]) { | 665 void registerException(e, [trace]) { |
| 739 _registerException(_currentTestCaseIndex, e, trace); | 666 _registerException(currentTestCase, e, trace); |
| 740 } | 667 } |
| 741 | 668 |
| 742 /** | 669 /** |
| 743 * Registers that an exception was caught for the current test. | 670 * Registers that an exception was caught for the current test. |
| 744 */ | 671 */ |
| 745 void _registerException(testNum, e, [trace]) { | 672 void _registerException(TestCase testCase, e, [trace]) { |
| 673 assert(testCase != null); |
| 746 trace = trace == null ? '' : trace.toString(); | 674 trace = trace == null ? '' : trace.toString(); |
| 747 String message = (e is TestFailure) ? e.message : 'Caught $e'; | 675 String message = (e is TestFailure) ? e.message : 'Caught $e'; |
| 748 if (testCases[testNum].result == null) { | 676 if (testCase.result == null) { |
| 749 testCases[testNum].fail(message, trace); | 677 testCase.fail(message, trace); |
| 750 } else { | 678 } else { |
| 751 testCases[testNum].error(message, trace); | 679 testCase.error(message, trace); |
| 752 } | 680 } |
| 753 } | 681 } |
| 754 | 682 |
| 755 /** | 683 /** |
| 756 * Runs a batch of tests, yielding whenever an asynchronous test starts | 684 * Executes tests in order starting with the provided index. |
| 757 * running. Tests will resume executing when such asynchronous test calls | 685 * If a test is synchronous, the following test is executed immediately |
| 758 * [done] or if it fails with an exception. | 686 * For asynchronous tests, a Future is returned which completes with _nextBatch |
| 687 * starting at the next index. |
| 688 * Future.forEach is explicitly not used because it slows down synchronous tests |
| 689 * noticeably |
| 759 */ | 690 */ |
| 760 void _nextBatch() { | 691 Future _nextBatch([int index = 0]) { |
| 761 while (true) { | 692 for(int i = index; i < testCases.length; i++) { |
| 762 if (_currentTestCaseIndex >= testCases.length) { | 693 _currentTestCase = testCases[i]; |
| 763 _completeTests(); | 694 |
| 764 break; | 695 Future f = guardAsync(_currentTestCase._run); |
| 696 |
| 697 if(f != null) { |
| 698 return f.then((_) => _nextBatch(i + 1)); |
| 765 } | 699 } |
| 766 final testCase = testCases[_currentTestCaseIndex]; | |
| 767 var f = _guardAsync(testCase._run, null, _currentTestCaseIndex); | |
| 768 if (f != null) { | |
| 769 f.whenComplete(() { | |
| 770 _nextTestCase(); // Schedule the next test. | |
| 771 }); | |
| 772 break; | |
| 773 } | |
| 774 _currentTestCaseIndex++; | |
| 775 } | 700 } |
| 701 _currentTestCase = null; |
| 702 return new Future(_completeTests); |
| 776 } | 703 } |
| 777 | 704 |
| 778 /** Publish results on the page and notify controller. */ | 705 /** Publish results on the page and notify controller. */ |
| 779 void _completeTests() { | 706 void _completeTests() { |
| 780 if (!_initialized) return; | 707 assert(_initialized); |
| 708 assert(_currentTestCase == null); |
| 709 |
| 781 int passed = 0; | 710 int passed = 0; |
| 782 int failed = 0; | 711 int failed = 0; |
| 783 int errors = 0; | 712 int errors = 0; |
| 784 | 713 |
| 785 for (TestCase t in testCases) { | 714 for (TestCase t in testCases) { |
| 786 switch (t.result) { | 715 switch (t.result) { |
| 787 case PASS: passed++; break; | 716 case PASS: passed++; break; |
| 788 case FAIL: failed++; break; | 717 case FAIL: failed++; break; |
| 789 case ERROR: errors++; break; | 718 case ERROR: errors++; break; |
| 790 } | 719 } |
| 791 } | 720 } |
| 792 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); | 721 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); |
| 793 _config.onDone(passed > 0 && failed == 0 && errors == 0 && | 722 _config.onDone(passed > 0 && failed == 0 && errors == 0 && |
| 794 _uncaughtErrorMessage == null); | 723 _uncaughtErrorMessage == null); |
| 795 _initialized = false; | 724 |
| 725 _uncaughtErrorMessage = null; |
| 796 } | 726 } |
| 797 | 727 |
| 798 String _fullSpec(String spec) { | 728 String _fullSpec(String spec) { |
| 799 if (spec == null) return '$_currentGroup'; | 729 if (spec == null) return '$_currentGroup'; |
| 800 return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec; | 730 return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec; |
| 801 } | 731 } |
| 802 | 732 |
| 803 /** | 733 /** |
| 804 * Lazily initializes the test library if not already initialized. | 734 * Lazily initializes the test library if not already initialized. |
| 805 */ | 735 */ |
| 806 void ensureInitialized() { | 736 void ensureInitialized() { |
| 807 _ensureInitialized(true); | 737 _ensureInitialized(true); |
| 808 } | 738 } |
| 809 | 739 |
| 740 void _requireNotRunning() { |
| 741 if(_currentTestCase != null) { |
| 742 throw new StateError("A forbidden operation occured " |
| 743 "while tests were running"); |
| 744 } |
| 745 } |
| 746 |
| 810 void _ensureInitialized(bool configAutoStart) { | 747 void _ensureInitialized(bool configAutoStart) { |
| 748 _requireNotRunning(); |
| 811 if (_initialized) { | 749 if (_initialized) { |
| 812 return; | 750 return; |
| 813 } | 751 } |
| 814 _initialized = true; | 752 _initialized = true; |
| 815 // Hook our async guard into the matcher library. | 753 // Hook our async guard into the matcher library. |
| 816 wrapAsync = (f, [id]) => expectAsync1(f, id: id); | 754 wrapAsync = (f, [id]) => expectAsync1(f, id: id); |
| 817 | 755 |
| 818 _uncaughtErrorMessage = null; | 756 _uncaughtErrorMessage = null; |
| 819 | 757 |
| 820 if (_config == null) { | 758 if (_config == null) { |
| 821 unittestConfiguration = new Configuration(); | 759 unittestConfiguration = new Configuration(); |
| 822 } | 760 } |
| 823 _config.onInit(); | 761 _config.onInit(); |
| 824 | 762 |
| 825 if (configAutoStart && _config.autoStart) { | 763 if (configAutoStart && _config.autoStart) { |
| 826 // Immediately queue the suite up. It will run after a timeout (i.e. after | 764 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 827 // main() has returned). | 765 // main() has returned). |
| 828 _defer(runTests); | 766 new Future(runTests); |
| 829 } | 767 } |
| 830 } | 768 } |
| 831 | 769 |
| 832 /** Select a solo test by ID. */ | 770 /** Select a solo test by ID. */ |
| 833 void setSoloTest(int id) { | 771 void setSoloTest(int id) { |
| 834 for (var i = 0; i < testCases.length; i++) { | 772 for (var i = 0; i < testCases.length; i++) { |
| 835 if (testCases[i].id == id) { | 773 if (testCases[i].id == id) { |
| 836 _soloTest = testCases[i]; | 774 _soloTest = testCases[i]; |
| 837 break; | 775 break; |
| 838 } | 776 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 855 } | 793 } |
| 856 | 794 |
| 857 /** Enable a test by ID. */ | 795 /** Enable a test by ID. */ |
| 858 void enableTest(int testId) => _setTestEnabledState(testId, true); | 796 void enableTest(int testId) => _setTestEnabledState(testId, true); |
| 859 | 797 |
| 860 /** Disable a test by ID. */ | 798 /** Disable a test by ID. */ |
| 861 void disableTest(int testId) => _setTestEnabledState(testId, false); | 799 void disableTest(int testId) => _setTestEnabledState(testId, false); |
| 862 | 800 |
| 863 /** Signature for a test function. */ | 801 /** Signature for a test function. */ |
| 864 typedef dynamic TestFunction(); | 802 typedef dynamic TestFunction(); |
| OLD | NEW |