Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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, specify the relative path to | 8 * To import this library, specify the relative path to |
| 9 * lib/unittest/unittest.dart. | 9 * lib/unittest/unittest.dart. |
| 10 * | 10 * |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 class _Sentinel { | 287 class _Sentinel { |
| 288 const _Sentinel(); | 288 const _Sentinel(); |
| 289 } | 289 } |
| 290 | 290 |
| 291 // TODO(sigmund): make a singleton const field when frog supports passing those | 291 // TODO(sigmund): make a singleton const field when frog supports passing those |
| 292 // as default values to named arguments. | 292 // as default values to named arguments. |
| 293 final _sentinel = const _Sentinel(); | 293 final _sentinel = const _Sentinel(); |
| 294 | 294 |
| 295 /** Simulates spread arguments using named arguments. */ | 295 /** Simulates spread arguments using named arguments. */ |
| 296 // TODO(sigmund): remove this class and simply use a closure with named | 296 // TODO(sigmund): remove this class and simply use a closure with named |
| 297 // arguments inside [_expectAsync], once bug 282 is fixed or frog is replaced by | 297 // arguments inside [_expectAsync], once bug 282 is fixed or frog is replaced by |
|
eub
2012/06/15 21:02:49
"now that frog is replaced by dart2js" :)
gram
2012/06/15 21:25:55
I tweaked the comment a bit. I'm not sure it makes
| |
| 298 // dart2js. | 298 // dart2js. |
| 299 class _SpreadArgsHelper { | 299 class _SpreadArgsHelper { |
| 300 Function callback; | 300 Function _callback; |
| 301 int expectedCalls; | 301 int _expectedCalls; |
| 302 int calls = 0; | 302 int _calls = 0; |
| 303 TestCase testCase; | 303 TestCase _testCase; |
| 304 _SpreadArgsHelper(this.callback, this.expectedCalls) { | 304 Function _shouldCallBack; |
| 305 Expect.isTrue(_currentTest < _tests.length); | 305 Function _isDone; |
| 306 testCase = _tests[_currentTest]; | 306 |
| 307 testCase.callbacks++; | 307 _init(Function callback, Function shouldCallBack, Function isDone, |
| 308 [expectedCalls = 0]) { | |
| 309 assert(_currentTest < _tests.length); | |
| 310 _callback = callback; | |
| 311 _shouldCallBack = shouldCallBack; | |
| 312 _isDone = isDone; | |
| 313 _expectedCalls = expectedCalls; | |
| 314 _testCase = _tests[_currentTest]; | |
| 315 if (expectedCalls > 0) { | |
| 316 _testCase.callbacks++; | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 _SpreadArgsHelper(callback, shouldCallBack, isDone) { | |
| 321 _init(callback, shouldCallBack, isDone); | |
| 322 } | |
| 323 | |
| 324 _SpreadArgsHelper.fixedCallCount(callback, expectedCalls) { | |
| 325 _init(callback, _checkCallCount, _allCallsDone, expectedCalls); | |
| 326 } | |
| 327 | |
| 328 _SpreadArgsHelper.variableCallCount(callback, isDone) { | |
| 329 _init(callback, _always, isDone); | |
| 330 } | |
| 331 | |
| 332 _after() { | |
| 333 if (_isDone()) { | |
| 334 _handleAllCallbacksDone(); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 _allCallsDone() => _calls == _expectedCalls; | |
| 339 | |
| 340 _always() { | |
| 341 // Always run except if the test is done. | |
| 342 if (_testCase.isComplete) { | |
| 343 _testCase.error( | |
| 344 'Callback called after already being marked as done ($_calls)', | |
| 345 ''); | |
| 346 _state = _UNCAUGHT_ERROR; | |
| 347 return false; | |
| 348 } else { | |
| 349 return true; | |
| 350 } | |
| 308 } | 351 } |
| 309 | 352 |
| 310 invoke([arg0 = _sentinel, arg1 = _sentinel, arg2 = _sentinel, | 353 invoke([arg0 = _sentinel, arg1 = _sentinel, arg2 = _sentinel, |
| 311 arg3 = _sentinel, arg4 = _sentinel]) { | 354 arg3 = _sentinel, arg4 = _sentinel]) { |
| 312 return guardAsync(() { | 355 return guardAsync(() { |
| 313 if (!_incrementCall()) { | 356 ++_calls; |
| 357 if (!_shouldCallBack()) { | |
| 314 return; | 358 return; |
| 315 } else if (arg0 == _sentinel) { | 359 } else if (arg0 == _sentinel) { |
| 316 return callback(); | 360 return _callback(); |
| 317 } else if (arg1 == _sentinel) { | 361 } else if (arg1 == _sentinel) { |
| 318 return callback(arg0); | 362 return _callback(arg0); |
| 319 } else if (arg2 == _sentinel) { | 363 } else if (arg2 == _sentinel) { |
| 320 return callback(arg0, arg1); | 364 return _callback(arg0, arg1); |
| 321 } else if (arg3 == _sentinel) { | 365 } else if (arg3 == _sentinel) { |
| 322 return callback(arg0, arg1, arg2); | 366 return _callback(arg0, arg1, arg2); |
| 323 } else if (arg4 == _sentinel) { | 367 } else if (arg4 == _sentinel) { |
| 324 return callback(arg0, arg1, arg2, arg3); | 368 return _callback(arg0, arg1, arg2, arg3); |
| 325 } else { | 369 } else { |
| 326 testCase.error( | 370 _testCase.error( |
| 327 'unittest lib does not support callbacks with more than 4 arguments', | 371 'unittest lib does not support callbacks with more than 4 arguments', |
| 328 ''); | 372 ''); |
| 329 _state = _UNCAUGHT_ERROR; | 373 _state = _UNCAUGHT_ERROR; |
| 330 } | 374 } |
| 331 }, () { if (calls == expectedCalls) callbackDone(); }); | 375 }, |
| 376 _after); | |
| 332 } | 377 } |
| 333 | 378 |
| 334 invoke0() { | 379 invoke0() { |
| 335 return guardAsync( | 380 return guardAsync( |
| 336 () => _incrementCall() ? callback() : null, | 381 () { |
| 337 () { if (calls == expectedCalls) callbackDone(); }); | 382 ++_calls; |
| 383 if (_shouldCallBack()) { | |
| 384 return _callback(); | |
| 385 } | |
| 386 }, | |
| 387 _after); | |
| 338 } | 388 } |
| 339 | 389 |
| 340 invoke1(arg1) { | 390 invoke1(arg1) { |
| 341 return guardAsync( | 391 return guardAsync( |
| 342 () => _incrementCall() ? callback(arg1) : null, | 392 () { |
| 343 () { if (calls == expectedCalls) callbackDone(); }); | 393 ++_calls; |
| 394 if (_shouldCallBack()) { | |
| 395 return _callback(arg1); | |
| 396 } | |
| 397 }, | |
| 398 _after); | |
| 344 } | 399 } |
| 345 | 400 |
| 346 invoke2(arg1, arg2) { | 401 invoke2(arg1, arg2) { |
| 347 return guardAsync( | 402 return guardAsync( |
| 348 () => _incrementCall() ? callback(arg1, arg2) : null, | 403 () { |
| 349 () { if (calls == expectedCalls) callbackDone(); }); | 404 ++_calls; |
| 405 if (_shouldCallBack()) { | |
| 406 return _callback(arg1, arg2); | |
| 407 } | |
| 408 }, | |
| 409 _after); | |
| 350 } | 410 } |
| 351 | 411 |
| 352 /** Returns false if we exceded the number of expected calls. */ | 412 /** Returns false if we exceded the number of expected calls. */ |
| 353 bool _incrementCall() { | 413 bool _checkCallCount() { |
| 354 calls++; | 414 if (_calls > _expectedCalls) { |
| 355 if (calls > expectedCalls) { | 415 _testCase.error( |
| 356 testCase.error( | 416 'Callback called more times than expected ' |
| 357 'Callback called more times than expected ($calls > $expectedCalls)', | 417 '($_calls > $_expectedCalls)', |
| 358 ''); | 418 ''); |
| 359 _state = _UNCAUGHT_ERROR; | 419 _state = _UNCAUGHT_ERROR; |
| 360 return false; | 420 return false; |
| 361 } | 421 } |
| 362 return true; | 422 return true; |
| 363 } | 423 } |
| 364 } | 424 } |
| 365 | 425 |
| 366 /** | 426 /** |
| 367 * Indicate that [callback] is expected to be called a [count] number of times | 427 * Indicate that [callback] is expected to be called a [count] number of times |
| 368 * (by default 1). The unittest framework will wait for the callback to run the | 428 * (by default 1). The unittest framework will wait for the callback to run the |
| 369 * specified [count] times before it continues with the following test. Using | 429 * specified [count] times before it continues with the following test. Using |
| 370 * [_expectAsync] will also ensure that errors that occur within [callback] are | 430 * [_expectAsync] will also ensure that errors that occur within [callback] are |
| 371 * tracked and reported. [callback] should take between 0 and 4 positional | 431 * tracked and reported. [callback] should take between 0 and 4 positional |
| 372 * arguments (named arguments are not supported here). | 432 * arguments (named arguments are not supported here). |
| 373 */ | 433 */ |
| 374 Function _expectAsync(Function callback, [int count = 1]) { | 434 Function _expectAsync(Function callback, [int count = 1]) { |
| 375 return new _SpreadArgsHelper(callback, count).invoke; | 435 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke; |
| 376 } | 436 } |
| 377 | 437 |
| 378 /** | 438 /** |
| 379 * Indicate that [callback] is expected to be called a [count] number of times | 439 * Indicate that [callback] is expected to be called a [count] number of times |
| 380 * (by default 1). The unittest framework will wait for the callback to run the | 440 * (by default 1). The unittest framework will wait for the callback to run the |
| 381 * specified [count] times before it continues with the following test. Using | 441 * specified [count] times before it continues with the following test. Using |
| 382 * [expectAsync0] will also ensure that errors that occur within [callback] are | 442 * [expectAsync0] will also ensure that errors that occur within [callback] are |
| 383 * tracked and reported. [callback] should take 0 positional arguments (named | 443 * tracked and reported. [callback] should take 0 positional arguments (named |
| 384 * arguments are not supported). | 444 * arguments are not supported). |
| 385 */ | 445 */ |
| 386 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 446 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 387 Function expectAsync0(Function callback, [int count = 1]) { | 447 Function expectAsync0(Function callback, [int count = 1]) { |
| 388 return new _SpreadArgsHelper(callback, count).invoke0; | 448 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke0; |
| 389 } | 449 } |
| 390 | 450 |
| 391 /** Like [expectAsync0] but [callback] should take 1 positional argument. */ | 451 /** Like [expectAsync0] but [callback] should take 1 positional argument. */ |
| 392 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 452 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 393 Function expectAsync1(Function callback, [int count = 1]) { | 453 Function expectAsync1(Function callback, [int count = 1]) { |
| 394 return new _SpreadArgsHelper(callback, count).invoke1; | 454 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke1; |
| 395 } | 455 } |
| 396 | 456 |
| 397 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */ | 457 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */ |
| 398 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | 458 // TODO(sigmund): deprecate this API when issue 2706 is fixed. |
| 399 Function expectAsync2(Function callback, [int count = 1]) { | 459 Function expectAsync2(Function callback, [int count = 1]) { |
| 400 return new _SpreadArgsHelper(callback, count).invoke2; | 460 return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke2; |
| 461 } | |
| 462 | |
| 463 /** | |
| 464 * Indicate that [callback] is expected to be called until [isDone] returns | |
| 465 * true. The unittest framework checks [isDone] after each callback and only | |
| 466 * when it returns true will it continue with the following test. Using | |
| 467 * [expectAsyncUntil] will also ensure that errors that occur within | |
| 468 * [callback] are tracked and reported. [callback] should take between 0 and | |
| 469 * 4 positional arguments (named arguments are not supported). | |
| 470 */ | |
| 471 Function _expectAsyncUntil(Function callback, Function isDone) { | |
| 472 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke; | |
| 473 } | |
| 474 | |
| 475 /** | |
| 476 * Indicate that [callback] is expected to be called until [isDone] returns | |
| 477 * true. The unittest framework check [isDone] after each callback and only | |
| 478 * when it returns true will it continue with the following test. Using | |
| 479 * [expectAsyncUntil0] will also ensure that errors that occur within | |
| 480 * [callback] are tracked and reported. [callback] should take 0 positional | |
| 481 * arguments (named arguments are not supported). | |
| 482 */ | |
| 483 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | |
| 484 Function expectAsyncUntil0(Function callback, Function isDone) { | |
| 485 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke0; | |
| 486 } | |
| 487 | |
| 488 /** | |
| 489 * Like [expectAsyncUntil0] but [callback] should take 1 positional argument. | |
| 490 */ | |
| 491 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | |
| 492 Function expectAsyncUntil1(Function callback, Function isDone) { | |
| 493 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke1; | |
| 494 } | |
| 495 | |
| 496 /** | |
| 497 * Like [expectAsyncUntil0] but [callback] should take 2 positional arguments. | |
| 498 */ | |
| 499 // TODO(sigmund): deprecate this API when issue 2706 is fixed. | |
| 500 Function expectAsyncUntil2(Function callback, Function isDone) { | |
| 501 return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke2; | |
| 401 } | 502 } |
| 402 | 503 |
| 403 /** | 504 /** |
| 404 * Creates a new named group of tests. Calls to group() or test() within the | 505 * 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. | 506 * body of the function passed to this will inherit this group's description. |
| 406 */ | 507 */ |
| 407 void group(String description, void body()) { | 508 void group(String description, void body()) { |
| 408 ensureInitialized(); | 509 ensureInitialized(); |
| 409 | 510 |
| 410 // Concatenate the new group. | 511 // Concatenate the new group. |
| 411 final oldGroup = _currentGroup; | 512 final oldGroup = _currentGroup; |
| 412 if (_currentGroup != '') { | 513 if (_currentGroup != '') { |
| 413 // Add a space. | 514 // Add a space. |
| 414 _currentGroup = '$_currentGroup $description'; | 515 _currentGroup = '$_currentGroup $description'; |
| 415 } else { | 516 } else { |
| 416 // The first group. | 517 // The first group. |
| 417 _currentGroup = description; | 518 _currentGroup = description; |
| 418 } | 519 } |
| 419 | 520 |
| 420 try { | 521 try { |
| 421 body(); | 522 body(); |
| 422 } finally { | 523 } finally { |
| 423 // Now that the group is over, restore the previous one. | 524 // Now that the group is over, restore the previous one. |
| 424 _currentGroup = oldGroup; | 525 _currentGroup = oldGroup; |
| 425 } | 526 } |
| 426 } | 527 } |
| 427 | 528 |
| 428 /** Called by subclasses to indicate that an asynchronous test completed. */ | 529 /** Called by subclasses to indicate that an asynchronous test completed. */ |
| 429 void callbackDone() { | 530 void _handleAllCallbacksDone() { |
| 430 // TODO (gram): we defer this to give the nextBatch recursive | 531 // TODO (gram): we defer this to give the nextBatch recursive |
| 431 // stack a chance to unwind. This is a temporary hack but | 532 // stack a chance to unwind. This is a temporary hack but |
| 432 // really a bunch of code here needs to be fixed. We have a | 533 // really a bunch of code here needs to be fixed. We have a |
| 433 // single array that is being iterated through by nextBatch(), | 534 // single array that is being iterated through by nextBatch(), |
| 434 // which is recursively invoked in the case of async tests that | 535 // which is recursively invoked in the case of async tests that |
| 435 // run synchronously. Bad things can then happen. | 536 // run synchronously. Bad things can then happen. |
| 436 _defer(() { | 537 _defer(() { |
| 437 _callbacksCalled++; | 538 _callbacksCalled++; |
| 438 if (_currentTest < _tests.length) { | 539 if (_currentTest < _tests.length) { |
| 439 final testCase = _tests[_currentTest]; | 540 final testCase = _tests[_currentTest]; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 * Runs a batch of tests, yielding whenever an asynchronous test starts | 636 * Runs a batch of tests, yielding whenever an asynchronous test starts |
| 536 * running. Tests will resume executing when such asynchronous test calls | 637 * running. Tests will resume executing when such asynchronous test calls |
| 537 * [done] or if it fails with an exception. | 638 * [done] or if it fails with an exception. |
| 538 */ | 639 */ |
| 539 _nextBatch() { | 640 _nextBatch() { |
| 540 while (_currentTest < _tests.length) { | 641 while (_currentTest < _tests.length) { |
| 541 final testCase = _tests[_currentTest]; | 642 final testCase = _tests[_currentTest]; |
| 542 guardAsync(() { | 643 guardAsync(() { |
| 543 _callbacksCalled = 0; | 644 _callbacksCalled = 0; |
| 544 _state = _RUNNING_TEST; | 645 _state = _RUNNING_TEST; |
| 545 | |
| 546 testCase.test(); | 646 testCase.test(); |
| 547 | 647 |
| 548 if (_state != _UNCAUGHT_ERROR) { | 648 if (_state != _UNCAUGHT_ERROR) { |
| 549 if (testCase.callbacks == _callbacksCalled) { | 649 if (testCase.callbacks == _callbacksCalled) { |
| 550 testCase.pass(); | 650 testCase.pass(); |
| 551 } | 651 } |
| 552 } | 652 } |
| 553 }); | 653 }); |
| 554 | 654 |
| 555 if (!testCase.isComplete && testCase.callbacks > 0) return; | 655 if (!testCase.isComplete && testCase.callbacks > 0) return; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 throw new ExpectException(message); | 689 throw new ExpectException(message); |
| 590 } | 690 } |
| 591 | 691 |
| 592 /** | 692 /** |
| 593 * Lazily initializes the test library if not already initialized. | 693 * Lazily initializes the test library if not already initialized. |
| 594 */ | 694 */ |
| 595 ensureInitialized() { | 695 ensureInitialized() { |
| 596 if (_state != _UNINITIALIZED) return; | 696 if (_state != _UNINITIALIZED) return; |
| 597 | 697 |
| 598 _tests = <TestCase>[]; | 698 _tests = <TestCase>[]; |
| 699 _uncaughtErrorMessage = null; | |
| 700 _currentTest = 0; | |
| 599 _currentGroup = ''; | 701 _currentGroup = ''; |
| 600 _state = _READY; | 702 _state = _READY; |
| 601 _testRunner = _nextBatch; | 703 _testRunner = _nextBatch; |
| 602 | 704 |
| 603 if (_config == null) { | 705 if (_config == null) { |
| 604 _config = new Configuration(); | 706 _config = new Configuration(); |
| 605 } | 707 } |
| 606 _config.onInit(); | 708 _config.onInit(); |
| 607 | 709 |
| 608 // Immediately queue the suite up. It will run after a timeout (i.e. after | 710 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 609 // main() has returned). | 711 // main() has returned). |
| 610 _defer(_runTests); | 712 _defer(_runTests); |
| 611 } | 713 } |
| 612 | 714 |
| 613 /** Signature for a test function. */ | 715 /** Signature for a test function. */ |
| 614 typedef void TestFunction(); | 716 typedef void TestFunction(); |
| 717 | |
| OLD | NEW |