| 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 /** |
| 179 void expectThrow(function) { | 182 * Evaluates the [function] and validates that it throws an exception. If |
| 183 * [callback] is provided, then it will be invoked with the thrown exception. |
| 184 * The callback may do any validation it wants. In addition, if it returns |
| 185 * `false`, that also indicates an expectation failure. |
| 186 */ |
| 187 void expectThrow(function, [bool callback(exception)]) { |
| 180 bool threw = false; | 188 bool threw = false; |
| 181 try { | 189 try { |
| 182 function(); | 190 function(); |
| 183 } catch (var e) { | 191 } catch (var e) { |
| 184 threw = true; | 192 threw = true; |
| 193 |
| 194 // Also let the callback look at it. |
| 195 if (callback != null) { |
| 196 var result = callback(e); |
| 197 |
| 198 // If the callback explicitly returned false, treat that like an |
| 199 // expectation too. (If it returns null, though, don't.) |
| 200 if (result == false) { |
| 201 _fail('Exception:\n$e\ndid not match expectation.'); |
| 202 } |
| 203 } |
| 185 } | 204 } |
| 186 Expect.equals(true, threw, 'Expected exception but none was thrown.'); | 205 |
| 206 if (threw != true) _fail('An expected exception was not thrown.'); |
| 187 } | 207 } |
| 188 | 208 |
| 189 /** | 209 /** |
| 190 * Creates a new test case with the given description and body. The | 210 * Creates a new test case with the given description and body. The |
| 191 * description will include the descriptions of any surrounding group() | 211 * description will include the descriptions of any surrounding group() |
| 192 * calls. | 212 * calls. |
| 193 */ | 213 */ |
| 194 void test(String spec, TestFunction body) { | 214 void test(String spec, TestFunction body) { |
| 195 ensureInitialized(); | 215 ensureInitialized(); |
| 196 | 216 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 209 final testCase = new TestCase( | 229 final testCase = new TestCase( |
| 210 _tests.length + 1, _fullSpec(spec), body, callbacks); | 230 _tests.length + 1, _fullSpec(spec), body, callbacks); |
| 211 _tests.add(testCase); | 231 _tests.add(testCase); |
| 212 | 232 |
| 213 if (callbacks < 1) { | 233 if (callbacks < 1) { |
| 214 testCase.error( | 234 testCase.error( |
| 215 'Async tests must wait for at least one callback ', ''); | 235 'Async tests must wait for at least one callback ', ''); |
| 216 } | 236 } |
| 217 } | 237 } |
| 218 | 238 |
| 239 /** |
| 240 * Creates a new test case with the given description and body. The |
| 241 * description will include the descriptions of any surrounding group() |
| 242 * calls. |
| 243 * |
| 244 * "solo_" means that this will be the only test that is run. All other tests |
| 245 * will be skipped. This is a convenience function to let you quickly isolate |
| 246 * a single test by adding "solo_" before it to temporarily disable all other |
| 247 * tests. |
| 248 */ |
| 249 void solo_test(String spec, TestFunction body) { |
| 250 // TODO(rnystrom): Support multiple solos. If more than one test is solo-ed, |
| 251 // all of the solo-ed tests and none of the non-solo-ed ones should run. |
| 252 if (_soloTest != null) { |
| 253 throw new Exception('Only one test can be soloed right now.'); |
| 254 } |
| 255 |
| 256 ensureInitialized(); |
| 257 |
| 258 _soloTest = new TestCase(_tests.length + 1, _fullSpec(spec), body, 0); |
| 259 _tests.add(_soloTest); |
| 260 } |
| 261 |
| 219 /** Sentinel value for [_SpreadArgsHelper]. */ | 262 /** Sentinel value for [_SpreadArgsHelper]. */ |
| 220 class _Sentinel { | 263 class _Sentinel { |
| 221 const _Sentinel(); | 264 const _Sentinel(); |
| 222 } | 265 } |
| 223 | 266 |
| 224 // TODO(sigmund): make a singleton const field when frog supports passing those | 267 // TODO(sigmund): make a singleton const field when frog supports passing those |
| 225 // as default values to named arguments. | 268 // as default values to named arguments. |
| 226 final _sentinel = const _Sentinel(); | 269 final _sentinel = const _Sentinel(); |
| 227 | 270 |
| 228 /** Simulates spread arguments using named arguments. */ | 271 /** Simulates spread arguments using named arguments. */ |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 final port = new ReceivePort(); | 444 final port = new ReceivePort(); |
| 402 port.receive((msg, reply) { | 445 port.receive((msg, reply) { |
| 403 callback(); | 446 callback(); |
| 404 port.close(); | 447 port.close(); |
| 405 }); | 448 }); |
| 406 port.toSendPort().send(null, null); | 449 port.toSendPort().send(null, null); |
| 407 } | 450 } |
| 408 | 451 |
| 409 /** Runs all queued tests, one at a time. */ | 452 /** Runs all queued tests, one at a time. */ |
| 410 _runTests() { | 453 _runTests() { |
| 454 // If we are soloing a test, remove all the others. |
| 455 if (_soloTest != null) { |
| 456 _tests = _tests.filter((t) => t == _soloTest); |
| 457 } |
| 458 |
| 411 _config.onStart(); | 459 _config.onStart(); |
| 412 | 460 |
| 413 _defer(() { | 461 _defer(() { |
| 414 assert (_currentTest == 0); | 462 assert (_currentTest == 0); |
| 415 _testRunner(); | 463 _testRunner(); |
| 416 }); | 464 }); |
| 417 } | 465 } |
| 418 | 466 |
| 419 /** | 467 /** |
| 420 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update | 468 * Run [tryBody] guarded in a try-catch block. If an exception is thrown, update |
| 421 * the [_currentTest] status accordingly. | 469 * the [_currentTest] status accordingly. |
| 422 */ | 470 */ |
| 423 _guard(tryBody, [finallyBody]) { | 471 _guard(tryBody, [finallyBody]) { |
| 424 try { | 472 try { |
| 425 return tryBody(); | 473 return tryBody(); |
| 426 } catch (ExpectException e, var trace) { | 474 } catch (ExpectException e, var trace) { |
| 427 if (_state != _UNCAUGHT_ERROR) { | 475 if (_state != _UNCAUGHT_ERROR) { |
| 428 _tests[_currentTest].fail(e.message, | 476 _tests[_currentTest].fail(e.message, |
| 429 trace == null ? '' : trace.toString()); | 477 trace == null ? '' : trace.toString()); |
| 430 } | 478 } |
| 431 } catch (var e, var trace) { | 479 } catch (var e, var trace) { |
| 432 if (_state != _UNCAUGHT_ERROR) { | 480 if (_state == _RUNNING_TEST) { |
| 481 // If a random exception is thrown from within a test, we consider that |
| 482 // a test failure too. A test case implicitly has an expectation that it |
| 483 // will run to completion without an uncaught exception being thrown. |
| 484 _tests[_currentTest].fail('Caught $e', |
| 485 trace == null ? '' : trace.toString()); |
| 486 } else if (_state != _UNCAUGHT_ERROR) { |
| 433 _tests[_currentTest].error('Caught $e', | 487 _tests[_currentTest].error('Caught $e', |
| 434 trace == null ? '' : trace.toString()); | 488 trace == null ? '' : trace.toString()); |
| 435 } | 489 } |
| 436 } finally { | 490 } finally { |
| 437 _state = _READY; | 491 _state = _READY; |
| 438 if (finallyBody != null) finallyBody(); | 492 if (finallyBody != null) finallyBody(); |
| 439 } | 493 } |
| 440 } | 494 } |
| 441 | 495 |
| 442 /** | 496 /** |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 | 540 |
| 487 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests, | 541 _config.onDone(testsPassed_, testsFailed_, testsErrors_, _tests, |
| 488 _uncaughtErrorMessage); | 542 _uncaughtErrorMessage); |
| 489 } | 543 } |
| 490 | 544 |
| 491 String _fullSpec(String spec) { | 545 String _fullSpec(String spec) { |
| 492 if (spec === null) return '$_currentGroup'; | 546 if (spec === null) return '$_currentGroup'; |
| 493 return _currentGroup != '' ? '$_currentGroup $spec' : spec; | 547 return _currentGroup != '' ? '$_currentGroup $spec' : spec; |
| 494 } | 548 } |
| 495 | 549 |
| 550 void _fail(String message) { |
| 551 throw new ExpectException(message); |
| 552 } |
| 553 |
| 496 /** | 554 /** |
| 497 * Lazily initializes the test library if not already initialized. | 555 * Lazily initializes the test library if not already initialized. |
| 498 */ | 556 */ |
| 499 ensureInitialized() { | 557 ensureInitialized() { |
| 500 if (_state != _UNINITIALIZED) return; | 558 if (_state != _UNINITIALIZED) return; |
| 501 | 559 |
| 502 _tests = <TestCase>[]; | 560 _tests = <TestCase>[]; |
| 503 _currentGroup = ''; | 561 _currentGroup = ''; |
| 504 _state = _READY; | 562 _state = _READY; |
| 505 _testRunner = _nextBatch; | 563 _testRunner = _nextBatch; |
| 506 | 564 |
| 507 if (_config == null) { | 565 if (_config == null) { |
| 508 _config = new Configuration(); | 566 _config = new Configuration(); |
| 509 } | 567 } |
| 510 _config.onInit(); | 568 _config.onInit(); |
| 511 | 569 |
| 512 // Immediately queue the suite up. It will run after a timeout (i.e. after | 570 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 513 // main() has returned). | 571 // main() has returned). |
| 514 _defer(_runTests); | 572 _defer(_runTests); |
| 515 } | 573 } |
| 516 | 574 |
| 517 /** Signature for a test function. */ | 575 /** Signature for a test function. */ |
| 518 typedef void TestFunction(); | 576 typedef void TestFunction(); |
| OLD | NEW |