2 Unit testing library for the OpenGL ES 2.0 HTML Canvas context
6 Copyright (c) 2019 The Khronos Group Inc.
7 Use of this source code is governed by an MIT-style license that can be
8 found in the LICENSE.txt file.
11 /* -- plaform specific code -- */
14 if (window
.testRunner
&& !window
.layoutTestController
) {
15 window
.layoutTestController
= window
.testRunner
;
18 if (window
.layoutTestController
) {
19 layoutTestController
.dumpAsText();
20 layoutTestController
.waitUntilDone();
22 // The WebKit testing system compares console output.
23 // Because the output of the WebGL Tests is GPU dependent
24 // we turn off console messages.
25 window
.console
.log = function() { };
26 window
.console
.error = function() { };
28 // RAF doesn't work in LayoutTests. Disable it so the tests will
29 // use setTimeout instead.
30 window
.requestAnimationFrame
= undefined;
31 window
.webkitRequestAnimationFrame
= undefined;
34 if (window
.internals
) {
35 window
.internals
.settings
.setWebGLErrorsToConsoleEnabled(false);
38 /* -- end platform specific code --*/
45 startUnit : function(){ return []; },
46 setup : function() { return arguments
; },
47 teardown : function() {},
48 endUnit : function() {}
51 var __testSuccess__
= true;
52 var __testFailCount__
= 0;
56 var getUrlOptions
= (function() {
57 var _urlOptionsParsed
= false;
60 if (!_urlOptionsParsed
) {
61 var s
= window
.location
.href
;
62 var q
= s
.indexOf("?");
63 var e
= s
.indexOf("#");
67 var query
= s
.substring(q
+ 1, e
);
68 var pairs
= query
.split("&");
69 for (var ii
= 0; ii
< pairs
.length
; ++ii
) {
70 var keyValue
= pairs
[ii
].split("=");
71 var key
= keyValue
[0];
72 var value
= decodeURIComponent(keyValue
[1]);
73 _urlOptions
[key
] = value
;
75 _urlOptionsParsed
= true;
82 if (typeof quietMode
== 'undefined') {
83 var quietMode
= (function() {
84 var _quietModeChecked
= false;
87 if (!_quietModeChecked
) {
88 _isQuiet
= (getUrlOptions().quiet
== 1);
89 _quietModeChecked
= true;
96 Object
.toSource = function(a
, seen
){
97 if (a
== null) return "null";
98 if (typeof a
== 'boolean') return a
? "true" : "false";
99 if (typeof a
== 'string') return '"' + a
.replace(/"/g, '\\"') + '"';
100 if (a instanceof HTMLElement) return a.toString();
101 if (a.width && a.height && a.data) return "[ImageData
]";
102 if (a instanceof Array) {
103 if (!seen) seen = [];
104 var idx = seen.indexOf(a);
105 if (idx != -1) return '#'+(idx+1)+'#';
107 var srcs = a.map(function(o){ return Object.toSource(o,seen) });
109 idx = seen.indexOf(a);
110 if (idx != -1) prefix = '#'+(idx+1)+'=';
111 return prefix + '[' + srcs.join(", ") + ']';
113 if (typeof a == 'object') {
114 if (!seen) seen = [];
115 var idx = seen.indexOf(a);
116 if (idx != -1) return '#'+(idx+1)+'#';
122 if (i.search(/^[a-zA-Z0-9]+$/) != -1)
125 name = '"' + i.replace(/"/g, '\\"') + '"';
128 catch(e) { ai = 'null /*ERROR_ACCESSING*/'; }
129 var s = name + ':' + Object.toSource(ai, seen);
134 idx = seen.indexOf(a);
135 if (idx != -1) prefix = '#'+(idx+1)+'=';
136 return prefix + '{' + members.join(", ") + '}'
138 if (typeof a == 'function')
139 return '('+a.toString().replace(/\n/g, " ").replace(/\s+/g, " ")+')';
143 function formatError(e) {
144 if (window.console) console.log(e);
145 var pathSegs = location.href.toString().split("/");
146 var currentDoc = e.lineNumber != null ? pathSegs[pathSegs.length - 1] : null;
147 var trace = (e.filename || currentDoc) + ":" + e.lineNumber + (e.trace ? "\n"+e.trace : "");
148 return e.message + "\n" + trace;
151 function runTests() {
152 var h = document.getElementById('test
-status
');
154 h = document.createElement('h1
');
155 h.id = 'test
-status
';
156 document.body.appendChild(h);
159 var log = document.getElementById('test
-log
');
161 log = document.createElement('div
');
163 document.body.appendChild(log);
165 while (log.childNodes.length > 0)
166 log.removeChild(log.firstChild);
170 if (Tests.startUnit != null) {
171 __testLog__ = document.createElement('div
');
173 setup_args = Tests.startUnit();
174 if (__testLog__.childNodes.length > 0)
175 log.appendChild(__testLog__);
177 testFailed("startUnit", formatError(e));
178 log.appendChild(__testLog__);
184 var testsRun = false;
185 var allTestsSuccessful = true;
187 for (var i in Tests) {
188 if (i.substring(0,4) != "test") continue;
189 __testLog__ = document.createElement('div
');
190 __testSuccess__ = true;
193 var args = setup_args;
194 if (Tests.setup != null)
195 args = Tests.setup.apply(Tests, setup_args);
196 Tests[i].apply(Tests, args);
197 if (Tests.teardown != null)
198 Tests.teardown.apply(Tests, args);
201 testFailed(i, e.name, formatError(e));
203 if (__testSuccess__ == false) {
206 var h = document.createElement('h2
');
208 __testLog__.insertBefore(h, __testLog__.firstChild);
209 log.appendChild(__testLog__);
210 allTestsSuccessful = allTestsSuccessful && __testSuccess__ == true;
211 reportTestResultsToHarness(__testSuccess__, i);
212 doTestNotify (i+"--"+(__testSuccess__?"OK":"FAIL"));
216 printTestStatus(testsRun);
217 if (Tests.endUnit != null) {
218 __testLog__ = document.createElement('div
');
220 Tests.endUnit.apply(Tests, setup_args);
221 if (__testLog__.childNodes.length > 0)
222 log.appendChild(__testLog__);
224 testFailed("endUnit", e.name, formatError(e));
225 log.appendChild(__testLog__);
228 notifyFinishedToHarness(allTestsSuccessful, "finished tests");
231 function doTestNotify(name) {
233 // var xhr = new XMLHttpRequest();
234 // xhr.open("GET", "http://localhost:8888/"+name, true);
239 function testFailed(assertName, name) {
240 var d = document.createElement('div
');
241 var h = document.createElement('h3
');
242 var d1 = document.createElement("span");
244 d1.appendChild(document.createTextNode("FAIL: "));
245 d1.style.color = "red";
246 h.appendChild(document.createTextNode(
247 name==null ? assertName : name + " (in " + assertName + ")"));
250 for (var i=2; i<arguments.length; i++) {
251 var a = arguments[i];
252 var p = document.createElement('p
');
253 p.style.whiteSpace = 'pre
';
254 p.textContent = (a == null) ? "null" :
255 (typeof a == 'boolean' || typeof a == 'string
') ? a : Object.toSource(a);
256 args.push(p.textContent);
259 __testLog__.appendChild(d);
260 __testSuccess__ = false;
261 doTestNotify([assertName, name].concat(args).join("--"));
264 function testPassed(assertName, name) {
266 var d = document.createElement('div
');
267 var h = document.createElement('h3
');
268 var d1 = document.createElement("span");
270 d1.appendChild(document.createTextNode("PASS: "));
271 d1.style.color = "green";
272 h.appendChild(document.createTextNode(
273 name==null ? assertName : name + " (in " + assertName + ")"));
276 for (var i=2; i<arguments.length; i++) {
277 var a = arguments[i];
278 var p = document.createElement('p
');
279 p.style.whiteSpace = 'pre
';
280 p.textContent = (a == null) ? "null" :
281 (typeof a == 'boolean' || typeof a == 'string
') ? a : Object.toSource(a);
282 args.push(p.textContent);
285 __testLog__.appendChild(d);
287 doTestNotify([assertName, name].concat(args).join("--"));
290 function checkTestSuccess() {
291 return __testFailCount__ == 0;
294 window.addEventListener('load
', function(){
295 for (var i=0; i<__backlog__.length; i++)
300 var p = document.createElement('p
');
302 for (var i=0; i<arguments.length; i++)
303 a.push(arguments[i]);
304 p.textContent = a.join(", ");
307 document.body.appendChild(p);
309 __backlog__.push(msg);
311 __testLog__.appendChild(p);
315 function printTestStatus(testsRun) {
316 var status = document.getElementById('test
-status
');
318 status.className = checkTestSuccess() ? 'ok
' : 'fail
';
319 status.textContent = checkTestSuccess() ? "PASS" : "FAIL";
321 status.className = 'fail
';
322 status.textContent = "NO TESTS FOUND";
326 function assertFail(name, f) {
327 if (f == null) { f = name; name = null; }
329 try { f(); } catch(e) { r=true; }
331 testFailed("assertFail", name, f);
334 testPassed("assertFail", name, f);
339 function assertOk(name, f) {
340 if (f == null) { f = name; name = null; }
343 try { f(); r=true; } catch(e) { err = e; }
345 testFailed("assertOk", name, f, err.toString());
348 testPassed("assertOk", name, f);
353 function assert(name, v) {
354 if (v == null) { v = name; name = null; }
356 testFailed("assert", name, v);
359 testPassed("assert", name, v);
364 function assertProperty(name, v, p) {
365 if (p == null) { p = v; v = name; name = p; }
367 testFailed("assertProperty", name);
370 testPassed("assertProperty", name);
375 function compare(a,b) {
376 if (typeof a == 'number
' && typeof b == 'number
') {
379 return Object.toSource(a) == Object.toSource(b);
383 function assertEquals(name, v, p) {
384 if (p == null) { p = v; v = name; name = null; }
385 if (!compare(v, p)) {
386 testFailed("assertEquals", name, v, p);
389 testPassed("assertEquals", name, v, p);
394 function assertArrayEquals(name, v, p) {
395 if (p == null) { p = v; v = name; name = null; }
397 testFailed("assertArrayEquals: first array undefined", name, v, p);
401 testFailed("assertArrayEquals: second array undefined", name, v, p);
404 if (v.length != p.length) {
405 testFailed("assertArrayEquals", name, v, p);
408 for (var ii = 0; ii < v.length; ++ii) {
409 if (v[ii] != p[ii]) {
410 testFailed("assertArrayEquals", name, v, p);
414 testPassed("assertArrayEquals", name, v, p);
418 function assertArrayEqualsWithEpsilon(name, v, p, l) {
419 if (l == null) { l = p; p = v; v = name; name = null; }
421 testFailed("assertArrayEqualsWithEpsilon: first array undefined", name, v, p);
425 testFailed("assertArrayEqualsWithEpsilon: second array undefined", name, v, p);
429 testFailed("assertArrayEqualsWithEpsilon: limit array undefined", name, v, p);
432 if (v.length != p.length) {
433 testFailed("assertArrayEqualsWithEpsilon", name, v, p, l);
436 if (v.length != l.length) {
437 testFailed("assertArrayEqualsWithEpsilon", name, v, p, l);
440 for (var ii = 0; ii < v.length; ++ii) {
441 if (Math.abs(v[ii]- p[ii])>l[ii]) {
442 testFailed("assertArrayEqualsWithEpsilon", name, v, p, l);
446 testPassed("assertArrayEqualsWithEpsilon", name, v, p, l);
450 function assertNotEquals(name, v, p) {
451 if (p == null) { p = v; v = name; name = null; }
453 testFailed("assertNotEquals", name, v, p)
456 testPassed("assertNotEquals", name, v, p)
461 function time(elementId, f) {
462 var s = document.getElementById(elementId);
463 var t0 = new Date().getTime();
465 var t1 = new Date().getTime();
466 s.textContent = 'Elapsed
: '+(t1-t0)+' ms
';
469 function randomFloat () {
470 // note that in fuzz-testing, this can used as the size of a buffer to allocate.
471 // so it shouldn't
return astronomic values
. The maximum value
10000000 is already quite big
.
473 var r
= Math
.random();
486 return -0.5*fac
+ Math
.random() * fac
;
488 function randomFloatFromRange(lo
, hi
) {
489 var r
= Math
.random();
495 return lo
+ Math
.random()*(hi
-lo
);
497 function randomInt (sz
) {
499 return Math
.floor(Math
.random()*sz
);
501 return Math
.floor(randomFloat());
503 function randomIntFromRange(lo
, hi
) {
504 return Math
.floor(randomFloatFromRange(lo
, hi
));
506 function randomLength () {
507 var l
= Math
.floor(Math
.random() * 256);
508 if (Math
.random
< 0.5) l
= l
/ 10;
509 if (Math
.random
< 0.3) l
= l
/ 10;
512 function randomSmallIntArray () {
513 var l
= randomLength();
514 var s
= new Array(l
);
515 for (var i
=0; i
<l
; i
++)
516 s
[i
] = Math
.floor(Math
.random() * 256)-1;
519 function randomFloatArray () {
520 var l
= randomLength();
521 var s
= new Array(l
);
522 for (var i
=0; i
<l
; i
++)
523 s
[i
] = randomFloat();
526 function randomIntArray () {
527 var l
= randomLength();
528 var s
= new Array(l
);
529 for (var i
=0; i
<l
; i
++)
530 s
[i
] = randomFloat();
533 function randomMixedArray () {
534 var l
= randomLength();
535 var s
= new Array(l
);
536 for (var i
=0; i
<l
; i
++)
537 s
[i
] = randomNonArray();
540 function randomArray () {
541 var r
= Math
.random();
543 return randomFloatArray();
545 return randomIntArray();
547 return randomSmallIntArray();
549 return randomMixedArray();
551 function randomString () {
552 return String
.fromCharCode
.apply(String
, randomSmallIntArray());
554 function randomGLConstant () {
555 return GLConstants
[Math
.floor(Math
.random() * GLConstants
.length
)];
558 function randomNonArray() {
559 var r
= Math
.random();
561 return randomFloat();
562 } else if (r
< 0.6) {
564 } else if (r
< 0.7) {
566 } else if (r
< 0.87) {
567 return randomString();
568 } else if (r
< 0.98) {
569 return randomGLConstant();
575 function generateRandomArg(pos
, count
) {
576 if (pos
== 0 && Math
.random() < 0.5)
577 return randomGLConstant();
578 if (pos
== count
-1 && Math
.random() < 0.25)
579 if (Math
.random() < 0.5)
580 return randomString();
582 return randomArray();
583 var r
= Math
.random();
585 return randomFloat();
586 } else if (r
< 0.6) {
588 } else if (r
< 0.7) {
590 } else if (r
< 0.77) {
591 return randomString();
592 } else if (r
< 0.84) {
593 return randomArray();
594 } else if (r
< 0.98) {
595 return randomGLConstant();
602 function generateRandomArgs(count
) {
603 var arr
= new Array(count
);
604 for (var i
=0; i
<count
; i
++)
605 arr
[i
] = generateRandomArg(i
, count
);
609 // qc (arg1gen, arg2gen, ..., predicate)
610 // qc (randomString, randomInt, randomInt, function(s,i,j){ s.substring(i,j) })
919 function reportTestResultsToHarness(success
, msg
) {
920 if (window
.parent
.webglTestHarness
) {
921 window
.parent
.webglTestHarness
.reportResults(window
.location
.pathname
, success
, msg
);
925 function notifyFinishedToHarness() {
926 if (window
.parent
.webglTestHarness
) {
927 window
.parent
.webglTestHarness
.notifyFinished(window
.location
.pathname
);
931 function initTests() {
932 if (Tests
.message
!= null) {
933 var h
= document
.getElementById('test-message');
935 h
= document
.createElement('p');
936 h
.id
= 'test-message';
937 document
.body
.insertBefore(h
, document
.body
.firstChild
);
939 h
.textContent
= Tests
.message
;
944 var h
= document
.getElementById('test-run');
946 h
= document
.createElement('input');
948 h
.value
= "Run tests";
949 h
.addEventListener('click', function(ev
){
954 document
.body
.insertBefore(h
, document
.body
.firstChild
);
956 h
.textContent
= Tests
.message
;
961 window
.addEventListener('load', function(){
962 if (Tests
.autoinit
) {
963 // let the browser hopefully finish updating the gl canvas surfaces if we are given a delay
965 setTimeout(initTests
, Tests
.delay
);