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

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

Issue 13062005: pkg/unittest: removed html_layout_config (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * A configuration for running layout tests with testrunner.
7 * This configuration is similar to the interactive_html_config
8 * as it runs each test in its own IFrame. However, where the former
9 * recreated the IFrame for each test, here the IFrames are preserved.
10 * Furthermore we post a message on completion.
11 */
12 library html_layout_config;
13
14 import 'dart:async';
15 import 'dart:html';
16 import 'dart:math';
17 import 'unittest.dart';
18
19 /** The messages exchanged between parent and child. */
20 // TODO(gram) At some point postMessage was supposed to support
21 // sending arrays and maps. When it does we can get rid of the encoding/
22 // decoding of messages as string.
23 class _Message {
24 static final START = 'start';
25 static final LOG = 'log';
26 static final STACK = 'stack';
27 static final PASS = 'pass';
28 static final FAIL = 'fail';
29 static final ERROR = 'error';
30
31 String messageType;
32 int elapsed;
33 String body;
34
35 static String text(String messageType,
36 [int elapsed = 0, String body = '']) =>
37 '$messageType $elapsed $body';
38
39 _Message(this.messageType, [this.elapsed = 0, this.body = '']);
40
41 _Message.fromString(String msg) {
42 // The format of a message is '<type> <elapsedTime> <body>'.
43 // If we don't get a type we default to a 'log' type.
44 var messageParser = new RegExp('\([a-z]*\) \([0-9]*\) \(.*\)');
45 Match match = messageParser.firstMatch(msg);
46 if (match == null) {
47 messageType = 'log';
48 elapsed = 0;
49 body = msg;
50 } else {
51 messageType = match.group(1);
52 elapsed = int.parse(match.group(2));
53 body = match.group(3);
54 }
55 }
56
57 String toString() => text(messageType, elapsed, body);
58 }
59
60 /**
61 * The child configuration that is used to run individual tests in
62 * an IFrame and post the results back to the parent. In principle
63 * this can run more than one test in the IFrame but currently only
64 * one is used.
65 */
66 class ChildHtmlConfiguration extends Configuration {
67 get name => 'ChildHtmlConfiguration';
68
69 StreamSubscription _errorSubscription;
70
71 /** The window to which results must be posted. */
72 Window parentWindow;
73
74 /** The time at which tests start. */
75 Map<int,DateTime> _testStarts;
76
77 ChildHtmlConfiguration() :
78 _testStarts = new Map<int,DateTime>();
79
80 /** Don't start running tests automatically. */
81 get autoStart => false;
82
83 void onInit() {
84 /**
85 * The parent posts a 'start' message to kick things off,
86 * which is handled by this handler. It saves the parent
87 * window, gets the test ID from the query parameter in the
88 * IFrame URL, sets that as a solo test and starts test execution.
89 */
90 window.onMessage.listen((MessageEvent e) {
91 var m = new _Message.fromString(e.data);
92 if (m.messageType == _Message.START) {
93 parentWindow = e.source;
94 String search = window.location.search;
95 int pos = search.indexOf('t=');
96 String ids = search.substring(pos+2);
97 int id = int.parse(ids);
98 setSoloTest(id);
99 runTests();
100 }
101 });
102 }
103
104 void onStart() {
105 _errorSubscription = window.onError.listen((e) {
106 handleExternalError(e, '(DOM callback has errors)');
107 });
108 }
109
110 /** Record the start time of the test. */
111 void onTestStart(TestCase testCase) {
112 super.onTestStart(testCase);
113 _testStarts[testCase.id]= new DateTime.now();
114 }
115
116 /**
117 * Tests can call [log] for diagnostic output. These log
118 * messages in turn get passed to this method, which adds
119 * a timestamp and posts them back to the parent window.
120 */
121 void logTestCaseMessage(TestCase testCase, String message) {
122 int elapsed;
123 if (testCase == null) {
124 elapsed = -1;
125 } else {
126 DateTime end = new DateTime.now();
127 elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
128 }
129 parentWindow.postMessage(
130 _Message.text(_Message.LOG, elapsed, message).toString(), '*');
131 }
132
133 /**
134 * Get the elapsed time for the test, and post the test result
135 * back to the parent window. If the test failed due to an exception
136 * the stack is posted back too (before the test result).
137 */
138 void onTestResult(TestCase testCase) {
139 super.onTestResult(testCase);
140 DateTime end = new DateTime.now();
141 int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
142 if (testCase.stackTrace != null) {
143 parentWindow.postMessage(
144 _Message.text(_Message.STACK, elapsed, testCase.stackTrace), '*');
145 }
146 parentWindow.postMessage(
147 _Message.text(testCase.result, elapsed, testCase.message), '*');
148 }
149
150 void onSummary(int passed, int failed, int errors, List<TestCase> results,
151 String uncaughtError) {
152 }
153
154 void onDone(bool success) {
155 assert(_errorSubscription != null);
156 _errorSubscription.cancel();
157 _errorSubscription = null;
158 }
159 }
160
161 /**
162 * The parent configuration runs in the top-level window; it wraps the tests
163 * in new functions that create child IFrames and run the real tests.
164 */
165 class ParentHtmlConfiguration extends Configuration {
166 get autoStart => false;
167 get name => 'ParentHtmlConfiguration';
168 Map<int,DateTime> _testStarts;
169
170 /** The stack that was posted back from the child, if any. */
171 String _stack;
172
173 int _testTime;
174 /**
175 * Whether or not we have already wrapped the TestCase test functions
176 * in new closures that instead create an IFrame and get it to run the
177 * test.
178 */
179 bool _doneWrap = false;
180
181 StreamSubscription _messageSubscription, _errorSubscription;
182
183 ParentHtmlConfiguration() :
184 _testStarts = new Map<int,DateTime>();
185
186 // We need to block until the test is done, so we make a
187 // dummy async callback that we will use to flag completion.
188 Function completeTest = null;
189
190 wrapTest(TestCase testCase) {
191 String baseUrl = window.location.toString();
192 String url = '${baseUrl}?t=${testCase.id}';
193 return () {
194 // Add the child IFrame.
195 Element childDiv = document.query('#child');
196 var label = new Element.html(
197 "<pre id='result${testCase.id}'>${testCase.description}</pre>");
198 IFrameElement child = new Element.html("""
199 <iframe id='childFrame${testCase.id}' src='$url'>
200 </iframe>""");
201 childDiv.nodes.add(label);
202 childDiv.nodes.add(child);
203 completeTest = expectAsync0((){ });
204 // Kick off the test when the IFrame is loaded.
205 child.onLoad.listen((e) {
206 child.contentWindow.postMessage(_Message.text(_Message.START), '*');
207 });
208 };
209 }
210
211 void _handleMessage(MessageEvent e) {
212 // Get the result, do any logging, then do a pass/fail.
213 var msg = new _Message.fromString(e.data);
214 if (msg.messageType == _Message.LOG) {
215 logMessage(e.data);
216 } else if (msg.messageType == _Message.STACK) {
217 _stack = msg.body;
218 } else {
219 _testTime = msg.elapsed;
220 if (msg.messageType == _Message.PASS) {
221 currentTestCase.pass();
222 } else if (msg.messageType == _Message.FAIL) {
223 currentTestCase.fail(msg.body, _stack);
224 } else if (msg.messageType == _Message.ERROR) {
225 currentTestCase.error(msg.body, _stack);
226 }
227 completeTest();
228 }
229 }
230
231 void onInit() {
232 }
233
234 void onStart() {
235 // Listen for uncaught errors.
236 assert(_errorSubscription == null);
237 _errorSubscription = window.onError.listen((e) {
238 handleExternalError(e, '(DOM callback has errors)');
239 });
240
241 if (!_doneWrap) {
242 _doneWrap = true;
243 for (int i = 0; i < testCases.length; i++) {
244 testCases[i].testFunction = wrapTest(testCases[i]);
245 testCases[i].setUp = null;
246 testCases[i].tearDown = null;
247 }
248 }
249
250 _messageSubscription = window.onMessage.listen(_handleMessage);
251 }
252
253 void onTestStart(TestCase testCase) {
254 var id = testCase.id;
255 _testStarts[testCase.id]= new DateTime.now();
256 super.onTestStart(testCase);
257 _stack = null;
258 }
259
260 // Actually test logging is handled by the child, then posted
261 // back to the parent. So here we know that the [message] argument
262 // is in the format used by [_Message].
263 void logTestCaseMessage(TestCase testCase, String message) {
264 var msg = new _Message.fromString(message);
265 document.query('#otherlogs').nodes.add(
266 new Element.html('<p>${msg.body}</p>'));
267 }
268
269 void onTestResult(TestCase testCase) {
270 if (!testCase.enabled) return;
271 super.onTestResult(testCase);
272 document.query('#result${testCase.id}').text =
273 '${testCase.result}:${testCase.runningTime.inMilliseconds}:'
274 '${testCase.description}//${testCase.message}';
275 }
276
277 void onSummary(int passed, int failed, int errors, List<TestCase> results,
278 String uncaughtError) {
279 }
280 void onDone(bool success) {
281 _messageSubscription.cancel();
282 _messageSubscription = null;
283
284 _errorSubscription.cancel();
285 _errorSubscription = null;
286
287 window.postMessage('done', '*'); // Unblock DRT
288 }
289 }
290
291 /**
292 * Add the divs to the DOM if they are not present.
293 */
294 void _prepareDom() {
295 if (document.query('#otherlogs') == null) {
296 document.body.nodes.add(new Element.html(
297 "<div id='otherlogs'></div>"));
298 }
299 if (document.query('#child') == null) {
300 document.body.nodes.add(new Element.html("<div id='child'></div>"));
301 }
302 }
303
304 /**
305 * Allocate a Configuration. We allocate either a parent or
306 * child, depending on whether the URL has a search part.
307 */
308 void useHtmlLayoutConfiguration() {
309 if (config != null) return;
310 if (window.location.search == '') { // This is the parent.
311 _prepareDom();
312 configure(new ParentHtmlConfiguration());
313 } else {
314 configure(new ChildHtmlConfiguration());
315 }
316 }
317
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