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

Side by Side Diff: client/testing/unittest/unittestsuite.dart

Issue 8302012: Move test(), group(), and expect() to top level. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove unneeded explicit suite. Created 9 years, 2 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
« no previous file with comments | « no previous file | client/tests/client/view/ViewTests.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // TODO(rnystrom): This code is gradually moving from a Java/JUnit style to
6 // something closer to JS/Jasmine. Eventually, the UnitTestSuite class can go
7 // away completely (or become private to this library) and the only exposed API
8 // will be group()/test()/expect(). Until then, both ways are supported, which
9 // is why things look a bit weird in here.
10
11 UnitTestSuite _currentSuite;
12
13 /**
14 * Description text of the current test group. If multiple groups are nested,
15 * this will contain all of their text concatenated.
16 */
17 String _currentGroup = '';
18
5 /** Base class for unit test suites run in a browser. */ 19 /** Base class for unit test suites run in a browser. */
6 class UnitTestSuite { 20 class UnitTestSuite {
7 21
8 /** Tests executed in this suite. */ 22 /** Tests executed in this suite. */
9 List<TestCase> _tests; 23 List<TestCase> _tests;
10 24
11 /**
12 * Description text of the current test group. If multiple groups are nested,
13 * this will contain all of their text concatenated.
14 */
15 String _group;
16
17 /** Whether this suite is run within dartium layout tests. */ 25 /** Whether this suite is run within dartium layout tests. */
18 bool _isLayoutTest; 26 bool _isLayoutTest;
19 27
20 /** Current test being executed. */ 28 /** Current test being executed. */
21 int _currentTest; 29 int _currentTest;
22 30
23 /** Total number of callbacks that have been executed in the current test. */ 31 /** Total number of callbacks that have been executed in the current test. */
24 int _callbacksCalled; 32 int _callbacksCalled;
25 33
26 /** 34 /**
27 * Whether an undetected error occurred while running the last test. This 35 * Whether an undetected error occurred while running the last test. This
28 * errors are commonly caused by DOM callbacks that were not guarded in a 36 * errors are commonly caused by DOM callbacks that were not guarded in a
29 * try-catch block. 37 * try-catch block.
30 */ 38 */
31 bool _uncaughtError; 39 bool _uncaughtError;
32 EventListener _onErrorClosure; 40 EventListener _onErrorClosure;
33 41
34 // TODO(sigmund): remove isLayoutTest argument after converting all DOM tests 42 // TODO(sigmund): remove isLayoutTest argument after converting all DOM tests
35 // to use the named constructor below. 43 // to use the named constructor below.
36 // TODO(vsm): remove the ignoredWindow parameter once all tests are fixed. 44 // TODO(vsm): remove the ignoredWindow parameter once all tests are fixed.
37 UnitTestSuite([var ignoredWindow = null, bool isLayoutTest = false]) 45 UnitTestSuite([var ignoredWindow = null, bool isLayoutTest = false])
38 : _isLayoutTest = isLayoutTest, 46 : _isLayoutTest = isLayoutTest,
39 _tests = new List<TestCase>(), 47 _tests = new List<TestCase>(),
40 _currentTest = 0, 48 _currentTest = 0,
41 _callbacksCalled = 0 { 49 _callbacksCalled = 0 {
42 _onErrorClosure = (e) { _onError(e); }; 50 _onErrorClosure = (e) { _onError(e); };
51 if (_currentSuite != null) {
52 throw 'Cannot have two UnitTestSuites in flight at the same time.';
53 }
54 _currentSuite = this;
43 } 55 }
44 56
45 // TODO(jacobr): remove the ignoredWindow parameter once all tests are fixed. 57 // TODO(jacobr): remove the ignoredWindow parameter once all tests are fixed.
46 UnitTestSuite.forLayoutTests([var ignoredWindow = null]) 58 UnitTestSuite.forLayoutTests([var ignoredWindow = null])
47 : _isLayoutTest = true, 59 : _isLayoutTest = true,
48 _tests = new List<TestCase>(), 60 _tests = new List<TestCase>(),
49 _currentTest = 0, 61 _currentTest = 0,
50 _callbacksCalled = 0 {} 62 _callbacksCalled = 0 {
63 if (_currentSuite != null) {
64 throw 'Cannot have two UnitTestSuites in flight at the same time.';
65 }
66 _currentSuite = this;
67 }
51 68
52 /** Starts running the testsuite. */ 69 /** Starts running the testsuite. */
53 void run() { 70 void run() {
54 final listener = (e) { 71 listener(e) {
55 _group = ''; 72 _currentGroup = '';
56 setUpTestSuite(); 73 setUpTestSuite();
57 runTests(); 74 runTests();
75
76 // This suite is done now, so discard it.
77 _currentSuite = null;
58 }; 78 };
79
59 try { 80 try {
60 window.dynamic.on.contentLoaded.add(listener); 81 window.dynamic.on.contentLoaded.add(listener);
61 } catch(var e) { 82 } catch(var e) {
62 // TODO(jacobr): remove this horrible hack to work around dartc bugs. 83 // TODO(jacobr): remove this horrible hack to work around dartc bugs.
63 window.dynamic.addEventListener("DOMContentLoaded", listener, false); 84 window.dynamic.addEventListener("DOMContentLoaded", listener, false);
64 } 85 }
65 } 86 }
66 87
67 /** Subclasses should override this method to register tests. */ 88 /** Subclasses should override this method to register tests. */
68 void setUpTestSuite() {} 89 void setUpTestSuite() {}
69 90
70 /** Enqueues a synchronous test. */ 91 /** Enqueues a synchronous test. */
71 UnitTestSuite addTest(TestFunction body) => test(null, body); 92 UnitTestSuite addTest(TestFunction body) {
93 test(null, body);
94 }
72 95
73 /** Adds the tests defined by the given TestSet to this suite. */ 96 /** Adds the tests defined by the given TestSet to this suite. */
74 void addTestSet(TestSet test) { 97 void addTestSet(TestSet test) {
75 test._bindToSuite(this); 98 test._bindToSuite(this);
76 test.setup(); 99 test.setup();
77 } 100 }
78 101
79 /** Adds the tests defined by the given TestSets to this suite. */ 102 /** Adds the tests defined by the given TestSets to this suite. */
80 void addTestSets(Iterable<TestSet> tests) { 103 void addTestSets(Iterable<TestSet> tests) {
81 for (TestSet test in tests) { 104 for (TestSet test in tests) {
82 addTestSet(test); 105 addTestSet(test);
83 } 106 }
84 } 107 }
85 108
86 /** Enqueues an asynchronous test that waits for [callbacks] callbacks. */ 109 /** Enqueues an asynchronous test that waits for [callbacks] callbacks. */
87 UnitTestSuite addAsyncTest(TestFunction body, int callbacks) => 110 void addAsyncTest(TestFunction body, int callbacks) {
Siggi Cherem (dart-lang) 2011/10/14 23:26:29 I'm not sure if this is currently used by any of t
88 asyncTest(null, callbacks, body); 111 asyncTest(null, callbacks, body);
112 }
89 113
90 /** Runs all queued tests, one at a time. */ 114 /** Runs all queued tests, one at a time. */
91 void runTests() { 115 void runTests() {
92 window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-start', '*'); 116 window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-start', '*');
93 // Isolate.bind makes sure the closure runs in the same isolate (i.e. this 117 // Isolate.bind makes sure the closure runs in the same isolate (i.e. this
94 // one) where it has been created. 118 // one) where it has been created.
95 window.setTimeout(Isolate.bind(() { 119 window.setTimeout(Isolate.bind(() {
96 assert (_currentTest == 0); 120 assert (_currentTest == 0);
97 // Listen for uncaught errors (see [_uncaughtError]). 121 // Listen for uncaught errors (see [_uncaughtError]).
98 // TODO(jacobr): remove this horrible hack when dartc bugs are fixed. 122 // TODO(jacobr): remove this horrible hack when dartc bugs are fixed.
(...skipping 13 matching lines...) Expand all
112 // Currently e.message works in dartium, but not in dartc. 136 // Currently e.message works in dartium, but not in dartc.
113 testCase.recordError('(DOM callback has errors) Caught ${e}', ''); 137 testCase.recordError('(DOM callback has errors) Caught ${e}', '');
114 _uncaughtError = true; 138 _uncaughtError = true;
115 if (testCase.callbacks > 0) { 139 if (testCase.callbacks > 0) {
116 _currentTest++; 140 _currentTest++;
117 _nextBatch(); 141 _nextBatch();
118 } 142 }
119 } 143 }
120 } 144 }
121 145
122 /**
123 * Creates a new test case with the given description and body. The
124 * description will include the descriptions of any surrounding group()
125 * calls.
126 */
127 UnitTestSuite test(String spec, TestFunction body) {
128 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0));
129 return this;
130 }
131
132 /**
133 * Creates a new async test case with the given description and body. The
134 * description will include the descriptions of any surrounding group()
135 * calls.
136 */
137 UnitTestSuite asyncTest(String spec, int callbacks, TestFunction body) {
138 final testCase =
139 new TestCase(_tests.length + 1, _fullSpec(spec), body, callbacks);
140 _tests.add(testCase);
141 if (callbacks < 1) {
142 testCase.recordError(
143 'Async tests must wait for at least one callback ', '');
144 }
145 return this;
146 }
147
148 /**
149 * Creates a new named group of tests. Calls to group() or test() within the
150 * body of the function passed to this will inherit this group's description.
151 */
152 void group(String description, void body()) {
153 // Concatenate the new group.
154 final oldGroup = _group;
155 if (_group != '') {
156 // Add a space.
157 _group = '$_group $description';
158 } else {
159 // The first group.
160 _group = description;
161 }
162
163 try {
164 body();
165 } finally {
166 // Now that the group is over, restore the previous one.
167 _group = oldGroup;
168 }
169 }
170
171 String _fullSpec(String spec) {
172 if (spec === null) return '$_group';
173 return _group != '' ? '$_group $spec' : spec;
174 }
175
176 /** Creates an expectation for the given value. */
177 Expectation expect(value) => new Expectation(value);
178
179 /** Called by subclasses to indicate that an asynchronous test completed. */ 146 /** Called by subclasses to indicate that an asynchronous test completed. */
180 void callbackDone() { 147 void callbackDone() {
181 _callbacksCalled++; 148 _callbacksCalled++;
182 final testCase = _tests[_currentTest]; 149 final testCase = _tests[_currentTest];
183 if (testCase.callbacks == 0) { 150 if (testCase.callbacks == 0) {
184 testCase.recordError( 151 testCase.recordError(
185 "Can't call callbackDone() on a synchronous test", ''); 152 "Can't call callbackDone() on a synchronous test", '');
186 _uncaughtError = true; 153 _uncaughtError = true;
187 } else if (_callbacksCalled > testCase.callbacks) { 154 } else if (_callbacksCalled > testCase.callbacks) {
188 final expected = testCase.callbacks; 155 final expected = testCase.callbacks;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 } 207 }
241 208
242 /** Publish results on the page and notify controller. */ 209 /** Publish results on the page and notify controller. */
243 void _completeTests() { 210 void _completeTests() {
244 try { 211 try {
245 window.dynamic.on.error.remove(_onErrorClosure); 212 window.dynamic.on.error.remove(_onErrorClosure);
246 } catch (var e) { 213 } catch (var e) {
247 // TODO(jacobr): remove this horrible hack to work around dartc bugs. 214 // TODO(jacobr): remove this horrible hack to work around dartc bugs.
248 window.dynamic.onerror = null; 215 window.dynamic.onerror = null;
249 } 216 }
217
250 int testsFailed = 0; 218 int testsFailed = 0;
251 int testsErrors = 0; 219 int testsErrors = 0;
252 int testsPassed = 0; 220 int testsPassed = 0;
253 221
254 for (TestCase t in _tests) { 222 for (TestCase t in _tests) {
255 if (t.success) { 223 if (t.success) {
256 testsPassed++; 224 testsPassed++;
257 } 225 }
258 if (t.fail) { 226 if (t.fail) {
259 testsFailed++; 227 testsFailed++;
(...skipping 28 matching lines...) Expand all
288 </td></tr>"""); 256 </td></tr>""");
289 } 257 }
290 newBody.add("</tbody></table>"); 258 newBody.add("</tbody></table>");
291 document.body.innerHTML = newBody.toString(); 259 document.body.innerHTML = newBody.toString();
292 } 260 }
293 261
294 window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-done', '*'); 262 window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-done', '*');
295 } 263 }
296 } 264 }
297 265
266 /** Creates an expectation for the given value. */
267 Expectation expect(value) => new Expectation(value);
268
269 /**
270 * Creates a new test case with the given description and body. The
271 * description will include the descriptions of any surrounding group()
272 * calls.
273 */
274 void test(String spec, TestFunction body) {
275 bool outermost = _ensureActiveSuite();
276
277 _currentSuite._tests.add(new TestCase(
278 _currentSuite._tests.length + 1, _fullSpec(spec), body, 0));
279
280 if (outermost) {
281 _currentSuite.run();
282 }
283 }
284
285 /**
286 * Creates a new async test case with the given description and body. The
287 * description will include the descriptions of any surrounding group()
288 * calls.
289 */
290 void asyncTest(String spec, int callbacks, TestFunction body) {
291 bool outermost = _ensureActiveSuite();
292
293 final testCase = new TestCase(
294 _currentSuite._tests.length + 1, _fullSpec(spec), body, callbacks);
295 _currentSuite._tests.add(testCase);
296
297 if (callbacks < 1) {
298 testCase.recordError(
299 'Async tests must wait for at least one callback ', '');
300 }
301
302 if (outermost) {
303 _currentSuite.run();
304 }
305 }
306
307 /**
308 * Creates a new named group of tests. Calls to group() or test() within the
309 * body of the function passed to this will inherit this group's description.
310 */
311 void group(String description, void body()) {
312 bool outermost = _ensureActiveSuite();
313
314 // Concatenate the new group.
315 final oldGroup = _currentGroup;
316 if (_currentGroup != '') {
317 // Add a space.
318 _currentGroup = '$_currentGroup $description';
319 } else {
320 // The first group.
321 _currentGroup = description;
322 }
323
324 try {
325 body();
326 } finally {
327 // Now that the group is over, restore the previous one.
328 _currentGroup = oldGroup;
329 }
330
331 if (outermost) {
332 _currentSuite.run();
333 }
334 }
335
336 String _fullSpec(String spec) {
337 if (spec === null) return '$_currentGroup';
338 return _currentGroup != '' ? '$_currentGroup $spec' : spec;
339 }
340
341 /**
342 * Lazily creates a UnitTestSuite if there isn't already an active one. Returns
343 * whether or not one was created.
344 */
345 _ensureActiveSuite() {
346 if (_currentSuite != null) {
347 return false;
348 }
349
350 _currentSuite = new UnitTestSuite();
351 return true;
352 }
353
298 /** 354 /**
299 * Wraps an value and provides an "==" operator that can be used to verify that 355 * Wraps an value and provides an "==" operator that can be used to verify that
300 * the value matches a given expectation. 356 * the value matches a given expectation.
301 */ 357 */
302 // TODO(rnystrom): Note that because Dart does not currently allow overloading 358 // TODO(rnystrom): Note that because Dart does not currently allow overloading
303 // != that this *cannot* be used with !=. If you do expect(1) != 2, it will do 359 // != that this *cannot* be used with !=. If you do expect(1) != 2, it will do
304 // the exact wrong thing. (It will invoke == which validates that 1 *does* 360 // the exact wrong thing. (It will invoke == which validates that 1 *does*
305 // equal 2.) If we get an overloadable != operator, that can be fixed. 361 // equal 2.) If we get an overloadable != operator, that can be fixed.
306 class Expectation { 362 class Expectation {
307 final _value; 363 final _value;
308 364
309 Expectation(this._value); 365 Expectation(this._value);
310 366
367 // TODO(rnystrom): Get rid of this and use .equals(). After some discussion,
368 // we decided this is the wrong approach for a bunch of reasons, clever as it
369 // may be.
311 /** Asserts that the value is equivalent to the given expected value. */ 370 /** Asserts that the value is equivalent to the given expected value. */
312 operator ==(expected) { 371 operator ==(expected) {
313 Expect.equals(expected, _value); 372 Expect.equals(expected, _value);
314 return _value == expected; 373 return _value == expected;
315 } 374 }
316 375
317 /** Asserts that the value is not null. */ 376 /** Asserts that the value is not null. */
318 void isNotNull() { 377 void isNotNull() {
319 Expect.notEquals(null, _value); 378 Expect.notEquals(null, _value);
320 } 379 }
321 380
322 /** Asserts that the value has the same elements as the given collection. */ 381 /** Asserts that the value has the same elements as the given collection. */
323 void equalsCollection(Collection expected) { 382 void equalsCollection(Collection expected) {
324 Expect.listEquals(expected, _value); 383 Expect.listEquals(expected, _value);
325 } 384 }
326 } 385 }
327 386
328 /** 387 /**
329 * A TestSet lets you break a test suite down into a collection of classes to 388 * A TestSet lets you break a test suite down into a collection of classes to
330 * keep things manageable. It exposes the same interface as UnitTestSuite 389 * keep things manageable. It exposes the same interface as UnitTestSuite
331 * (test(), group(), expect(), etc.) but defers to a parent suite that owns it. 390 * (test(), group(), expect(), etc.) but defers to a parent suite that owns it.
332 */ 391 */
333 class TestSet { 392 class TestSet {
334 UnitTestSuite _suite = null; 393 UnitTestSuite _currentSuite = null;
335 394
336 // TODO(rnystrom): Remove this when default constructors are supported. 395 // TODO(rnystrom): Remove this when default constructors are supported.
337 TestSet(); 396 TestSet();
338 397
339 void _bindToSuite(UnitTestSuite suite) { 398 void _bindToSuite(UnitTestSuite suite) {
340 _suite = suite; 399 _currentSuite = suite;
341 } 400 }
342 401
343 /** Override this to define the specifications for this test set. */ 402 /** Override this to define the specifications for this test set. */
344 void setup() { 403 void setup() {
345 // Do nothing. 404 // Do nothing.
346 } 405 }
347 406
348 /** Enqueues a synchronous test. */ 407 /** Enqueues a synchronous test. */
349 void addTest(TestFunction test) { 408 void addTest(TestFunction test) {
350 _suite.addTest(test); 409 _currentSuite.addTest(test);
351 } 410 }
352 411
353 /** Adds the tests defined by the given TestSet to this suite. */ 412 /** Adds the tests defined by the given TestSet to this suite. */
354 void addTestSet(TestSet test) { 413 void addTestSet(TestSet test) {
355 _suite.addTestSet(test); 414 _currentSuite.addTestSet(test);
356 } 415 }
357 416
358 /** Adds the tests defined by the given TestSets to this suite. */ 417 /** Adds the tests defined by the given TestSets to this suite. */
359 void addTestSets(Iterable<TestSet> tests) { 418 void addTestSets(Iterable<TestSet> tests) {
360 _suite.addTestSets(tests); 419 _currentSuite.addTestSets(tests);
361 } 420 }
362 421
363 /** Enqueues an asynchronous test that waits for [callbacks] callbacks. */ 422 /** Enqueues an asynchronous test that waits for [callbacks] callbacks. */
364 void addAsyncTest(TestFunction test, int callbacks) { 423 void addAsyncTest(TestFunction test, int callbacks) {
365 _suite.addAsyncTest(test, callbacks); 424 _currentSuite.addAsyncTest(test, callbacks);
366 } 425 }
367
368 /**
369 * Creates a new test case with the given description and body. The
370 * description will include the descriptions of any surrounding group()
371 * calls.
372 */
373 void test(String spec, void body()) {
374 _suite.test(spec, body);
375 }
376
377 /**
378 * Creates a new named group of tests. Calls to group() or test() within the
379 * body of the function passed to this will inherit this group's description.
380 */
381 void group(String description, void body()) {
382 _suite.group(description, body);
383 }
384
385 /** Creates an expectation for the given value. */
386 Expectation expect(value) => _suite.expect(value);
387 } 426 }
388 427
389 /** Summarizes information about a single test case. */ 428 /** Summarizes information about a single test case. */
390 class TestCase { 429 class TestCase {
391 /** Identifier for this test. */ 430 /** Identifier for this test. */
392 final id; 431 final id;
393 432
394 /** A description of what the test is specifying. */ 433 /** A description of what the test is specifying. */
395 final String description; 434 final String description;
396 435
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 </tr>"""; 499 </tr>""";
461 if (stackTrace != null) { 500 if (stackTrace != null) {
462 message += 501 message +=
463 "<tr><td></td><td colspan='2'><pre>${stackTrace}</pre></td></tr>"; 502 "<tr><td></td><td colspan='2'><pre>${stackTrace}</pre></td></tr>";
464 } 503 }
465 fail = true; 504 fail = true;
466 } 505 }
467 } 506 }
468 507
469 typedef void TestFunction(); 508 typedef void TestFunction();
OLDNEW
« no previous file with comments | « no previous file | client/tests/client/view/ViewTests.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698