|
1 /* |
|
2 Copyright (C) 2009 Apple Computer, Inc. All rights reserved. |
|
3 |
|
4 Redistribution and use in source and binary forms, with or without |
|
5 modification, are permitted provided that the following conditions |
|
6 are met: |
|
7 1. Redistributions of source code must retain the above copyright |
|
8 notice, this list of conditions and the following disclaimer. |
|
9 2. Redistributions in binary form must reproduce the above copyright |
|
10 notice, this list of conditions and the following disclaimer in the |
|
11 documentation and/or other materials provided with the distribution. |
|
12 |
|
13 THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
|
14 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
16 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
|
17 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
18 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
19 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
20 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
21 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
24 */ |
|
25 |
|
26 // WebKit Specfic code. Add your own here. |
|
27 function initNonKhronosFramework(waitUntilDone) { |
|
28 if (window.layoutTestController) { |
|
29 layoutTestController.overridePreference("WebKitWebGLEnabled", "1"); |
|
30 layoutTestController.dumpAsText(); |
|
31 if (waitUntilDone) { |
|
32 layoutTestController.waitUntilDone(); |
|
33 } |
|
34 } |
|
35 } |
|
36 |
|
37 function nonKhronosFrameworkNotifyDone() { |
|
38 if (window.layoutTestController) { |
|
39 layoutTestController.notifyDone(); |
|
40 } |
|
41 } |
|
42 |
|
43 function reportTestResultsToHarness(success, msg) { |
|
44 if (window.parent.webglTestHarness) { |
|
45 window.parent.webglTestHarness.reportResults(success, msg); |
|
46 } |
|
47 } |
|
48 |
|
49 function notifyFinishedToHarness() { |
|
50 if (window.parent.webglTestHarness) { |
|
51 window.parent.webglTestHarness.notifyFinished(); |
|
52 } |
|
53 } |
|
54 |
|
55 function description(msg) |
|
56 { |
|
57 // For MSIE 6 compatibility |
|
58 var span = document.createElement("span"); |
|
59 span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>'; |
|
60 var description = document.getElementById("description"); |
|
61 if (description.firstChild) |
|
62 description.replaceChild(span, description.firstChild); |
|
63 else |
|
64 description.appendChild(span); |
|
65 } |
|
66 |
|
67 function debug(msg) |
|
68 { |
|
69 var span = document.createElement("span"); |
|
70 document.getElementById("console").appendChild(span); // insert it first so XHTML knows the namespace |
|
71 span.innerHTML = msg + '<br />'; |
|
72 } |
|
73 |
|
74 function escapeHTML(text) |
|
75 { |
|
76 return text.replace(/&/g, "&").replace(/</g, "<"); |
|
77 } |
|
78 |
|
79 function testPassed(msg) |
|
80 { |
|
81 reportTestResultsToHarness(true, msg); |
|
82 debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>'); |
|
83 } |
|
84 |
|
85 function testFailed(msg) |
|
86 { |
|
87 reportTestResultsToHarness(false, msg); |
|
88 debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>'); |
|
89 dump('FAIL: ' + msg + '\n'); |
|
90 |
|
91 var stack = (new Error).stack.split('\n'); |
|
92 if (!stack.length) { |
|
93 return; |
|
94 } |
|
95 |
|
96 dump('STACK TRACE: \n'); |
|
97 |
|
98 stack.pop(); |
|
99 var index = 0, frame, messages = new Array(); |
|
100 // Match all .html files and print out the line in them. |
|
101 while (stack.length && index != -1) { |
|
102 frame = stack.pop(); |
|
103 index = frame.indexOf(".html:"); |
|
104 if (index != -1) { |
|
105 messages.unshift(frame); |
|
106 } |
|
107 } |
|
108 |
|
109 // Print out the first stack frame in JS and then stop. |
|
110 if (stack.length) { |
|
111 messages.unshift(stack.pop()); |
|
112 } |
|
113 |
|
114 for (message in messages) { |
|
115 dump(messages[message] + '\n'); |
|
116 } |
|
117 } |
|
118 |
|
119 function testFailedRender(msg, ref, test, width, height) |
|
120 { |
|
121 var refData; |
|
122 if (typeof ref.getImageData == 'function') { |
|
123 refData = ref.canvas.toDataURL(); |
|
124 } else { |
|
125 refData = arrayToURLData(ref, width, height); |
|
126 } |
|
127 |
|
128 var testData; |
|
129 if (typeof test.getImageData == 'function') { |
|
130 testData = test.canvas.toDataURL(); |
|
131 } else { |
|
132 testData = arrayToURLData(test, width, height); |
|
133 } |
|
134 |
|
135 testFailed(msg); |
|
136 |
|
137 var data = 'REFTEST TEST-DEBUG-INFO | ' + msg + ' | image comparison (==)\n' + |
|
138 'REFTEST IMAGE 1 (TEST): ' + testData + '\n' + |
|
139 'REFTEST IMAGE 2 (REFERENCE): ' + refData; |
|
140 dump('FAIL: ' + data + '\n'); |
|
141 dump('To view the differences between these image renderings, go to the following link: https://hg.mozilla.org/mozilla-central/raw-file/tip/layout/tools/reftest/reftest-analyzer.xhtml#log=' + |
|
142 encodeURIComponent(encodeURIComponent(data)) + '\n'); |
|
143 } |
|
144 |
|
145 function arrayToURLData(buf, width, height) |
|
146 { |
|
147 var cv = document.createElement('canvas'); |
|
148 cv.height = height; |
|
149 cv.width = width; |
|
150 var ctx = cv.getContext('2d'); |
|
151 var imgd = ctx.getImageData(0, 0, width, height); |
|
152 for (i = 0; i < height * width; ++i) { |
|
153 offset = i * 4; |
|
154 for (j = 0; j < 4; j++) { |
|
155 imgd.data[offset + j] = buf[offset + j]; |
|
156 } |
|
157 } |
|
158 ctx.putImageData(imgd, 0, 0); |
|
159 return cv.toDataURL(); |
|
160 } |
|
161 |
|
162 function areArraysEqual(_a, _b) |
|
163 { |
|
164 try { |
|
165 if (_a.length !== _b.length) |
|
166 return false; |
|
167 for (var i = 0; i < _a.length; i++) |
|
168 if (_a[i] !== _b[i]) |
|
169 return false; |
|
170 } catch (ex) { |
|
171 return false; |
|
172 } |
|
173 return true; |
|
174 } |
|
175 |
|
176 function isMinusZero(n) |
|
177 { |
|
178 // the only way to tell 0 from -0 in JS is the fact that 1/-0 is |
|
179 // -Infinity instead of Infinity |
|
180 return n === 0 && 1/n < 0; |
|
181 } |
|
182 |
|
183 function isResultCorrect(_actual, _expected) |
|
184 { |
|
185 if (_expected === 0) |
|
186 return _actual === _expected && (1/_actual) === (1/_expected); |
|
187 if (_actual === _expected) |
|
188 return true; |
|
189 if (typeof(_expected) == "number" && isNaN(_expected)) |
|
190 return typeof(_actual) == "number" && isNaN(_actual); |
|
191 if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([])) |
|
192 return areArraysEqual(_actual, _expected); |
|
193 return false; |
|
194 } |
|
195 |
|
196 function stringify(v) |
|
197 { |
|
198 if (v === 0 && 1/v < 0) |
|
199 return "-0"; |
|
200 else return "" + v; |
|
201 } |
|
202 |
|
203 function evalAndLog(_a) |
|
204 { |
|
205 if (typeof _a != "string") |
|
206 debug("WARN: tryAndLog() expects a string argument"); |
|
207 |
|
208 // Log first in case things go horribly wrong or this causes a sync event. |
|
209 debug(_a); |
|
210 |
|
211 var _av; |
|
212 try { |
|
213 _av = eval(_a); |
|
214 } catch (e) { |
|
215 testFailed(_a + " threw exception " + e); |
|
216 } |
|
217 return _av; |
|
218 } |
|
219 |
|
220 function shouldBe(_a, _b, quiet) |
|
221 { |
|
222 if (typeof _a != "string" || typeof _b != "string") |
|
223 debug("WARN: shouldBe() expects string arguments"); |
|
224 var exception; |
|
225 var _av; |
|
226 try { |
|
227 _av = eval(_a); |
|
228 } catch (e) { |
|
229 exception = e; |
|
230 } |
|
231 var _bv = eval(_b); |
|
232 |
|
233 if (exception) |
|
234 testFailed(_a + " should be " + _bv + ". Threw exception " + exception); |
|
235 else if (isResultCorrect(_av, _bv)) { |
|
236 if (!quiet) { |
|
237 testPassed(_a + " is " + _b); |
|
238 } |
|
239 } else if (typeof(_av) == typeof(_bv)) |
|
240 testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + "."); |
|
241 else |
|
242 testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ")."); |
|
243 } |
|
244 |
|
245 function shouldNotBe(_a, _b, quiet) |
|
246 { |
|
247 if (typeof _a != "string" || typeof _b != "string") |
|
248 debug("WARN: shouldNotBe() expects string arguments"); |
|
249 var exception; |
|
250 var _av; |
|
251 try { |
|
252 _av = eval(_a); |
|
253 } catch (e) { |
|
254 exception = e; |
|
255 } |
|
256 var _bv = eval(_b); |
|
257 |
|
258 if (exception) |
|
259 testFailed(_a + " should not be " + _bv + ". Threw exception " + exception); |
|
260 else if (!isResultCorrect(_av, _bv)) { |
|
261 if (!quiet) { |
|
262 testPassed(_a + " is not " + _b); |
|
263 } |
|
264 } else |
|
265 testFailed(_a + " should not be " + _bv + "."); |
|
266 } |
|
267 |
|
268 function shouldBeTrue(_a) { shouldBe(_a, "true"); } |
|
269 function shouldBeFalse(_a) { shouldBe(_a, "false"); } |
|
270 function shouldBeNaN(_a) { shouldBe(_a, "NaN"); } |
|
271 function shouldBeNull(_a) { shouldBe(_a, "null"); } |
|
272 |
|
273 function shouldBeEqualToString(a, b) |
|
274 { |
|
275 var unevaledString = '"' + b.replace(/"/g, "\"") + '"'; |
|
276 shouldBe(a, unevaledString); |
|
277 } |
|
278 |
|
279 function shouldEvaluateTo(actual, expected) { |
|
280 // A general-purpose comparator. 'actual' should be a string to be |
|
281 // evaluated, as for shouldBe(). 'expected' may be any type and will be |
|
282 // used without being eval'ed. |
|
283 if (expected == null) { |
|
284 // Do this before the object test, since null is of type 'object'. |
|
285 shouldBeNull(actual); |
|
286 } else if (typeof expected == "undefined") { |
|
287 shouldBeUndefined(actual); |
|
288 } else if (typeof expected == "function") { |
|
289 // All this fuss is to avoid the string-arg warning from shouldBe(). |
|
290 try { |
|
291 actualValue = eval(actual); |
|
292 } catch (e) { |
|
293 testFailed("Evaluating " + actual + ": Threw exception " + e); |
|
294 return; |
|
295 } |
|
296 shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'", |
|
297 "'" + expected.toString().replace(/\n/g, "") + "'"); |
|
298 } else if (typeof expected == "object") { |
|
299 shouldBeTrue(actual + " == '" + expected + "'"); |
|
300 } else if (typeof expected == "string") { |
|
301 shouldBe(actual, expected); |
|
302 } else if (typeof expected == "boolean") { |
|
303 shouldBe("typeof " + actual, "'boolean'"); |
|
304 if (expected) |
|
305 shouldBeTrue(actual); |
|
306 else |
|
307 shouldBeFalse(actual); |
|
308 } else if (typeof expected == "number") { |
|
309 shouldBe(actual, stringify(expected)); |
|
310 } else { |
|
311 debug(expected + " is unknown type " + typeof expected); |
|
312 shouldBeTrue(actual, "'" +expected.toString() + "'"); |
|
313 } |
|
314 } |
|
315 |
|
316 function shouldBeNonZero(_a) |
|
317 { |
|
318 var exception; |
|
319 var _av; |
|
320 try { |
|
321 _av = eval(_a); |
|
322 } catch (e) { |
|
323 exception = e; |
|
324 } |
|
325 |
|
326 if (exception) |
|
327 testFailed(_a + " should be non-zero. Threw exception " + exception); |
|
328 else if (_av != 0) |
|
329 testPassed(_a + " is non-zero."); |
|
330 else |
|
331 testFailed(_a + " should be non-zero. Was " + _av); |
|
332 } |
|
333 |
|
334 function shouldBeNonNull(_a) |
|
335 { |
|
336 var exception; |
|
337 var _av; |
|
338 try { |
|
339 _av = eval(_a); |
|
340 } catch (e) { |
|
341 exception = e; |
|
342 } |
|
343 |
|
344 if (exception) |
|
345 testFailed(_a + " should be non-null. Threw exception " + exception); |
|
346 else if (_av != null) |
|
347 testPassed(_a + " is non-null."); |
|
348 else |
|
349 testFailed(_a + " should be non-null. Was " + _av); |
|
350 } |
|
351 |
|
352 function shouldBeUndefined(_a) |
|
353 { |
|
354 var exception; |
|
355 var _av; |
|
356 try { |
|
357 _av = eval(_a); |
|
358 } catch (e) { |
|
359 exception = e; |
|
360 } |
|
361 |
|
362 if (exception) |
|
363 testFailed(_a + " should be undefined. Threw exception " + exception); |
|
364 else if (typeof _av == "undefined") |
|
365 testPassed(_a + " is undefined."); |
|
366 else |
|
367 testFailed(_a + " should be undefined. Was " + _av); |
|
368 } |
|
369 |
|
370 function shouldBeDefined(_a) |
|
371 { |
|
372 var exception; |
|
373 var _av; |
|
374 try { |
|
375 _av = eval(_a); |
|
376 } catch (e) { |
|
377 exception = e; |
|
378 } |
|
379 |
|
380 if (exception) |
|
381 testFailed(_a + " should be defined. Threw exception " + exception); |
|
382 else if (_av !== undefined) |
|
383 testPassed(_a + " is defined."); |
|
384 else |
|
385 testFailed(_a + " should be defined. Was " + _av); |
|
386 } |
|
387 |
|
388 function shouldBeGreaterThanOrEqual(_a, _b) { |
|
389 if (typeof _a != "string" || typeof _b != "string") |
|
390 debug("WARN: shouldBeGreaterThanOrEqual expects string arguments"); |
|
391 |
|
392 var exception; |
|
393 var _av; |
|
394 try { |
|
395 _av = eval(_a); |
|
396 } catch (e) { |
|
397 exception = e; |
|
398 } |
|
399 var _bv = eval(_b); |
|
400 |
|
401 if (exception) |
|
402 testFailed(_a + " should be >= " + _b + ". Threw exception " + exception); |
|
403 else if (typeof _av == "undefined" || _av < _bv) |
|
404 testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ")."); |
|
405 else |
|
406 testPassed(_a + " is >= " + _b); |
|
407 } |
|
408 |
|
409 function shouldThrow(_a, _e) |
|
410 { |
|
411 var exception; |
|
412 var _av; |
|
413 try { |
|
414 _av = eval(_a); |
|
415 } catch (e) { |
|
416 exception = e; |
|
417 } |
|
418 |
|
419 var _ev; |
|
420 if (_e) |
|
421 _ev = eval(_e); |
|
422 |
|
423 if (exception) { |
|
424 if (typeof _e == "undefined" || exception == _ev) |
|
425 testPassed(_a + " threw exception " + exception + "."); |
|
426 else |
|
427 testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + "."); |
|
428 } else if (typeof _av == "undefined") |
|
429 testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined."); |
|
430 else |
|
431 testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + "."); |
|
432 } |
|
433 |
|
434 function assertMsg(assertion, msg) { |
|
435 if (assertion) { |
|
436 testPassed(msg); |
|
437 } else { |
|
438 testFailed(msg); |
|
439 } |
|
440 } |
|
441 |
|
442 function gc() { |
|
443 if (window.GCController) { |
|
444 window.GCController.collect(); |
|
445 return; |
|
446 } |
|
447 |
|
448 if (window.opera && window.opera.collect) { |
|
449 window.opera.collect(); |
|
450 return; |
|
451 } |
|
452 |
|
453 try { |
|
454 window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) |
|
455 .getInterface(Components.interfaces.nsIDOMWindowUtils) |
|
456 .garbageCollect(); |
|
457 return; |
|
458 } catch(e) {} |
|
459 |
|
460 function gcRec(n) { |
|
461 if (n < 1) |
|
462 return {}; |
|
463 var temp = {i: "ab" + i + (i / 100000)}; |
|
464 temp += "foo"; |
|
465 gcRec(n-1); |
|
466 } |
|
467 for (var i = 0; i < 1000; i++) |
|
468 gcRec(10); |
|
469 } |
|
470 |
|
471 function finishTest() { |
|
472 debug('<br /><span class="pass">TEST COMPLETE</span>'); |
|
473 notifyFinishedToHarness(); |
|
474 } |