2010-10-19 05:50:07 +02:00
|
|
|
|
/// Copyright (c) 2009 Microsoft Corporation
|
|
|
|
|
///
|
|
|
|
|
/// Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
|
|
|
|
/// that the following conditions are met:
|
|
|
|
|
/// * Redistributions of source code must retain the above copyright notice, this list of conditions and
|
|
|
|
|
/// the following disclaimer.
|
|
|
|
|
/// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
|
|
|
|
/// the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
|
|
|
/// * Neither the name of Microsoft nor the names of its contributors may be used to
|
|
|
|
|
/// endorse or promote products derived from this software without specific prior written permission.
|
|
|
|
|
///
|
|
|
|
|
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
|
|
|
|
/// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
|
/// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
|
|
|
/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
|
/// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
|
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
|
/// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
|
|
|
/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
2010-11-02 00:28:46 +01:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/*
|
|
|
|
|
* Run a test in the browser. Works by injecting an iframe with the test code.
|
|
|
|
|
*
|
|
|
|
|
* Public Methods:
|
|
|
|
|
* * run(id, test): Runs the test specified.
|
|
|
|
|
*
|
|
|
|
|
* Callbacks:
|
|
|
|
|
* * onComplete(test): Called when the test is run. Test object contains result and error strings describing how the
|
|
|
|
|
* test ran.
|
|
|
|
|
*/
|
|
|
|
|
function BrowserRunner() {
|
|
|
|
|
var iframe, // injected iframe
|
|
|
|
|
currentTest, // Current test being run.
|
|
|
|
|
scriptCache = {}, // Holds the various includes required to run certain sputnik tests.
|
|
|
|
|
instance = this;
|
|
|
|
|
|
|
|
|
|
/* Called by the child window to notify that the test has finished. This function call is put in a separate script
|
|
|
|
|
* block at the end of the page so errors in the test script block should not prevent this function from being
|
|
|
|
|
* called.
|
|
|
|
|
*/
|
|
|
|
|
function testFinished() {
|
|
|
|
|
if(typeof currentTest.result === "undefined") {
|
|
|
|
|
// We didn't get a call to testRun, which likely means the test failed to load.
|
|
|
|
|
currentTest.result = "fail";
|
|
|
|
|
currentTest.error = "Failed to Load";
|
|
|
|
|
} else if(typeof currentTest.error !== "undefined") {
|
|
|
|
|
// We have an error logged from testRun.
|
|
|
|
|
if(currentTest.error instanceof SputnikError) {
|
|
|
|
|
currentTest.error = currentTest.message;
|
|
|
|
|
} else {
|
|
|
|
|
currentTest.error = currentTest.error.name + ": " + currentTest.error.message
|
2010-11-02 00:28:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
document.body.removeChild(iframe);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
instance.onComplete(currentTest);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Called from the child window after the test has run. */
|
|
|
|
|
function testRun(id, path, description, codeString, preconditionString, result, error) {
|
|
|
|
|
currentTest.id = id;
|
|
|
|
|
currentTest.path = path;
|
|
|
|
|
currentTest.description = description;
|
|
|
|
|
currentTest.result = result;
|
|
|
|
|
currentTest.error = error;
|
|
|
|
|
currentTest.code = codeString;
|
|
|
|
|
currentTest.pre = preconditionString;
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-02 00:28:46 +01:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Run the test. */
|
|
|
|
|
this.run = function(id, code) {
|
|
|
|
|
var includes = code.match(/\$INCLUDE\(([^\)]+)\)/g), // find all of the $INCLUDE statements
|
|
|
|
|
include;
|
|
|
|
|
|
|
|
|
|
currentTest = {id: id}; // default test, in case it doesn't get registered.
|
|
|
|
|
|
|
|
|
|
iframe = document.createElement("iframe");
|
|
|
|
|
iframe.setAttribute("style", "display:none");
|
|
|
|
|
iframe.setAttribute("id", "runnerIframe");
|
|
|
|
|
|
|
|
|
|
document.body.appendChild(iframe);
|
|
|
|
|
|
|
|
|
|
var win = window.frames[window.frames.length - 1];
|
|
|
|
|
var doc = win.document;
|
|
|
|
|
|
|
|
|
|
doc.open();
|
|
|
|
|
|
|
|
|
|
// Set up some globals.
|
|
|
|
|
win.testRun = testRun;
|
|
|
|
|
win.testFinished = testFinished;
|
2011-02-04 01:28:52 +01:00
|
|
|
|
//TODO: these should be moved to sta.js
|
2010-11-12 18:27:59 +01:00
|
|
|
|
win.SputnikError = SputnikError;
|
|
|
|
|
win.$ERROR = $ERROR;
|
|
|
|
|
win.$FAIL = $FAIL;
|
|
|
|
|
win.$PRINT = function () {};
|
|
|
|
|
win.$INCLUDE = function() {};
|
|
|
|
|
|
|
|
|
|
if(includes !== null) {
|
|
|
|
|
// We have some includes, so loop through each include and pull in the dependencies.
|
|
|
|
|
for(var i = 0; i < includes.length; i++) {
|
|
|
|
|
include = includes[i].replace(/.*\(('|")(.*)('|")\)/, "$2");
|
|
|
|
|
|
|
|
|
|
// First check to see if we have this script cached already, and if not, grab it.
|
|
|
|
|
if(typeof scriptCache[include] === "undefined") {
|
|
|
|
|
$.ajax({
|
|
|
|
|
async: false,
|
|
|
|
|
url: 'resources/scripts/global/' + include,
|
|
|
|
|
success: function(s) { scriptCache[include] = s }
|
|
|
|
|
})
|
2010-11-02 00:28:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
// Finally, write the required script to the window.
|
|
|
|
|
doc.writeln("<script type='text/javascript'>" + scriptCache[include] + "</script>");
|
2010-11-02 00:28:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-11-12 18:27:59 +01:00
|
|
|
|
|
2011-02-04 01:28:52 +01:00
|
|
|
|
//Write out all of our helper functions
|
|
|
|
|
doc.writeln("<script type='text/javascript'>" + PickledSimpleTestAPIs + "</script>");
|
|
|
|
|
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
// Write ES5Harness.registerTest and fnGlobalObject, which returns the global object, and the testFinished call.
|
|
|
|
|
doc.writeln("<script type='text/javascript'>ES5Harness = {};" +
|
|
|
|
|
"function fnGlobalObject() { return window; }" +
|
|
|
|
|
"ES5Harness.registerTest = function(test) {" +
|
|
|
|
|
" var error;" +
|
|
|
|
|
" if(test.precondition && !test.precondition()) {" +
|
2011-01-18 00:01:19 +01:00
|
|
|
|
" testRun(test.id, test.path, test.description, test.test.toString(),typeof test.precondition !== 'undefined' ? test.precondition.toString() : '', 'fail', 'Precondition Failed');" +
|
2010-11-12 18:27:59 +01:00
|
|
|
|
" } else {" +
|
|
|
|
|
" try { var res = test.test.call(window); } catch(e) { res = 'fail'; error = e; }" +
|
2011-01-18 00:01:19 +01:00
|
|
|
|
" var retVal = /^s/i.test(test.id) ? (res === true || typeof res === 'undefined' ? 'pass' : 'fail') : (res === true ? 'pass' : 'fail');" +
|
|
|
|
|
" testRun(test.id, test.path, test.description, test.test.toString(), typeof test.precondition !== 'undefined' ? test.precondition.toString() : '', retVal, error);" +
|
2010-11-12 18:27:59 +01:00
|
|
|
|
" }" +
|
|
|
|
|
"}</script>" +
|
|
|
|
|
"<script type='text/javascript'>" + code + "</script>" +
|
|
|
|
|
"<script type='text/javascript'>testFinished();</script>")
|
|
|
|
|
doc.close();
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
2010-11-12 18:27:59 +01:00
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Loads tests from the sections specified in testcaseslist.xml.
|
|
|
|
|
* Public Methods:
|
|
|
|
|
* * getNextTest() - Start loading the next test.
|
|
|
|
|
* * reset() - Start over at the first test.
|
|
|
|
|
*
|
|
|
|
|
* Callbacks:
|
|
|
|
|
* * onLoadingNextSection(path): Called after a request is sent for the next section xml, with the path to that xml.
|
|
|
|
|
* * onInitialized(totalTests, version, date): Called after the testcaseslist.xml is loaded and parsed.
|
|
|
|
|
* * onTestReady(id, code): Called when a test is ready with the test's id and code.
|
|
|
|
|
* * onTestsExhausted(): Called when there are no more tests to run.
|
|
|
|
|
*/
|
|
|
|
|
function TestLoader() {
|
|
|
|
|
var TEST_LIST_PATH = "resources/scripts/testcases/testcaseslist.xml",
|
|
|
|
|
testGroups = [],
|
|
|
|
|
testGroupIndex = 0,
|
|
|
|
|
currentTestIndex = 0,
|
|
|
|
|
loader = this;
|
|
|
|
|
|
|
|
|
|
this.version = undefined;
|
|
|
|
|
this.date = undefined;
|
|
|
|
|
this.totalTests = 0;
|
|
|
|
|
|
|
|
|
|
/* Get the XML for the next section */
|
|
|
|
|
function getNextXML() {
|
|
|
|
|
var group = testGroups[testGroupIndex];
|
|
|
|
|
currentTestIndex = 0;
|
|
|
|
|
|
|
|
|
|
if(group.tests.length > 0) {
|
|
|
|
|
// already loaded this section.
|
|
|
|
|
loader.getNextTest();
|
2010-10-19 05:50:07 +02:00
|
|
|
|
return;
|
2010-11-02 00:28:46 +01:00
|
|
|
|
}
|
2010-11-12 18:27:59 +01:00
|
|
|
|
|
|
|
|
|
$.ajax({url: group.path, dataType: 'xml', success: function(data) {
|
|
|
|
|
group.tests = data.getElementsByTagName("test");
|
|
|
|
|
loader.getNextTest();
|
|
|
|
|
}});
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onLoadingNextSection(group.path);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Get the test list xml */
|
|
|
|
|
function loadTestXML() {
|
|
|
|
|
var testsListLoader = new XMLHttpRequest();
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
$.ajax({url: TEST_LIST_PATH, dataType: 'xml', success: function(data) {
|
|
|
|
|
var oTests = data.getElementsByTagName('testGroup');
|
|
|
|
|
var testSuite = data.getElementsByTagName('testSuite');
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.version = testSuite[0].getAttribute("version");
|
|
|
|
|
loader.date = testSuite[0].getAttribute("date");
|
|
|
|
|
loader.totalTests = testSuite[0].getAttribute("numTests");
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
for (var i = 0; i < oTests.length; i++) {
|
|
|
|
|
testGroups[i] = {
|
|
|
|
|
path: (oTests[i].text != undefined) ? oTests[i].text : oTests[i].textContent,
|
|
|
|
|
tests: []
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onInitialized(loader.totalTests, loader.version, loader.date);
|
|
|
|
|
getNextXML();
|
|
|
|
|
}});
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Move on to the next test */
|
|
|
|
|
this.getNextTest = function() {
|
|
|
|
|
if(testGroups.length == 0) {
|
|
|
|
|
// Initialize.
|
|
|
|
|
loadTestXML();
|
|
|
|
|
} else if(currentTestIndex < testGroups[testGroupIndex].tests.length) {
|
|
|
|
|
// We have tests left in this test group.
|
|
|
|
|
var test = testGroups[testGroupIndex].tests[currentTestIndex++];
|
|
|
|
|
var scriptCode = (test.firstChild.text != undefined) ? test.firstChild.text : test.firstChild.textContent;
|
|
|
|
|
|
|
|
|
|
loader.onTestReady(test.getAttribute("id"), $.base64Decode(scriptCode));
|
|
|
|
|
} else if(testGroupIndex < testGroups.length - 1) {
|
|
|
|
|
// We don't have tests left in this test group, so move on to the next.
|
|
|
|
|
testGroupIndex++;
|
|
|
|
|
getNextXML();
|
|
|
|
|
} else {
|
|
|
|
|
// We're done.
|
|
|
|
|
loader.onTestsExhausted();
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Start over at the beginning */
|
|
|
|
|
this.reset = function() {
|
|
|
|
|
currentTestIndex = 0;
|
|
|
|
|
testGroupIndex = 0;
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
2010-11-12 18:27:59 +01:00
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
/* Controls test generation and running, and sends results to the presenter. */
|
|
|
|
|
function Controller() {
|
|
|
|
|
var state = 'stopped';
|
|
|
|
|
var runner = new BrowserRunner();
|
|
|
|
|
var loader = new TestLoader();
|
|
|
|
|
var controller = this;
|
2011-02-04 01:28:52 +01:00
|
|
|
|
var startTime;
|
|
|
|
|
var elapsed = 0;
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
runner.onComplete = function(test) {
|
|
|
|
|
presenter.addTestResult(test);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
if(state === 'running')
|
|
|
|
|
setTimeout(loader.getNextTest, 10);
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onInitialized = function(totalTests, version, date) {
|
|
|
|
|
presenter.setVersion(version);
|
|
|
|
|
presenter.setDate(date);
|
|
|
|
|
presenter.setTotalTests(totalTests);
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onLoadingNextSection = function(path) {
|
|
|
|
|
presenter.updateStatus("Loading: " + path);
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onTestReady = function(id, test) {
|
|
|
|
|
presenter.updateStatus("Executing Test: " + id);
|
|
|
|
|
runner.run(id, test);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.onTestsExhausted = function() {
|
|
|
|
|
state = 'stopped';
|
2011-02-04 01:28:52 +01:00
|
|
|
|
elapsed += new Date() - startTime;
|
|
|
|
|
elapsed = elapsed/(1000*60); //minutes
|
|
|
|
|
elapsed = elapsed.toFixed(1);
|
|
|
|
|
presenter.finished(elapsed);
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
this.start = function() {
|
|
|
|
|
state = 'running';
|
2011-02-04 01:28:52 +01:00
|
|
|
|
startTime = new Date();
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.getNextTest();
|
|
|
|
|
presenter.started();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.pause = function() {
|
2011-02-04 01:28:52 +01:00
|
|
|
|
elapsed += new Date() - startTime;
|
2010-11-12 18:27:59 +01:00
|
|
|
|
state = 'paused';
|
|
|
|
|
presenter.paused();
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
this.reset = function() {
|
2011-02-04 01:28:52 +01:00
|
|
|
|
startTime = new Date();
|
|
|
|
|
elapsed = 0;
|
2010-11-12 18:27:59 +01:00
|
|
|
|
loader.reset();
|
|
|
|
|
presenter.reset();
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
this.toggle = function() {
|
|
|
|
|
if(state === 'running') {
|
|
|
|
|
controller.pause();
|
|
|
|
|
} else {
|
|
|
|
|
controller.start();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-10-19 05:50:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
var controller = new Controller()
|
|
|
|
|
|
2011-02-08 18:42:59 +01:00
|
|
|
|
/* Helper function which shows if we're in the 'debug' mode of the Test262 site.
|
|
|
|
|
This mode is only useful for debugging issues with the test harness and
|
|
|
|
|
website. */
|
|
|
|
|
function isSiteDebugMode() {
|
|
|
|
|
var str=window.location.href.substring(window.location.href.indexOf("?")+1)
|
|
|
|
|
if(str.indexOf("sitedebug") > -1) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-11-12 18:27:59 +01:00
|
|
|
|
$(function () {
|
|
|
|
|
presenter.setup();
|
|
|
|
|
|
|
|
|
|
$('.content-home').show();
|
|
|
|
|
// Adding attribute to the tabs (e.g. Home, Run etc.) and attaching the click event on buttons (e.g. Reset, Start etc.)
|
|
|
|
|
$('.nav-link').each(function (index) {
|
|
|
|
|
//Adding "targetDiv" attribute to the header tab and on that basis the div related to header tabs are displayed
|
|
|
|
|
if (index === 0) {
|
|
|
|
|
$(this).attr('targetDiv', '.content-home');
|
|
|
|
|
} else if (index === 1) {
|
|
|
|
|
$(this).attr('targetDiv', '.content-tests');
|
|
|
|
|
} else if (index === 2) {
|
|
|
|
|
$(this).attr('targetDiv', '.content-results');
|
|
|
|
|
$(this).attr('testRunning', 'false');
|
|
|
|
|
} else if (index === 3) {
|
|
|
|
|
$(this).attr('targetDiv', '.content-dev');
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$(this).attr('targetDiv', '.content-browsers');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Attaching the click event to the header tab that shows the respective div of header
|
|
|
|
|
$(this).click(function () {
|
|
|
|
|
var target = $(this).attr('targetDiv');
|
|
|
|
|
$('#contentContainer > div:visible').hide();
|
|
|
|
|
$('.navBar .selected').toggleClass('selected');
|
|
|
|
|
$(this).addClass('selected');
|
|
|
|
|
$(target).show();
|
|
|
|
|
|
|
|
|
|
//If clicked tab is Result, it generates the results.
|
|
|
|
|
if ($(target).hasClass('content-results')) {
|
|
|
|
|
presenter.refresh();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//Attach the click event to the start button. It starts, stops and pauses the tests
|
|
|
|
|
$('.button-start').click(function () {
|
|
|
|
|
controller.toggle();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//Attach the click event to the reset button. It reset all the test to zero
|
|
|
|
|
$('.button-reset').click(function () {
|
|
|
|
|
controller.reset();
|
|
|
|
|
});
|
|
|
|
|
});
|