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 * ##Concepts## | 8 * ##Concepts## |
| 9 * | 9 * |
| 10 * * Tests: Tests are specified via the top-level function [test], they can be | 10 * * Tests: Tests are specified via the top-level function [test], they can be |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 */ | 165 */ |
| 166 final _UNCAUGHT_ERROR = 3; | 166 final _UNCAUGHT_ERROR = 3; |
| 167 | 167 |
| 168 int _state = _UNINITIALIZED; | 168 int _state = _UNINITIALIZED; |
| 169 String _uncaughtErrorMessage = null; | 169 String _uncaughtErrorMessage = null; |
| 170 | 170 |
| 171 final _PASS = 'pass'; | 171 final _PASS = 'pass'; |
| 172 final _FAIL = 'fail'; | 172 final _FAIL = 'fail'; |
| 173 final _ERROR = 'error'; | 173 final _ERROR = 'error'; |
| 174 | 174 |
| 175 /** If set, then all other test cases will be ignored. */ | |
| 176 TestCase _soloTest; | |
| 177 | |
| 175 /** Creates an expectation for the given value. */ | 178 /** Creates an expectation for the given value. */ |
| 176 Expectation expect(value) => new Expectation(value); | 179 Expectation expect(value) => new Expectation(value); |
| 177 | 180 |
| 178 /** Evaluates the given function and validates that it throws an exception. */ | 181 /** Evaluates the given function and validates that it throws an exception. */ |
| 179 void expectThrow(function) { | 182 void expectThrow(function, [bool callback(exception)]) { |
|
Siggi Cherem (dart-lang)
2012/05/02 22:07:43
please add some comments on what is the expected u
Bob Nystrom
2012/05/03 00:23:40
Done. The idea is that you can do either or both.
| |
| 180 bool threw = false; | 183 bool threw = false; |
| 181 try { | 184 try { |
| 182 function(); | 185 function(); |
| 183 } catch (var e) { | 186 } catch (var e) { |
| 184 threw = true; | 187 threw = true; |
| 188 | |
| 189 // Also let the callback look at it. | |
| 190 if (callback != null) { | |
| 191 var result = callback(e); | |
| 192 | |
| 193 // If the callback explicitly returned false, treat that like an | |
| 194 // expectation too. (If it returns null, though, don't.) | |
| 195 if (result == false) { | |
| 196 _fail('Exception:\n$e\ndid not match expectation.'); | |
| 197 } | |
| 198 } | |
| 185 } | 199 } |
| 186 Expect.equals(true, threw, 'Expected exception but none was thrown.'); | 200 |
| 201 if (threw != true) _fail('An expected exception was not thrown.'); | |
|
Siggi Cherem (dart-lang)
2012/05/02 22:07:43
why not Expect.isTrue(message...)?
Bob Nystrom
2012/05/03 00:23:40
Expect.isTrue does a bunch of nasty formatting on
| |
| 187 } | 202 } |
| 188 | 203 |
| 189 /** | 204 /** |
| 190 * Creates a new test case with the given description and body. The | 205 * Creates a new test case with the given description and body. The |
| 191 * description will include the descriptions of any surrounding group() | 206 * description will include the descriptions of any surrounding group() |
| 192 * calls. | 207 * calls. |
| 193 */ | 208 */ |
| 194 void test(String spec, TestFunction body) { | 209 void test(String spec, TestFunction body) { |
| 195 ensureInitialized(); | 210 ensureInitialized(); |
| 196 | 211 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 209 final testCase = new TestCase( | 224 final testCase = new TestCase( |
| 210 _tests.length + 1, _fullSpec(spec), body, callbacks); | 225 _tests.length + 1, _fullSpec(spec), body, callbacks); |
| 211 _tests.add(testCase); | 226 _tests.add(testCase); |
| 212 | 227 |
| 213 if (callbacks < 1) { | 228 if (callbacks < 1) { |
| 214 testCase.error( | 229 testCase.error( |
| 215 'Async tests must wait for at least one callback ', ''); | 230 'Async tests must wait for at least one callback ', ''); |
| 216 } | 231 } |
| 217 } | 232 } |
| 218 | 233 |
| 234 /** | |
| 235 * Creates a new test case with the given description and body. The | |
| 236 * description will include the descriptions of any surrounding group() | |
| 237 * calls. | |
| 238 * | |
| 239 * "solo_" means that this will be the only test that is run. All other tests | |
| 240 * will be skipped. This is a convenience function to let you quickly isolate | |
| 241 * a single test by adding "solo_" before it to temporarily disable all other | |
| 242 * tests. | |
|
Siggi Cherem (dart-lang)
2012/05/02 22:07:43
maybe mention what happens if you have 2 solo_ tes
Bob Nystrom
2012/05/03 00:23:40
What should happen is that all soloed tests would
| |
| 243 */ | |
| 244 void solo_test(String spec, TestFunction body) { | |
| 245 ensureInitialized(); | |
| 246 | |
| 247 _soloTest = new TestCase(_tests.length + 1, _fullSpec(spec), body, 0); | |
| 248 _tests.add(_soloTest); | |
| 249 } | |
| 250 | |
| 219 /** Sentinel value for [_SpreadArgsHelper]. */ | 251 /** Sentinel value for [_SpreadArgsHelper]. */ |
| 220 class _Sentinel { | 252 class _Sentinel { |
| 221 const _Sentinel(); | 253 const _Sentinel(); |
| 222 } | 254 } |
| 223 | 255 |
| 224 // TODO(sigmund): make a singleton const field when frog supports passing those | 256 // TODO(sigmund): make a singleton const field when frog supports passing those |
| 225 // as default values to named arguments. | 257 // as default values to named arguments. |
| 226 final _sentinel = const _Sentinel(); | 258 final _sentinel = const _Sentinel(); |
| 227 | 259 |
| 228 /** Simulates spread arguments using named arguments. */ | 260 /** Simulates spread arguments using named arguments. */ |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 final port = new ReceivePort(); | 433 final port = new ReceivePort(); |
| 402 port.receive((msg, reply) { | 434 port.receive((msg, reply) { |
| 403 callback(); | 435 callback(); |
| 404 port.close(); | 436 port.close(); |
| 405 }); | 437 }); |
| 406 port.toSendPort().send(null, null); | 438 port.toSendPort().send(null, null); |
| 407 } | 439 } |
| 408 | 440 |
| 409 /** Runs all queued tests, one at a time. */ | 441 /** Runs all queued tests, one at a time. */ |
| 410 _runTests() { | 442 _runTests() { |
| 443 // If we are soloing a test, remove all the others. | |
| 444 if (_soloTest != null) { | |
| 445 _tests = _tests.filter((t) => t == _soloTest); | |
| 446 } | |
| 447 | |
| 411 _config.onStart(); | 448 _config.onStart(); |
| 412 | 449 |
| 413 _defer(() { | 450 _defer(() { |
| 414 assert (_currentTest == 0); | 451 assert (_currentTest == 0); |
| 415 _testRunner(); | 452 _testRunner(); |
| 416 }); | 453 }); |
| 417 } | 454 } |
| 418 | 455 |
| 419 /** | 456 /** |
| 420 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update | 457 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update |
| 421 * the [_currentTest] status accordingly. | 458 * the [_currentTest] status accordingly. |
| 422 */ | 459 */ |
| 423 _guard(tryBody, [finallyBody]) { | 460 _guard(tryBody, [finallyBody]) { |
| 424 try { | 461 try { |
| 425 return tryBody(); | 462 return tryBody(); |
| 426 } catch (ExpectException e, var trace) { | 463 } catch (ExpectException e, var trace) { |
| 427 if (_state != _UNCAUGHT_ERROR) { | 464 if (_state != _UNCAUGHT_ERROR) { |
| 428 _tests[_currentTest].fail(e.message, | 465 _tests[_currentTest].fail(e.message, |
| 429 trace == null ? '' : trace.toString()); | 466 trace == null ? '' : trace.toString()); |
| 430 } | 467 } |
| 431 } catch (var e, var trace) { | 468 } catch (var e, var trace) { |
| 432 if (_state != _UNCAUGHT_ERROR) { | 469 if (_state == _RUNNING_TEST) { |
| 470 // If a random exception is thrown from within a test, we consider that | |
| 471 // a test failure too. A test case implicitly has an expectation that it | |
| 472 // will run to completion without an uncaught exception being thrown. | |
| 473 _tests[_currentTest].fail('Caught $e', | |
| 474 trace == null ? '' : trace.toString()); | |
| 475 } else if (_state != _UNCAUGHT_ERROR) { | |
| 433 _tests[_currentTest].error('Caught $e', | 476 _tests[_currentTest].error('Caught $e', |
| 434 trace == null ? '' : trace.toString()); | 477 trace == null ? '' : trace.toString()); |
| 435 } | 478 } |
| 436 } finally { | 479 } finally { |
| 437 _state = _READY; | 480 _state = _READY; |
| 438 if (finallyBody != null) finallyBody(); | 481 if (finallyBody != null) finallyBody(); |
| 439 } | 482 } |
| 440 } | 483 } |
| 441 | 484 |
| 442 /** | 485 /** |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 486 | 529 |
| 487 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests, | 530 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests, |
| 488 _uncaughtErrorMessage); | 531 _uncaughtErrorMessage); |
| 489 } | 532 } |
| 490 | 533 |
| 491 String _fullSpec(String spec) { | 534 String _fullSpec(String spec) { |
| 492 if (spec === null) return '$_currentGroup'; | 535 if (spec === null) return '$_currentGroup'; |
| 493 return _currentGroup != '' ? '$_currentGroup $spec' : spec; | 536 return _currentGroup != '' ? '$_currentGroup $spec' : spec; |
| 494 } | 537 } |
| 495 | 538 |
| 539 void _fail(String message) { | |
|
Siggi Cherem (dart-lang)
2012/05/02 22:07:43
why not use Expect.fail(message) ?
Bob Nystrom
2012/05/03 00:23:40
See above comment.
| |
| 540 throw new ExpectException(message); | |
| 541 } | |
| 542 | |
| 496 /** | 543 /** |
| 497 * Lazily initializes the test library if not already initialized. | 544 * Lazily initializes the test library if not already initialized. |
| 498 */ | 545 */ |
| 499 ensureInitialized() { | 546 ensureInitialized() { |
| 500 if (_state != _UNINITIALIZED) return; | 547 if (_state != _UNINITIALIZED) return; |
| 501 | 548 |
| 502 _tests = <TestCase>[]; | 549 _tests = <TestCase>[]; |
| 503 _currentGroup = ''; | 550 _currentGroup = ''; |
| 504 _state = _READY; | 551 _state = _READY; |
| 505 _testRunner = _nextBatch; | 552 _testRunner = _nextBatch; |
| 506 | 553 |
| 507 if (_config == null) { | 554 if (_config == null) { |
| 508 _config = new Configuration(); | 555 _config = new Configuration(); |
| 509 } | 556 } |
| 510 _config.onInit(); | 557 _config.onInit(); |
| 511 | 558 |
| 512 // Immediately queue the suite up. It will run after a timeout (i.e. after | 559 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 513 // main() has returned). | 560 // main() has returned). |
| 514 _defer(_runTests); | 561 _defer(_runTests); |
| 515 } | 562 } |
| 516 | 563 |
| 517 /** Signature for a test function. */ | 564 /** Signature for a test function. */ |
| 518 typedef void TestFunction(); | 565 typedef void TestFunction(); |
| OLD | NEW |