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

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

Issue 18420007: pkg/unittest: cleanup to InteractiveHtmlConfiguration (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 5 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 | no next file » | 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 * This configuration can be used to rerun selected tests, as well 6 * This configuration can be used to rerun selected tests, as well
7 * as see diagnostic output from tests. It runs each test in its own 7 * as see diagnostic output from tests. It runs each test in its own
8 * IFrame, so the configuration consists of two parts - a 'parent' 8 * IFrame, so the configuration consists of two parts - a 'parent'
9 * config that manages all the tests, and a 'child' config for the 9 * config that manages all the tests, and a 'child' config for the
10 * IFrame that runs the individual tests. 10 * IFrame that runs the individual tests.
11 * 11 *
12 * Note: this unit test configuration will not work with the debugger (the tests 12 * Note: this unit test configuration will not work with the debugger (the tests
13 * are executed in a separate IFrame). 13 * are executed in a separate IFrame).
14 */ 14 */
15 library unittest_interactive_html_config; 15 library unittest_interactive_html_config;
16 16
17 // TODO(gram) - add options for: remove IFrame on done/keep 17 // TODO(gram) - add options for: remove IFrame on done/keep
18 // IFrame for failed tests/keep IFrame for all tests. 18 // IFrame for failed tests/keep IFrame for all tests.
19 19
20 import 'dart:html'; 20 import 'dart:html';
21 import 'dart:async'; 21 import 'dart:async';
22 import 'dart:math'; 22 import 'dart:math';
23 import 'unittest.dart'; 23 import 'unittest.dart';
24 24
25 /** The messages exchanged between parent and child. */ 25 /** The messages exchanged between parent and child. */
26
27 class _Message { 26 class _Message {
28 static const START = 'start'; 27 static const START = 'start';
29 static const LOG = 'log'; 28 static const LOG = 'log';
30 static const STACK = 'stack'; 29 static const STACK = 'stack';
31 static const PASS = 'pass'; 30 static const PASS = 'pass';
32 static const FAIL = 'fail'; 31 static const FAIL = 'fail';
33 static const ERROR = 'error'; 32 static const ERROR = 'error';
33 static const _PREFIX = 'TestMsg:';
34 34
35 String messageType; 35 final String messageType;
36 int elapsed; 36 final int elapsed;
37 String body; 37 final String body;
38 38
39 static String text(String messageType, 39 static String text(String messageType,
40 [int elapsed = 0, String body = '']) => 40 [int elapsed = 0, String body = '']) =>
41 '$messageType $elapsed $body'; 41 '$_PREFIX$messageType $elapsed $body';
42 42
43 _Message(this.messageType, [this.elapsed = 0, this.body = '']); 43 _Message(this.messageType, [this.elapsed = 0, this.body = '']);
44 44
45 _Message.fromString(String msg) { 45 factory _Message.fromString(String msg) {
46 int idx = msg.indexOf(' '); 46 if(!msg.startsWith(_PREFIX)) {
47 messageType = msg.substring(0, idx); 47 return null;
48 }
49 int idx = msg.indexOf(' ', _PREFIX.length);
50 var messageType = msg.substring(_PREFIX.length, idx);
48 ++idx; 51 ++idx;
49 int idx2 = msg.indexOf(' ', idx); 52 int idx2 = msg.indexOf(' ', idx);
50 elapsed = int.parse(msg.substring(idx, idx2)); 53 var elapsed = int.parse(msg.substring(idx, idx2));
51 ++idx2; 54 ++idx2;
52 body = msg.substring(idx2); 55 var body = msg.substring(idx2);
56
57 return new _Message(messageType, elapsed, body);
53 } 58 }
54 59
55 String toString() => text(messageType, elapsed, body); 60 String toString() => text(messageType, elapsed, body);
56 } 61 }
57 62
58 63
59 class HtmlConfiguration extends Configuration { 64 class HtmlConfiguration extends Configuration {
60 StreamSubscription _errorSubscription; 65 StreamSubscription _errorSubscription;
61 66
62 void _installErrorHandler() { 67 void _installErrorHandler() {
(...skipping 14 matching lines...) Expand all
77 82
78 /** 83 /**
79 * The child configuration that is used to run individual tests in 84 * The child configuration that is used to run individual tests in
80 * an IFrame and post the results back to the parent. In principle 85 * an IFrame and post the results back to the parent. In principle
81 * this can run more than one test in the IFrame but currently only 86 * this can run more than one test in the IFrame but currently only
82 * one is used. 87 * one is used.
83 */ 88 */
84 class ChildInteractiveHtmlConfiguration extends HtmlConfiguration { 89 class ChildInteractiveHtmlConfiguration extends HtmlConfiguration {
85 90
86 /** The window to which results must be posted. */ 91 /** The window to which results must be posted. */
87 WindowBase parentWindow; 92 WindowBase _parentWindow;
88 93
89 /** The time at which tests start. */ 94 /** The time at which tests start. */
90 Map<int,DateTime> _testStarts; 95 final Map<int,DateTime> _testStarts;
91 96
92 ChildInteractiveHtmlConfiguration() : 97 ChildInteractiveHtmlConfiguration() :
93 _testStarts = new Map<int,DateTime>(); 98 _testStarts = new Map<int,DateTime>();
94 99
95 /** Don't start running tests automatically. */ 100 /** Don't start running tests automatically. */
96 get autoStart => false; 101 get autoStart => false;
97 102
98 void onInit() { 103 void onInit() {
99 _installErrorHandler(); 104 _installErrorHandler();
100 105
101 /** 106 /**
102 * The parent posts a 'start' message to kick things off, 107 * The parent posts a 'start' message to kick things off,
103 * which is handled by this handler. It saves the parent 108 * which is handled by this handler. It saves the parent
104 * window, gets the test ID from the query parameter in the 109 * window, gets the test ID from the query parameter in the
105 * IFrame URL, sets that as a solo test and starts test execution. 110 * IFrame URL, sets that as a solo test and starts test execution.
106 */ 111 */
107 window.onMessage.listen((MessageEvent e) { 112 window.onMessage.listen((MessageEvent e) {
108 // Get the result, do any logging, then do a pass/fail. 113 // Get the result, do any logging, then do a pass/fail.
109 var m = new _Message.fromString(e.data); 114 var m = new _Message.fromString(e.data);
110 if (m.messageType == _Message.START) { 115 if (m != null && m.messageType == _Message.START) {
111 parentWindow = e.source; 116 _parentWindow = e.source;
112 String search = window.location.search; 117 String search = window.location.search;
113 int pos = search.indexOf('t='); 118 int pos = search.indexOf('t=');
114 String ids = search.substring(pos+2); 119 String ids = search.substring(pos+2);
115 int id = int.parse(ids); 120 int id = int.parse(ids);
116 setSoloTest(id); 121 setSoloTest(id);
117 runTests(); 122 runTests();
118 } 123 }
119 }); 124 });
120 } 125 }
121 126
(...skipping 13 matching lines...) Expand all
135 * a timestamp and posts them back to the parent window. 140 * a timestamp and posts them back to the parent window.
136 */ 141 */
137 void onLogMessage(TestCase testCase, String message) { 142 void onLogMessage(TestCase testCase, String message) {
138 int elapsed; 143 int elapsed;
139 if (testCase == null) { 144 if (testCase == null) {
140 elapsed = -1; 145 elapsed = -1;
141 } else { 146 } else {
142 DateTime end = new DateTime.now(); 147 DateTime end = new DateTime.now();
143 elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds; 148 elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
144 } 149 }
145 parentWindow.postMessage( 150 _parentWindow.postMessage(
146 _Message.text(_Message.LOG, elapsed, message).toString(), '*'); 151 _Message.text(_Message.LOG, elapsed, message).toString(), '*');
147 } 152 }
148 153
149 /** 154 /**
150 * Get the elapsed time for the test, anbd post the test result 155 * Get the elapsed time for the test, anbd post the test result
151 * back to the parent window. If the test failed due to an exception 156 * back to the parent window. If the test failed due to an exception
152 * the stack is posted back too (before the test result). 157 * the stack is posted back too (before the test result).
153 */ 158 */
154 void onTestResult(TestCase testCase) { 159 void onTestResult(TestCase testCase) {
155 super.onTestResult(testCase); 160 super.onTestResult(testCase);
156 DateTime end = new DateTime.now(); 161 DateTime end = new DateTime.now();
157 int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds; 162 int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
158 if (testCase.stackTrace != null) { 163 if (testCase.stackTrace != null) {
159 parentWindow.postMessage( 164 _parentWindow.postMessage(
160 _Message.text(_Message.STACK, elapsed, testCase.stackTrace), '*'); 165 _Message.text(_Message.STACK, elapsed, testCase.stackTrace), '*');
161 } 166 }
162 parentWindow.postMessage( 167 _parentWindow.postMessage(
163 _Message.text(testCase.result, elapsed, testCase.message), '*'); 168 _Message.text(testCase.result, elapsed, testCase.message), '*');
164 } 169 }
165 void onSummary(int passed, int failed, int errors, List<TestCase> results, 170 void onSummary(int passed, int failed, int errors, List<TestCase> results,
166 String uncaughtError) { 171 String uncaughtError) {
167 } 172 }
168 173
169 void onDone(bool success) { 174 void onDone(bool success) {
170 _uninstallErrorHandler(); 175 _uninstallErrorHandler();
171 } 176 }
172 } 177 }
173 178
174 /** 179 /**
175 * The parent configuration runs in the top-level window; it wraps the tests 180 * The parent configuration runs in the top-level window; it wraps the tests
176 * in new functions that create child IFrames and run the real tests. 181 * in new functions that create child IFrames and run the real tests.
177 */ 182 */
178 class ParentInteractiveHtmlConfiguration extends HtmlConfiguration { 183 class ParentInteractiveHtmlConfiguration extends HtmlConfiguration {
179 Map<int,DateTime> _testStarts; 184 final Map<int,DateTime> _testStarts;
180 185
181 186
182 /** The stack that was posted back from the child, if any. */ 187 /** The stack that was posted back from the child, if any. */
183 String _stack; 188 String _stack;
184 189
185 int _testTime; 190 int _testTime;
186 /** 191 /**
187 * Whether or not we have already wrapped the TestCase test functions 192 * Whether or not we have already wrapped the TestCase test functions
188 * in new closures that instead create an IFrame and get it to run the 193 * in new closures that instead create an IFrame and get it to run the
189 * test. 194 * test.
190 */ 195 */
191 bool _doneWrap = false; 196 bool _doneWrap = false;
192 197
193 StreamSubscription _messageSubscription; 198 StreamSubscription _messageSubscription;
194 199
195 ParentInteractiveHtmlConfiguration() : 200 ParentInteractiveHtmlConfiguration() :
196 _testStarts = new Map<int,DateTime>(); 201 _testStarts = new Map<int,DateTime>();
197 202
198 // We need to block until the test is done, so we make a 203 // We need to block until the test is done, so we make a
199 // dummy async callback that we will use to flag completion. 204 // dummy async callback that we will use to flag completion.
200 Function completeTest = null; 205 Function _completeTest = null;
201 206
202 wrapTest(TestCase testCase) { 207 Function _wrapTest(TestCase testCase) {
203 String baseUrl = window.location.toString(); 208 String baseUrl = window.location.toString();
204 String url = '${baseUrl}?t=${testCase.id}'; 209 String url = '${baseUrl}?t=${testCase.id}';
205 return () { 210 return () {
206 // Rebuild the child IFrame. 211 // Rebuild the child IFrame.
207 Element childDiv = document.query('#child'); 212 Element childDiv = document.query('#child');
208 childDiv.nodes.clear(); 213 childDiv.nodes.clear();
209 IFrameElement child = new Element.html(""" 214 IFrameElement child = new Element.html("""
210 <iframe id='childFrame${testCase.id}' src='$url' style='display:none'> 215 <iframe id='childFrame${testCase.id}' src='$url' style='display:none'>
211 </iframe>"""); 216 </iframe>""");
212 childDiv.nodes.add(child); 217 childDiv.nodes.add(child);
213 completeTest = expectAsync0((){ }); 218 _completeTest = expectAsync0((){ });
214 // Kick off the test when the IFrame is loaded. 219 // Kick off the test when the IFrame is loaded.
215 child.onLoad.listen((e) { 220 child.onLoad.listen((e) {
216 child.contentWindow.postMessage(_Message.text(_Message.START), '*'); 221 child.contentWindow.postMessage(_Message.text(_Message.START), '*');
217 }); 222 });
218 }; 223 };
219 } 224 }
220 225
221 void _handleMessage(MessageEvent e) { 226 void _handleMessage(MessageEvent e) {
222 // Get the result, do any logging, then do a pass/fail. 227 // Get the result, do any logging, then do a pass/fail.
223 var msg = new _Message.fromString(e.data); 228 var msg = new _Message.fromString(e.data);
229
230 if(msg == null) {
231 return;
232 }
224 if (msg.messageType == _Message.LOG) { 233 if (msg.messageType == _Message.LOG) {
225 logMessage(e.data); 234 logMessage(e.data);
226 } else if (msg.messageType == _Message.STACK) { 235 } else if (msg.messageType == _Message.STACK) {
227 _stack = msg.body; 236 _stack = msg.body;
228 } else { 237 } else {
229 _testTime = msg.elapsed; 238 _testTime = msg.elapsed;
230 logMessage(_Message.text(_Message.LOG, _testTime, 'Complete')); 239 logMessage(_Message.text(_Message.LOG, _testTime, 'Complete'));
231 if (msg.messageType == _Message.PASS) { 240 if (msg.messageType == _Message.PASS) {
232 currentTestCase.pass(); 241 currentTestCase.pass();
233 } else if (msg.messageType == _Message.FAIL) { 242 } else if (msg.messageType == _Message.FAIL) {
234 currentTestCase.fail(msg.body, _stack); 243 currentTestCase.fail(msg.body, _stack);
235 } else if (msg.messageType == _Message.ERROR) { 244 } else if (msg.messageType == _Message.ERROR) {
236 currentTestCase.error(msg.body, _stack); 245 currentTestCase.error(msg.body, _stack);
237 } 246 }
238 completeTest(); 247 _completeTest();
239 } 248 }
240 } 249 }
241 250
242 void onInit() { 251 void onInit() {
243 _installErrorHandler(); 252 _installErrorHandler();
244 document.query('#group-divs').innerHtml = ""; 253 document.query('#group-divs').innerHtml = "";
245 } 254 }
246 255
247 void onStart() { 256 void onStart() {
248 _installErrorHandler(); 257 _installErrorHandler();
249 if (!_doneWrap) { 258 if (!_doneWrap) {
250 _doneWrap = true; 259 _doneWrap = true;
251 for (int i = 0; i < testCases.length; i++) { 260 for (int i = 0; i < testCases.length; i++) {
252 testCases[i].testFunction = wrapTest(testCases[i]); 261 testCases[i].testFunction = _wrapTest(testCases[i]);
253 testCases[i].setUp = null; 262 testCases[i].setUp = null;
254 testCases[i].tearDown = null; 263 testCases[i].tearDown = null;
255 } 264 }
256 } 265 }
257 assert(_messageSubscription == null); 266 assert(_messageSubscription == null);
258 _messageSubscription = window.onMessage.listen(_handleMessage); 267 _messageSubscription = window.onMessage.listen(_handleMessage);
259 } 268 }
260 269
261 static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]'); 270 static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]');
262 271
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 "</img></div>")); 469 "</img></div>"));
461 } 470 }
462 if (document.query('#child') == null) { 471 if (document.query('#child') == null) {
463 document.body.nodes.add(new Element.html("<div id='child'></div>")); 472 document.body.nodes.add(new Element.html("<div id='child'></div>"));
464 } 473 }
465 } 474 }
466 475
467 /** 476 /**
468 * Allocate a Configuration. We allocate either a parent or child, depending on 477 * Allocate a Configuration. We allocate either a parent or child, depending on
469 * whether the URL has a search part. 478 * whether the URL has a search part.
470 * 479 *
471 * Note: this unit test configuration will not work with the debugger (the tests 480 * Note: this unit test configuration will not work with the debugger (the tests
472 * are executed in a separate IFrame). 481 * are executed in a separate IFrame).
473 */ 482 */
474 void useInteractiveHtmlConfiguration() { 483 void useInteractiveHtmlConfiguration() {
475 if (window.location.search == '') { // This is the parent. 484 if (window.location.search == '') { // This is the parent.
476 _prepareDom(); 485 _prepareDom();
477 unittestConfiguration = _singletonParent; 486 unittestConfiguration = _singletonParent;
478 } else { 487 } else {
479 unittestConfiguration = _singletonChild; 488 unittestConfiguration = _singletonChild;
480 } 489 }
481 } 490 }
482 491
483 final _singletonParent = new ParentInteractiveHtmlConfiguration(); 492 final _singletonParent = new ParentInteractiveHtmlConfiguration();
484 final _singletonChild = new ChildInteractiveHtmlConfiguration(); 493 final _singletonChild = new ChildInteractiveHtmlConfiguration();
485 494
486 String _CSS = """ 495 const String _CSS = """
487 body { 496 body {
488 font-family: Arial, sans-serif; 497 font-family: Arial, sans-serif;
489 margin: 0; 498 margin: 0;
490 font-size: 14px; 499 font-size: 14px;
491 } 500 }
492 501
493 #application h2, 502 #application h2,
494 #specs h2 { 503 #specs h2 {
495 margin: 0; 504 margin: 0;
496 padding: 0.5em; 505 padding: 0.5em;
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 682
674 ul, menu, dir { 683 ul, menu, dir {
675 display: block; 684 display: block;
676 list-style-type: disc; 685 list-style-type: disc;
677 -webkit-margin-before: 1em; 686 -webkit-margin-before: 1em;
678 -webkit-margin-after: 1em; 687 -webkit-margin-after: 1em;
679 -webkit-margin-start: 0px; 688 -webkit-margin-start: 0px;
680 -webkit-margin-end: 0px; 689 -webkit-margin-end: 0px;
681 -webkit-padding-start: 40px; 690 -webkit-padding-start: 40px;
682 } 691 }
683 692 """;
684 """;
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698