Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: lib/unittest/unittest.dart

Issue 10441104: New expectation functions plus convert old tests to use these. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 *
11 * ##Concepts## 11 * ##Concepts##
Siggi Cherem (dart-lang) 2012/06/06 00:26:08 could you add another item introducing 'Matchers:
gram 2012/06/06 16:23:56 Done.
12 * 12 *
13 * * Tests: Tests are specified via the top-level function [test], they can be 13 * * Tests: Tests are specified via the top-level function [test], they can be
14 * organized together using [group]. 14 * organized together using [group].
15 * * Checks: Test expectations can be specified via [expect] (see methods in 15 * * Checks: Test expectations can be specified via [expect]
16 * [Expectation]), [expectThrow], or using assertions with the [Expect]
17 * class.
18 * * Configuration: The framework can be adapted by calling [configure] with a 16 * * Configuration: The framework can be adapted by calling [configure] with a
19 * [Configuration]. Common configurations can be found in this package 17 * [Configuration]. Common configurations can be found in this package
20 * under: 'dom\_config.dart', 'html\_config.dart', and 'vm\_config.dart'. 18 * under: 'dom\_config.dart' (deprecated), 'html\_config.dart' (for running
19 * tests compiled to Javascript in a browser), and 'vm\_config.dart' (for
20 * running native Dart tests on the VM).
21 * 21 *
22 * ##Examples## 22 * ##Examples##
23 * 23 *
24 * A trivial test: 24 * A trivial test:
25 * 25 *
26 * #import('path-to-dart/lib/unittest/unitest.dart'); 26 * #import('path-to-dart/lib/unittest/unitest.dart');
27 * main() { 27 * main() {
28 * test('this is a test', () { 28 * test('this is a test', () {
29 * int x = 2 + 3; 29 * int x = 2 + 3;
30 * expect(x).equals(5); 30 * expect(x, equals(5));
31 * }); 31 * });
32 * } 32 * }
33 * 33 *
34 * Multiple tests: 34 * Multiple tests:
35 * 35 *
36 * #import('path-to-dart/lib/unittest/unitest.dart'); 36 * #import('path-to-dart/lib/unittest/unitest.dart');
37 * main() { 37 * main() {
38 * test('this is a test', () { 38 * test('this is a test', () {
39 * int x = 2 + 3; 39 * int x = 2 + 3;
40 * expect(x).equals(5); 40 * expect(x, equals(5));
41 * }); 41 * });
42 * test('this is another test', () { 42 * test('this is another test', () {
43 * int x = 2 + 3; 43 * int x = 2 + 3;
44 * expect(x).equals(5); 44 * expect(x, equals(5));
45 * }); 45 * });
46 * } 46 * }
47 * 47 *
48 * Multiple tests, grouped by category: 48 * Multiple tests, grouped by category:
49 * 49 *
50 * #import('path-to-dart/lib/unittest/unitest.dart'); 50 * #import('path-to-dart/lib/unittest/unitest.dart');
51 * main() { 51 * main() {
52 * group('group A', () { 52 * group('group A', () {
53 * test('test A.1', () { 53 * test('test A.1', () {
54 * int x = 2 + 3; 54 * int x = 2 + 3;
55 * expect(x).equals(5); 55 * expect(x, equals(5));
56 * }); 56 * });
57 * test('test A.2', () { 57 * test('test A.2', () {
58 * int x = 2 + 3; 58 * int x = 2 + 3;
59 * expect(x).equals(5); 59 * expect(x, equals(5));
60 * }); 60 * });
61 * }); 61 * });
62 * group('group B', () { 62 * group('group B', () {
63 * test('this B.1', () { 63 * test('this B.1', () {
64 * int x = 2 + 3; 64 * int x = 2 + 3;
65 * expect(x).equals(5); 65 * expect(x, equals(5));
66 * }); 66 * });
67 * }); 67 * });
68 * } 68 * }
69 * 69 *
70 * Asynchronous tests: if callbacks expect between 0 and 2 positional arguments. 70 * Asynchronous tests: if callbacks expect between 0 and 2 positional arguments,
71 * depending on the suffix of expectAsyncX(). expectAsyncX() will wrap a
72 * function into a new callback and will not consider the test complete until
73 * that callback is run. A count argument can be provided to specify the number
74 * of times the callback should be called (the default is 1).
71 * 75 *
72 * #import('path-to-dart/lib/unittest/unitest.dart'); 76 * #import('path-to-dart/lib/unittest/unitest.dart');
73 * #import('dart:dom_deprecated'); 77 * #import('dart:dom_deprecated');
74 * main() { 78 * main() {
75 * test('calllback is executed once', () { 79 * test('calllback is executed once', () {
76 * // wrap the callback of an asynchronous call with [expectAsync0] if 80 * // wrap the callback of an asynchronous call with [expectAsync0] if
77 * // the callback takes 0 arguments... 81 * // the callback takes 0 arguments...
78 * window.setTimeout(expectAsync0(() { 82 * window.setTimeout(expectAsync0(() {
79 * int x = 2 + 3; 83 * int x = 2 + 3;
80 * expect(x).equals(5); 84 * expect(x, equals(5));
81 * }), 0); 85 * }), 0);
82 * }); 86 * });
83 * 87 *
84 * test('calllback is executed twice', () { 88 * test('calllback is executed twice', () {
85 * var callback = expectAsync0(() { 89 * var callback = expectAsync0(() {
86 * int x = 2 + 3; 90 * int x = 2 + 3;
87 * expect(x).equals(5); 91 * expect(x, equals(5));
88 * }, count: 2); // <-- we can indicate multiplicity to [expectAsync0] 92 * }, count: 2); // <-- we can indicate multiplicity to [expectAsync0]
89 * window.setTimeout(callback, 0); 93 * window.setTimeout(callback, 0);
90 * window.setTimeout(callback, 0); 94 * window.setTimeout(callback, 0);
91 * }); 95 * });
92 * } 96 * }
93 * 97 *
98 * expectAsyncX() will wrap the callback code in a try/catch handler to handle
99 * exceptions (treated as test failures). There may be times when the number of
100 * times a callback should be called is non-deterministic. In this case a dummy
101 * callback can be created with expectAsync0((){}) and this can be called from
102 * the real callback when it is finally complete. In this case the body of the
103 * callback should be protected within a call to guardAsync(); this will ensure
104 * that exceptions are properly handled.
105 *
94 * Note: due to some language limitations we have to use different functions 106 * Note: due to some language limitations we have to use different functions
95 * depending on the number of positional arguments of the callback. In the 107 * depending on the number of positional arguments of the callback. In the
96 * future, we plan to expose a single `expectAsync` function that can be used 108 * future, we plan to expose a single `expectAsync` function that can be used
97 * regardless of the number of positional arguments. This requires new langauge 109 * regardless of the number of positional arguments. This requires new langauge
98 * features or fixes to the current spec (e.g. see 110 * features or fixes to the current spec (e.g. see
99 * [Issue 2706](http://dartbug.com/2706)). 111 * [Issue 2706](http://dartbug.com/2706)).
100 * 112 *
101 * Meanwhile, we plan to add this alternative API for callbacks of more than 2 113 * Meanwhile, we plan to add this alternative API for callbacks of more than 2
102 * arguments or that take named parameters. (this is not implemented yet, 114 * arguments or that take named parameters. (this is not implemented yet,
103 * but will be coming here soon). 115 * but will be coming here soon).
104 * 116 *
105 * #import('path-to-dart/lib/unittest/unitest.dart'); 117 * #import('path-to-dart/lib/unittest/unitest.dart');
106 * #import('dart:dom_deprecated'); 118 * #import('dart:dom_deprecated');
107 * main() { 119 * main() {
108 * test('calllback is executed', () { 120 * test('calllback is executed', () {
109 * // indicate ahead of time that an async callback is expected. 121 * // indicate ahead of time that an async callback is expected.
110 * var async = startAsync(); 122 * var async = startAsync();
111 * window.setTimeout(() { 123 * window.setTimeout(() {
112 * // Guard the body of the callback, so errors are propagated 124 * // Guard the body of the callback, so errors are propagated
113 * // correctly 125 * // correctly
114 * guardAsync(() { 126 * guardAsync(() {
115 * int x = 2 + 3; 127 * int x = 2 + 3;
116 * expect(x).equals(5); 128 * expect(x, equals(5));
117 * }); 129 * });
118 * // indicate that the asynchronous callback was invoked. 130 * // indicate that the asynchronous callback was invoked.
119 * async.complete(); 131 * async.complete();
120 * }), 0); 132 * }), 0);
121 * }); 133 * });
122 * 134 *
123 */ 135 */
124 #library('unittest'); 136 #library('unittest');
125 137
126 #import('dart:isolate'); 138 #import('dart:isolate');
127 139
140 #source('collection_matchers.dart');
128 #source('config.dart'); 141 #source('config.dart');
129 #source('expectation.dart'); 142 #source('core_matchers.dart');
143 #source('description.dart');
144 #source('expect.dart');
145 #source('interfaces.dart');
146 #source('map_matchers.dart');
147 #source('matcher.dart');
148 #source('numeric_matchers.dart');
149 #source('operator_matchers.dart');
150 #source('string_matchers.dart');
130 #source('test_case.dart'); 151 #source('test_case.dart');
131 152
132 /** [Configuration] used by the unittest library. */ 153 /** [Configuration] used by the unittest library. */
133 Configuration _config = null; 154 Configuration _config = null;
134 155
135 /** Set the [Configuration] used by the unittest library. */ 156 /** Set the [Configuration] used by the unittest library. */
136 void configure(Configuration config) { 157 void configure(Configuration config) {
137 _config = config; 158 _config = config;
138 } 159 }
139 160
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 int _state = _UNINITIALIZED; 193 int _state = _UNINITIALIZED;
173 String _uncaughtErrorMessage = null; 194 String _uncaughtErrorMessage = null;
174 195
175 final _PASS = 'pass'; 196 final _PASS = 'pass';
176 final _FAIL = 'fail'; 197 final _FAIL = 'fail';
177 final _ERROR = 'error'; 198 final _ERROR = 'error';
178 199
179 /** If set, then all other test cases will be ignored. */ 200 /** If set, then all other test cases will be ignored. */
180 TestCase _soloTest; 201 TestCase _soloTest;
181 202
182 /** Creates an expectation for the given value. */
183 Expectation expect(value) => new Expectation(value);
184
185 /** 203 /**
186 * Evaluates the [function] and validates that it throws an exception. If 204 * (Deprecated) Evaluates the [function] and validates that it throws an
187 * [callback] is provided, then it will be invoked with the thrown exception. 205 * exception. If [callback] is provided, then it will be invoked with the
188 * The callback may do any validation it wants. In addition, if it returns 206 * thrown exception. The callback may do any validation it wants. In addition,
189 * `false`, that also indicates an expectation failure. 207 * if it returns `false`, that also indicates an expectation failure.
190 */ 208 */
191 void expectThrow(function, [bool callback(exception)]) { 209 void expectThrow(function, [bool callback(exception)]) {
192 bool threw = false; 210 bool threw = false;
193 try { 211 try {
194 function(); 212 function();
195 } catch (var e) { 213 } catch (var e) {
196 threw = true; 214 threw = true;
197 215
198 // Also let the callback look at it. 216 // Also let the callback look at it.
199 if (callback != null) { 217 if (callback != null) {
(...skipping 15 matching lines...) Expand all
215 * description will include the descriptions of any surrounding group() 233 * description will include the descriptions of any surrounding group()
216 * calls. 234 * calls.
217 */ 235 */
218 void test(String spec, TestFunction body) { 236 void test(String spec, TestFunction body) {
219 ensureInitialized(); 237 ensureInitialized();
220 238
221 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0)); 239 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0));
222 } 240 }
223 241
224 /** 242 /**
225 * Creates a new async test case with the given description and body. The 243 * (Deprecated) Creates a new async test case with the given description
226 * description will include the descriptions of any surrounding group() 244 * and body. The description will include the descriptions of any surrounding
227 * calls. 245 * group() calls.
228 */ 246 */
229 // TODO(sigmund): deprecate this API 247 // TODO(sigmund): deprecate this API
230 void asyncTest(String spec, int callbacks, TestFunction body) { 248 void asyncTest(String spec, int callbacks, TestFunction body) {
231 ensureInitialized(); 249 ensureInitialized();
232 250
233 final testCase = new TestCase( 251 final testCase = new TestCase(
234 _tests.length + 1, _fullSpec(spec), body, callbacks); 252 _tests.length + 1, _fullSpec(spec), body, callbacks);
235 _tests.add(testCase); 253 _tests.add(testCase);
236 254
237 if (callbacks < 1) { 255 if (callbacks < 1) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 return guardAsync( 345 return guardAsync(
328 () => _incrementCall() ? callback(arg1, arg2) : null, 346 () => _incrementCall() ? callback(arg1, arg2) : null,
329 () { if (calls == expectedCalls) callbackDone(); }); 347 () { if (calls == expectedCalls) callbackDone(); });
330 } 348 }
331 349
332 /** Returns false if we exceded the number of expected calls. */ 350 /** Returns false if we exceded the number of expected calls. */
333 bool _incrementCall() { 351 bool _incrementCall() {
334 calls++; 352 calls++;
335 if (calls > expectedCalls) { 353 if (calls > expectedCalls) {
336 testCase.error( 354 testCase.error(
337 'Callback called more times than expected ($expectedCalls)', 355 'Callback called more times than expected ($calls > $expectedCalls)',
338 ''); 356 '');
339 _state = _UNCAUGHT_ERROR; 357 _state = _UNCAUGHT_ERROR;
340 return false; 358 return false;
341 } 359 }
342 return true; 360 return true;
343 } 361 }
344 } 362 }
345 363
346 /** 364 /**
347 * Indicate that [callback] is expected to be called a [count] number of times 365 * Indicate that [callback] is expected to be called a [count] number of times
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 body(); 419 body();
402 } finally { 420 } finally {
403 // Now that the group is over, restore the previous one. 421 // Now that the group is over, restore the previous one.
404 _currentGroup = oldGroup; 422 _currentGroup = oldGroup;
405 } 423 }
406 } 424 }
407 425
408 /** Called by subclasses to indicate that an asynchronous test completed. */ 426 /** Called by subclasses to indicate that an asynchronous test completed. */
409 void callbackDone() { 427 void callbackDone() {
410 // TODO (gram): we defer this to give the nextBatch recursive 428 // TODO (gram): we defer this to give the nextBatch recursive
411 // stack a chance to unwind. This is a temporary hack but 429 // stack a chance to unwind. This is a temporary hack but
412 // really a bunch of code here needs to be fixed. We have a 430 // really a bunch of code here needs to be fixed. We have a
413 // single array that is being iterated through by nextBatch(), 431 // single array that is being iterated through by nextBatch(),
414 // which is recursively invoked in the case of async tests that 432 // which is recursively invoked in the case of async tests that
415 // run synchronously. Bad things can then happen. 433 // run synchronously. Bad things can then happen.
416 _defer(() { 434 _defer(() {
417 _callbacksCalled++; 435 _callbacksCalled++;
418 if (_currentTest < _tests.length) { 436 if (_currentTest < _tests.length) {
419 final testCase = _tests[_currentTest]; 437 final testCase = _tests[_currentTest];
420 if (_callbacksCalled > testCase.callbacks) { 438 if (_callbacksCalled > testCase.callbacks) {
421 final expected = testCase.callbacks; 439 final expected = testCase.callbacks;
422 testCase.error( 440 testCase.error(
423 'More calls to callbackDone() than expected. ' 441 'More calls to callbackDone() than expected. '
424 'Actual: ${_callbacksCalled}, expected: ${expected}', ''); 442 'Actual: ${_callbacksCalled}, expected: ${expected}', '');
425 _state = _UNCAUGHT_ERROR; 443 _state = _UNCAUGHT_ERROR;
426 } else if ((_callbacksCalled == testCase.callbacks) && 444 } else if ((_callbacksCalled == testCase.callbacks) &&
427 (_state != _RUNNING_TEST)) { 445 (_state != _RUNNING_TEST)) {
428 if (testCase.result == null) testCase.pass(); 446 if (testCase.result == null) {
447 testCase.pass();
448 }
429 _currentTest++; 449 _currentTest++;
430 _testRunner(); 450 _testRunner();
431 } 451 }
432 } 452 }
433 }); 453 });
434 } 454 }
435 455
436 /** Menchanism to notify that an error was caught outside of this library. */ 456 /**
457 * Utility function that can be used to notify the test framework that an
458 * error was caught outside of this library.
459 */
437 void reportTestError(String msg, String trace) { 460 void reportTestError(String msg, String trace) {
438 if (_currentTest < _tests.length) { 461 if (_currentTest < _tests.length) {
439 final testCase = _tests[_currentTest]; 462 final testCase = _tests[_currentTest];
440 testCase.error(msg, trace); 463 testCase.error(msg, trace);
441 _state = _UNCAUGHT_ERROR; 464 _state = _UNCAUGHT_ERROR;
442 if (testCase.callbacks > 0) { 465 if (testCase.callbacks > 0) {
443 _currentTest++; 466 _currentTest++;
444 _testRunner(); 467 _testRunner();
445 } 468 }
446 } else { 469 } else {
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 } 603 }
581 _config.onInit(); 604 _config.onInit();
582 605
583 // Immediately queue the suite up. It will run after a timeout (i.e. after 606 // Immediately queue the suite up. It will run after a timeout (i.e. after
584 // main() has returned). 607 // main() has returned).
585 _defer(_runTests); 608 _defer(_runTests);
586 } 609 }
587 610
588 /** Signature for a test function. */ 611 /** Signature for a test function. */
589 typedef void TestFunction(); 612 typedef void TestFunction();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698