michael@0: /* michael@0: Unit testing library for the OpenGL ES 2.0 HTML Canvas context michael@0: michael@0: Copyright (C) 2011 Ilmari Heikkinen michael@0: michael@0: Permission is hereby granted, free of charge, to any person michael@0: obtaining a copy of this software and associated documentation michael@0: files (the "Software"), to deal in the Software without michael@0: restriction, including without limitation the rights to use, michael@0: copy, modify, merge, publish, distribute, sublicense, and/or sell michael@0: copies of the Software, and to permit persons to whom the michael@0: Software is furnished to do so, subject to the following michael@0: conditions: michael@0: michael@0: The above copyright notice and this permission notice shall be michael@0: included in all copies or substantial portions of the Software. michael@0: michael@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, michael@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES michael@0: OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND michael@0: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT michael@0: HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, michael@0: WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING michael@0: FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR michael@0: OTHER DEALINGS IN THE SOFTWARE. michael@0: */ michael@0: Tests = { michael@0: autorun : true, michael@0: message : null, michael@0: delay : 0, michael@0: michael@0: startUnit : function(){ return []; }, michael@0: setup : function() { return arguments; }, michael@0: teardown : function() {}, michael@0: endUnit : function() {} michael@0: } michael@0: michael@0: var __testSuccess__ = true; michael@0: var __testFailCount__ = 0; michael@0: var __testLog__; michael@0: var __backlog__ = []; michael@0: michael@0: Object.toSource = function(a, seen){ michael@0: if (a == null) return "null"; michael@0: if (typeof a == 'boolean') return a ? "true" : "false"; michael@0: if (typeof a == 'string') return '"' + a.replace(/"/g, '\\"') + '"'; michael@0: if (a instanceof HTMLElement) return a.toString(); michael@0: if (a.width && a.height && a.data) return "[ImageData]"; michael@0: if (a instanceof Array) { michael@0: if (!seen) seen = []; michael@0: var idx = seen.indexOf(a); michael@0: if (idx != -1) return '#'+(idx+1)+'#'; michael@0: seen.unshift(a); michael@0: var srcs = a.map(function(o){ return Object.toSource(o,seen) }); michael@0: var prefix = ''; michael@0: idx = seen.indexOf(a); michael@0: if (idx != -1) prefix = '#'+(idx+1)+'='; michael@0: return prefix + '[' + srcs.join(", ") + ']'; michael@0: } michael@0: if (typeof a == 'object') { michael@0: if (!seen) seen = []; michael@0: var idx = seen.indexOf(a); michael@0: if (idx != -1) return '#'+(idx+1)+'#'; michael@0: seen.unshift(a); michael@0: var members = []; michael@0: var name; michael@0: try { michael@0: for (var i in a) { michael@0: if (i.search(/^[a-zA-Z0-9]+$/) != -1) michael@0: name = i; michael@0: else michael@0: name = '"' + i.replace(/"/g, '\\"') + '"'; michael@0: var ai; michael@0: try { ai = a[i]; } michael@0: catch(e) { ai = 'null /*ERROR_ACCESSING*/'; } michael@0: var s = name + ':' + Object.toSource(ai, seen); michael@0: members.push(s); michael@0: } michael@0: } catch (e) {} michael@0: var prefix = ''; michael@0: idx = seen.indexOf(a); michael@0: if (idx != -1) prefix = '#'+(idx+1)+'='; michael@0: return prefix + '{' + members.join(", ") + '}' michael@0: } michael@0: if (typeof a == 'function') michael@0: return '('+a.toString().replace(/\n/g, " ").replace(/\s+/g, " ")+')'; michael@0: return a.toString(); michael@0: } michael@0: michael@0: function formatError(e) { michael@0: if (window.console) console.log(e); michael@0: var pathSegs = location.href.toString().split("/"); michael@0: var currentDoc = e.lineNumber != null ? pathSegs[pathSegs.length - 1] : null; michael@0: var trace = (e.filename || currentDoc) + ":" + e.lineNumber + (e.trace ? "\n"+e.trace : ""); michael@0: return e.message + "\n" + trace; michael@0: } michael@0: michael@0: function runTests() { michael@0: var h = document.getElementById('test-status'); michael@0: if (h == null) { michael@0: h = document.createElement('h1'); michael@0: h.id = 'test-status'; michael@0: document.body.appendChild(h); michael@0: } michael@0: h.textContent = ""; michael@0: var log = document.getElementById('test-log'); michael@0: if (log == null) { michael@0: log = document.createElement('div'); michael@0: log.id = 'test-log'; michael@0: document.body.appendChild(log); michael@0: } michael@0: while (log.childNodes.length > 0) michael@0: log.removeChild(log.firstChild); michael@0: michael@0: var setup_args = []; michael@0: michael@0: if (Tests.startUnit != null) { michael@0: __testLog__ = document.createElement('div'); michael@0: try { michael@0: setup_args = Tests.startUnit(); michael@0: if (__testLog__.childNodes.length > 0) michael@0: log.appendChild(__testLog__); michael@0: } catch(e) { michael@0: testFailed("startUnit", formatError(e)); michael@0: log.appendChild(__testLog__); michael@0: printTestStatus(); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: var testsRun = false; michael@0: var allTestsSuccessful = true; michael@0: michael@0: for (var i in Tests) { michael@0: if (i.substring(0,4) != "test") continue; michael@0: __testLog__ = document.createElement('div'); michael@0: __testSuccess__ = true; michael@0: try { michael@0: doTestNotify (i); michael@0: var args = setup_args; michael@0: if (Tests.setup != null) michael@0: args = Tests.setup.apply(Tests, setup_args); michael@0: Tests[i].apply(Tests, args); michael@0: if (Tests.teardown != null) michael@0: Tests.teardown.apply(Tests, args); michael@0: } michael@0: catch (e) { michael@0: testFailed(i, e.name, formatError(e)); michael@0: } michael@0: if (__testSuccess__ == false) { michael@0: ++__testFailCount__; michael@0: } michael@0: var h = document.createElement('h2'); michael@0: h.textContent = i; michael@0: __testLog__.insertBefore(h, __testLog__.firstChild); michael@0: log.appendChild(__testLog__); michael@0: allTestsSuccessful = allTestsSuccessful && __testSuccess__ == true; michael@0: reportTestResultsToHarness(__testSuccess__, i); michael@0: doTestNotify (i+"--"+(__testSuccess__?"OK":"FAIL")); michael@0: testsRun = true; michael@0: } michael@0: michael@0: printTestStatus(testsRun); michael@0: if (Tests.endUnit != null) { michael@0: __testLog__ = document.createElement('div'); michael@0: try { michael@0: Tests.endUnit.apply(Tests, setup_args); michael@0: if (__testLog__.childNodes.length > 0) michael@0: log.appendChild(__testLog__); michael@0: } catch(e) { michael@0: testFailed("endUnit", e.name, formatError(e)); michael@0: log.appendChild(__testLog__); michael@0: } michael@0: } michael@0: notifyFinishedToHarness(allTestsSuccessful, "finished tests"); michael@0: } michael@0: michael@0: function doTestNotify(name) { michael@0: //try { michael@0: // var xhr = new XMLHttpRequest(); michael@0: // xhr.open("GET", "http://localhost:8888/"+name, true); michael@0: // xhr.send(null); michael@0: //} catch(e) {} michael@0: } michael@0: michael@0: function testFailed(assertName, name) { michael@0: var d = document.createElement('div'); michael@0: var h = document.createElement('h3'); michael@0: var d1 = document.createElement("span"); michael@0: h.appendChild(d1); michael@0: d1.appendChild(document.createTextNode("FAIL: ")); michael@0: d1.style.color = "red"; michael@0: h.appendChild(document.createTextNode( michael@0: name==null ? assertName : name + " (in " + assertName + ")")); michael@0: d.appendChild(h); michael@0: var args = [] michael@0: for (var i=2; i 0.95) michael@0: return hi; michael@0: else michael@0: return lo + Math.random()*(hi-lo); michael@0: } michael@0: function randomInt (sz) { michael@0: if (sz != null) michael@0: return Math.floor(Math.random()*sz); michael@0: else michael@0: return Math.floor(randomFloat()); michael@0: } michael@0: function randomIntFromRange(lo, hi) { michael@0: return Math.floor(randomFloatFromRange(lo, hi)); michael@0: } michael@0: function randomLength () { michael@0: var l = Math.floor(Math.random() * 256); michael@0: if (Math.random < 0.5) l = l / 10; michael@0: if (Math.random < 0.3) l = l / 10; michael@0: return l; michael@0: } michael@0: function randomSmallIntArray () { michael@0: var l = randomLength(); michael@0: var s = new Array(l); michael@0: for (var i=0; i