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