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

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

Issue 8413058: Add command-line non-client support to unit test lib. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename a couple of methods. Created 9 years, 1 month 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 | « client/testing/unittest/sample.dart ('k') | client/testing/unittest/unittest.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 /** 5 /**
6 * Description text of the current test group. If multiple groups are nested, 6 * Description text of the current test group. If multiple groups are nested,
7 * this will contain all of their text concatenated. 7 * this will contain all of their text concatenated.
8 */ 8 */
9 String _currentGroup = ''; 9 String _currentGroup = '';
10 10
11 /** Tests executed in this suite. */ 11 /** Tests executed in this suite. */
12 List<TestCase> _tests; 12 List<TestCase> _tests;
13 13
14 /** Whether this is run within dartium layout tests. */ 14 /** Whether this is run within dartium layout tests. */
15 bool _isLayoutTest = false; 15 bool _isLayoutTest = false;
16 16
17 /** Current test being executed. */ 17 /** Current test being executed. */
18 int _currentTest = 0; 18 int _currentTest = 0;
19 19
20 /** Total number of callbacks that have been executed in the current test. */ 20 /** Total number of callbacks that have been executed in the current test. */
21 int _callbacksCalled = 0; 21 int _callbacksCalled = 0;
22 22
23 // TODO(rnystrom): Get rid of this if we get canonical closures for methods.
24 EventListener _onErrorClosure;
25
26 final _UNINITIALIZED = 0; 23 final _UNINITIALIZED = 0;
27 final _READY = 1; 24 final _READY = 1;
28 final _RUNNING_TEST = 2; 25 final _RUNNING_TEST = 2;
29 26
30 /** 27 /**
31 * Whether an undetected error occurred while running the last test. These 28 * Whether an undetected error occurred while running the last test. These
32 * errors are commonly caused by DOM callbacks that were not guarded in a 29 * errors are commonly caused by DOM callbacks that were not guarded in a
33 * try-catch block. 30 * try-catch block.
34 */ 31 */
35 final _UNCAUGHT_ERROR = 3; 32 final _UNCAUGHT_ERROR = 3;
36 33
37 int _state = _UNINITIALIZED; 34 int _state = _UNINITIALIZED;
38 35
36 final _PASS = 'pass';
37 final _FAIL = 'fail';
38 final _ERROR = 'error';
39
39 /** Creates an expectation for the given value. */ 40 /** Creates an expectation for the given value. */
40 Expectation expect(value) => new Expectation(value); 41 Expectation expect(value) => new Expectation(value);
41 42
42 /** Evaluates the given function and validates that it throws an exception. */ 43 /** Evaluates the given function and validates that it throws an exception. */
43 void expectThrow(function) { 44 void expectThrow(function) {
44 bool threw = false; 45 bool threw = false;
45 try { 46 try {
46 function(); 47 function();
47 } catch (var e) { 48 } catch (var e) {
48 threw = true; 49 threw = true;
(...skipping 18 matching lines...) Expand all
67 * calls. 68 * calls.
68 */ 69 */
69 void asyncTest(String spec, int callbacks, TestFunction body) { 70 void asyncTest(String spec, int callbacks, TestFunction body) {
70 _ensureInitialized(); 71 _ensureInitialized();
71 72
72 final testCase = new TestCase( 73 final testCase = new TestCase(
73 _tests.length + 1, _fullSpec(spec), body, callbacks); 74 _tests.length + 1, _fullSpec(spec), body, callbacks);
74 _tests.add(testCase); 75 _tests.add(testCase);
75 76
76 if (callbacks < 1) { 77 if (callbacks < 1) {
77 testCase.recordError( 78 testCase.error(
78 'Async tests must wait for at least one callback ', ''); 79 'Async tests must wait for at least one callback ', '');
79 } 80 }
80 } 81 }
81 82
82 /** 83 /**
83 * Creates a new named group of tests. Calls to group() or test() within the 84 * Creates a new named group of tests. Calls to group() or test() within the
84 * body of the function passed to this will inherit this group's description. 85 * body of the function passed to this will inherit this group's description.
85 */ 86 */
86 void group(String description, void body()) { 87 void group(String description, void body()) {
87 _ensureInitialized(); 88 _ensureInitialized();
(...skipping 14 matching lines...) Expand all
102 // Now that the group is over, restore the previous one. 103 // Now that the group is over, restore the previous one.
103 _currentGroup = oldGroup; 104 _currentGroup = oldGroup;
104 } 105 }
105 } 106 }
106 107
107 /** Called by subclasses to indicate that an asynchronous test completed. */ 108 /** Called by subclasses to indicate that an asynchronous test completed. */
108 void callbackDone() { 109 void callbackDone() {
109 _callbacksCalled++; 110 _callbacksCalled++;
110 final testCase = _tests[_currentTest]; 111 final testCase = _tests[_currentTest];
111 if (testCase.callbacks == 0) { 112 if (testCase.callbacks == 0) {
112 testCase.recordError( 113 testCase.error(
113 "Can't call callbackDone() on a synchronous test", ''); 114 "Can't call callbackDone() on a synchronous test", '');
114 _state = _UNCAUGHT_ERROR; 115 _state = _UNCAUGHT_ERROR;
115 } else if (_callbacksCalled > testCase.callbacks) { 116 } else if (_callbacksCalled > testCase.callbacks) {
116 final expected = testCase.callbacks; 117 final expected = testCase.callbacks;
117 testCase.recordError( 118 testCase.error(
118 'More calls to callbackDone() than expected. ' 119 'More calls to callbackDone() than expected. '
119 + 'Actual: ${_callbacksCalled}, expected: ${expected}', ''); 120 + 'Actual: ${_callbacksCalled}, expected: ${expected}', '');
120 _state = _UNCAUGHT_ERROR; 121 _state = _UNCAUGHT_ERROR;
121 } else if ((_callbacksCalled == testCase.callbacks) && 122 } else if ((_callbacksCalled == testCase.callbacks) &&
122 (_state != _RUNNING_TEST)) { 123 (_state != _RUNNING_TEST)) {
123 testCase.recordSuccess(); 124 testCase.pass();
124 _currentTest++; 125 _currentTest++;
125 _nextBatch(); 126 _nextBatch();
126 } 127 }
127 } 128 }
128 129
129 void forLayoutTests() { 130 void forLayoutTests() {
130 _isLayoutTest = true; 131 _isLayoutTest = true;
131 } 132 }
132 133
133 /** Runs all queued tests, one at a time. */ 134 /** Runs all queued tests, one at a time. */
134 _runTests() { 135 _runTests() {
135 window.postMessage('unittest-suite-start', '*'); 136 _platformStartTests();
136 window.setTimeout(() { 137
138 _platformDefer(() {
137 assert (_currentTest == 0); 139 assert (_currentTest == 0);
138
139 // Listen for uncaught errors.
140 window.onerror = _onErrorClosure;
141 _nextBatch(); 140 _nextBatch();
142 }, 0); 141 });
143 } 142 }
144 143
145 /** Runs a single test. */ 144 /** Runs a single test. */
146 _runTest(TestCase testCase) { 145 _runTest(TestCase testCase) {
147 try { 146 try {
148 // TODO(sigmund): remove this declaration once dartc supports trapping error 147 // TODO(sigmund): remove this declaration once dartc supports trapping error
149 // traces. 148 // traces.
150 var trace = ''; 149 var trace = '';
151 _callbacksCalled = 0; 150 _callbacksCalled = 0;
152 _state = _RUNNING_TEST; 151 _state = _RUNNING_TEST;
153 152
154 testCase.test(); 153 testCase.test();
155 154
156 if (_state != _UNCAUGHT_ERROR) { 155 if (_state != _UNCAUGHT_ERROR) {
157 if (testCase.callbacks == _callbacksCalled) { 156 if (testCase.callbacks == _callbacksCalled) {
158 testCase.recordSuccess(); 157 testCase.pass();
159 } 158 }
160 } 159 }
160
161 } catch (ExpectException e, var trace) { 161 } catch (ExpectException e, var trace) {
162 if (_state != _UNCAUGHT_ERROR) { 162 if (_state != _UNCAUGHT_ERROR) {
163 testCase.recordFail(e.message, trace.toString()); 163 testCase.fail(e.message, trace.toString());
164 } 164 }
165 } catch (var e, var trace) { 165 } catch (var e, var trace) {
166 if (_state != _UNCAUGHT_ERROR) { 166 if (_state != _UNCAUGHT_ERROR) {
167 testCase.recordError('Caught ${e}', trace.toString()); 167 testCase.error('Caught ${e}', trace.toString());
168 } 168 }
169 } finally { 169 } finally {
170 _state = _READY; 170 _state = _READY;
171 } 171 }
172 } 172 }
173 173
174 /** 174 /**
175 * Runs a batch of tests, yielding whenever an asynchronous test starts 175 * Runs a batch of tests, yielding whenever an asynchronous test starts
176 * running. Tests will resume executing when such asynchronous test calls 176 * running. Tests will resume executing when such asynchronous test calls
177 * [done] or if it fails with an exception. 177 * [done] or if it fails with an exception.
178 */ 178 */
179 _nextBatch() { 179 _nextBatch() {
180 while (_currentTest < _tests.length) { 180 while (_currentTest < _tests.length) {
181 final testCase = _tests[_currentTest]; 181 final testCase = _tests[_currentTest];
182 182
183 _runTest(testCase); 183 _runTest(testCase);
184 184
185 if (!testCase.isComplete && testCase.callbacks > 0) return; 185 if (!testCase.isComplete && testCase.callbacks > 0) return;
186 186
187 _currentTest++; 187 _currentTest++;
188 } 188 }
189 189
190 _completeTests(); 190 _completeTests();
191 } 191 }
192 192
193 /** Publish results on the page and notify controller. */ 193 /** Publish results on the page and notify controller. */
194 _completeTests() { 194 _completeTests() {
195 window.onerror = null;
196
197 _state = _UNINITIALIZED; 195 _state = _UNINITIALIZED;
198 196
197 int testsPassed = 0;
199 int testsFailed = 0; 198 int testsFailed = 0;
200 int testsErrors = 0; 199 int testsErrors = 0;
201 int testsPassed = 0;
202 200
203 for (TestCase t in _tests) { 201 for (TestCase t in _tests) {
204 if (t.success) testsPassed++; 202 switch (t.result) {
205 if (t.fail) testsFailed++; 203 case _PASS: testsPassed++; break;
206 if (t.error) testsErrors++; 204 case _FAIL: testsFailed++; break;
205 case _ERROR: testsErrors++; break;
206 }
207 } 207 }
208 208
209 if (_isLayoutTest && testsPassed == _tests.length) { 209 _platformCompleteTests(testsPassed, testsFailed, testsErrors);
210 document.body.innerHTML = "PASS";
211 } else {
212 var newBody = new StringBuffer();
213 newBody.add("<table class='unittest-table'><tbody>");
214 newBody.add(testsPassed == _tests.length
215 ? "<tr><td colspan='3' class='unittest-pass'>PASS</td></tr>"
216 : "<tr><td colspan='3' class='unittest-fail'>FAIL</td></tr>");
217
218 for (final test in _tests) {
219 newBody.add(test.message);
220 }
221
222 if (testsPassed == _tests.length) {
223 newBody.add("<tr><td colspan='3' class='unittest-pass'>All "
224 + testsPassed + " tests passed</td></tr>");
225 } else {
226 newBody.add("""
227 <tr><td colspan='3'>Total
228 <span class='unittest-pass'>${testsPassed} passed</span>,
229 <span class='unittest-fail'>${testsFailed} failed</span>
230 <span class='unittest-error'>${testsErrors} errors</span>
231 </td></tr>""");
232 }
233 newBody.add("</tbody></table>");
234 document.body.innerHTML = newBody.toString();
235 }
236
237 window.postMessage('unittest-suite-done', '*');
238 }
239
240 void _onError(e) {
241 if (_currentTest < _tests.length) {
242 final testCase = _tests[_currentTest];
243 // TODO(vsm): figure out how to expose the stack trace here
244 // Currently e.message works in dartium, but not in dartc.
245 testCase.recordError('(DOM callback has errors) Caught ${e}', '');
246 _state = _UNCAUGHT_ERROR;
247 if (testCase.callbacks > 0) {
248 _currentTest++;
249 _nextBatch();
250 }
251 }
252 } 210 }
253 211
254 String _fullSpec(String spec) { 212 String _fullSpec(String spec) {
255 if (spec === null) return '$_currentGroup'; 213 if (spec === null) return '$_currentGroup';
256 return _currentGroup != '' ? '$_currentGroup $spec' : spec; 214 return _currentGroup != '' ? '$_currentGroup $spec' : spec;
257 } 215 }
258 216
259 /** 217 /**
260 * Lazily initializes the test library if not already initialized. 218 * Lazily initializes the test library if not already initialized.
261 */ 219 */
262 _ensureInitialized() { 220 _ensureInitialized() {
263 if (_state != _UNINITIALIZED) return; 221 if (_state != _UNINITIALIZED) return;
264 222
265 _tests = <TestCase>[]; 223 _tests = <TestCase>[];
266 _onErrorClosure = (e) { _onError(e); }; 224 _currentGroup = '';
225 _state = _READY;
226
227 _platformInitialize();
267 228
268 // Immediately queue the suite up. It will run after a timeout (i.e. after 229 // Immediately queue the suite up. It will run after a timeout (i.e. after
269 // main() has returned). 230 // main() has returned).
270 listener() { 231 _platformDefer(_runTests);
271 _currentGroup = '';
272 _runTests();
273 };
274
275 window.setTimeout(listener, 0);
276
277 _state = _READY;
278 } 232 }
279 233
280 /** 234 /**
281 * Wraps an value and provides an "==" operator that can be used to verify that 235 * Wraps an value and provides an "==" operator that can be used to verify that
282 * the value matches a given expectation. 236 * the value matches a given expectation.
283 */ 237 */
284 class Expectation { 238 class Expectation {
285 final _value; 239 final _value;
286 240
287 Expectation(this._value); 241 Expectation(this._value);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 296
343 /** A description of what the test is specifying. */ 297 /** A description of what the test is specifying. */
344 final String description; 298 final String description;
345 299
346 /** The body of the test case. */ 300 /** The body of the test case. */
347 final TestFunction test; 301 final TestFunction test;
348 302
349 /** Total number of callbacks to wait for before the test completes. */ 303 /** Total number of callbacks to wait for before the test completes. */
350 int callbacks; 304 int callbacks;
351 305
352 /** Whether this test case was succesful. */ 306 /** Error or failure message. */
353 bool success; 307 String message = '';
354 308
355 /** Whether an Expect call failed in this test. */ 309 /**
356 bool fail; 310 * One of [_PASS], [_FAIL], or [_ERROR] or [null] if the test hasn't run yet.
311 */
312 String result;
357 313
358 /** Whether this test case had a runtime error. */ 314 /** Stack trace associated with this test, or null if it succeeded. */
359 bool error; 315 String stackTrace;
360 316
361 /** Messages to display at the end of the test run. */ 317 TestCase(this.id, this.description, this.test, this.callbacks);
362 String message;
363 318
364 TestCase(this.id, this.description, this.test, this.callbacks) 319 bool get isComplete() => result != null;
365 : success = false, 320
366 fail = false, 321 void pass() {
367 error = false { 322 result = _PASS;
368 message = '''<tr>
369 <td>${id}</td>
370 <td class="unittest-error">NO STATUS</td>
371 <td>Test did not complete</td>
372 </tr>''';
373 } 323 }
374 324
375 bool get isComplete() => success || fail || error; 325 void fail(String message, String stackTrace) {
376 326 result = _FAIL;
377 void recordSuccess() { 327 this.message = message;
378 _setMessage('pass', '', null); 328 this.stackTrace = stackTrace;
379 success = true;
380 } 329 }
381 330
382 void recordError(String msg, String stackTrace) { 331 void error(String message, String stackTrace) {
383 _setMessage('error', msg, stackTrace); 332 result = _ERROR;
384 error = true; 333 this.message = message;
385 } 334 this.stackTrace = stackTrace;
386
387 void recordFail(String msg, String stackTrace) {
388 _setMessage('fail', msg, stackTrace);
389 fail = true;
390 }
391
392 void _setMessage(String type, String msg, String stackTrace) {
393 message =
394 '''
395 <tr>
396 <td>${id}</td>
397 <td class="unittest-$type">${type.toUpperCase()}</td>
398 <td>Expectation: $description. $msg</td>
399 </tr>
400 ''';
401
402 if (stackTrace != null) {
403 message +=
404 '<tr><td></td><td colspan="2"><pre>${stackTrace}</pre></td></tr>';
405 }
406 } 335 }
407 } 336 }
408 337
409 typedef void TestFunction(); 338 typedef void TestFunction();
OLDNEW
« no previous file with comments | « client/testing/unittest/sample.dart ('k') | client/testing/unittest/unittest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698