<commit_before>/*
* Copyright 2004 ThoughtWorks, Inc
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

// An object representing the current test, used external
var currentTest = null; // TODO: get rid of this global, which mirrors the htmlTestRunner.currentTest
var selenium = null;

var htmlTestRunner;
var HtmlTestRunner = classCreate();
objectExtend(HtmlTestRunner.prototype, {
    initialize: function() {
        this.metrics = new Metrics();
        this.controlPanel = new HtmlTestRunnerControlPanel();
        this.testFailed = false;
        this.currentTest = null;
        this.runAllTests = false;
        this.appWindow = null;
        // we use a timeout here to make sure the LOG has loaded first, so we can see _every_ error
        setTimeout(fnBind(function() {
            this.loadSuiteFrame();
        }, this), 500);
    },

    getTestSuite: function() {
        return suiteFrame.getCurrentTestSuite();
    },

    markFailed: function() {
        this.testFailed = true;
        this.getTestSuite().markFailed();
    },

    loadSuiteFrame: function() {
        if (selenium == null) {
            selenium = Selenium.createForWindow(this._getApplicationWindow());
            this._registerCommandHandlers();
        }
        this.controlPanel.setHighlightOption();
        var testSuiteName = this.controlPanel.getTestSuiteName();
        if (testSuiteName) {
            suiteFrame.load(testSuiteName, fnBind(this._onloadTestSuite, this));
        }
    },

    _getApplicationWindow: function () {
        if (this.controlPanel.isMultiWindowMode()) {
            return this._getSeparateApplicationWindow();
        }
        return $('myiframe').contentWindow;
    },

    _getSeparateApplicationWindow: function () {
        if (this.appWindow == null) {
            this.appWindow = openSeparateApplicationWindow('TestRunner-splash.html');
        }
        return this.appWindow;
    },

    _onloadTestSuite:function () {
        if (! this.getTestSuite().isAvailable()) {
            return;
        }
        if (this.controlPanel.isAutomatedRun()) {
            this.startTestSuite();
        } else if (this.controlPanel.getAutoUrl()) {
            //todo what is the autourl doing, left to check it out
            addLoadListener(this._getApplicationWindow(), fnBind(this._startSingleTest, this));
            this._getApplicationWindow().src = this.controlPanel.getAutoUrl();
        } else {
            this.getTestSuite().getSuiteRows()[0].loadTestCase();
        }
    },

    _startSingleTest:function () {
        removeLoadListener(getApplicationWindow(), fnBind(this._startSingleTest, this));
        var singleTestName = this.controlPanel.getSingleTestName();
        testFrame.load(singleTestName, fnBind(this.startTest, this));
    },

    _registerCommandHandlers: function () {
        this.commandFactory = new CommandHandlerFactory();
        this.commandFactory.registerAll(selenium);
    },

    startTestSuite: function() {
        this.controlPanel.reset();
        this.metrics.resetMetrics();
        this.getTestSuite().reset();
        this.runAllTests = true;
        this.runNextTest();
    },

    runNextTest: function () {
        this.getTestSuite().updateSuiteWithResultOfPreviousTest();
        if (!this.runAllTests) {
            return;
        }
        this.getTestSuite().runNextTestInSuite();
    },

    startTest: function () {
        this.controlPanel.reset();
        testFrame.scrollToTop();
        //todo: move testFailed and storedVars to TestCase
        this.testFailed = false;
        storedVars = new Object();
        this.currentTest = new HtmlRunnerTestLoop(testFrame.getCurrentTestCase(), this.metrics, this.commandFactory);
        currentTest = this.currentTest;
        this.currentTest.start();
    },

    runSingleTest:function() {
        this.runAllTests = false;
        this.metrics.resetMetrics();
        this.startTest();
    }
});

var runInterval = 0;

/** SeleniumFrame encapsulates an iframe element */
var SeleniumFrame = classCreate();
objectExtend(SeleniumFrame.prototype, {

    initialize : function(frame) {
        this.frame = frame;
        addLoadListener(this.frame, fnBind(this._handleLoad, this));
    },

    getDocument : function() {
        return this.frame.contentWindow.document;
    },

    _handleLoad: function() {
        this._attachStylesheet();
        this._onLoad();
        if (this.loadCallback) {
            this.loadCallback();
            this.loadCallback = null;
        }
    },

    _attachStylesheet: function() {
        var d = this.getDocument();
        var head = d.getElementsByTagName('head').item(0);
        var styleLink = d.createElement("link");
        styleLink.rel = "stylesheet";
        styleLink.type = "text/css";
        styleLink.href = window.location.pathname.replace(/[^\/\\]+$/, "selenium-test.css");
        head.appendChild(styleLink);
    },

    _onLoad: function() {
    },

    scrollToTop : function() {
        this.frame.contentWindow.scrollTo(0, 0);
    },

    _setLocation: function(location) {
        if (browserVersion.isSafari) {
            // safari doesn't reload the page when the location equals to current location.
            // hence, set the location to blank so that the page will reload automatically.
            this.frame.src = "about:blank";
            this.frame.src = location;
        } else {
            this.frame.contentWindow.location.replace(location);
        }
    },

    load: function(/* url, [callback] */) {
        if (arguments.length > 1) {
            this.loadCallback = arguments[1];

        }
        this._setLocation(arguments[0]);
    }

});

/** HtmlTestSuiteFrame - encapsulates the suite iframe element */
var HtmlTestSuiteFrame = classCreate();
objectExtend(HtmlTestSuiteFrame.prototype, SeleniumFrame.prototype);
objectExtend(HtmlTestSuiteFrame.prototype, {

    _onLoad: function() {
        this.currentTestSuite = new HtmlTestSuite(this.getDocument());
    },

    getCurrentTestSuite: function() {
        return this.currentTestSuite;
    }

});

/** HtmlTestFrame - encapsulates the test-case iframe element */
var HtmlTestFrame = classCreate();
objectExtend(HtmlTestFrame.prototype, SeleniumFrame.prototype);
objectExtend(HtmlTestFrame.prototype, {

    _onLoad: function() {
        this.currentTestCase = new HtmlTestCase(this.getDocument(), htmlTestRunner.getTestSuite().getCurrentRow());
    },

    getCurrentTestCase: function() {
        return this.currentTestCase;
    }

});

function onSeleniumLoad() {
    suiteFrame = new HtmlTestSuiteFrame(getSuiteFrame());
    testFrame = new HtmlTestFrame(getTestFrame());
    htmlTestRunner = new HtmlTestRunner();
}

var suiteFrame;
var testFrame;

function getSuiteFrame() {
    var f = $('testSuiteFrame');
    if (f == null) {
        f = top;
        // proxyInjection mode does not set myiframe
    }
    return f;
}

function getTestFrame() {
    var f = $('testFrame');
    if (f == null) {
        f = top;
        // proxyInjection mode does not set myiframe
    }
    return f;
}

var HtmlTestRunnerControlPanel = classCreate();
objectExtend(HtmlTestRunnerControlPanel.prototype, URLConfiguration.prototype);
objectExtend(HtmlTestRunnerControlPanel.prototype, {
    initialize: function() {
        this._acquireQueryString();

        this.runInterval = 0;

        this.highlightOption = $('highlightOption');
        this.pauseButton = $('pauseTest');
        this.stepButton = $('stepTest');

        this.highlightOption.onclick = fnBindAsEventListener((function() {
            this.setHighlightOption();
        }), this);
        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);
        this.stepButton.onclick = fnBindAsEventListener(this.stepCurrentTest, this);


        this.speedController = new Control.Slider('speedHandle', 'speedTrack', {
            range: $R(0, 1000),
            onSlide: fnBindAsEventListener(this.setRunInterval, this),
            onChange: fnBindAsEventListener(this.setRunInterval, this)
        });

        this._parseQueryParameter();
    },

    setHighlightOption: function () {
        var isHighlight = this.highlightOption.checked;
        selenium.browserbot.getCurrentPage().setHighlightElement(isHighlight);
    },

    _parseQueryParameter: function() {
        var tempRunInterval = this._getQueryParameter("runInterval");
        if (tempRunInterval) {
            this.setRunInterval(tempRunInterval);
        }
        this.highlightOption.checked = this._getQueryParameter("highlight");
    },

    setRunInterval: function(runInterval) {
        this.runInterval = runInterval;
    },

    setToPauseAtNextCommand: function() {
        this.runInterval = -1;
    },

    pauseCurrentTest: function () {
        this.setToPauseAtNextCommand();
        this._switchPauseButtonToContinue();
    },

    continueCurrentTest: function () {
        this.reset();
        currentTest.resume();
    },

    reset: function() {
        // this.runInterval = this.speedController.value;
        this._switchContinueButtonToPause();
    },

    _switchContinueButtonToPause: function() {
        this.pauseButton.className = "cssPauseTest";
        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);
    },

    _switchPauseButtonToContinue: function() {
        $('stepTest').disabled = false;
        this.pauseButton.className = "cssContinueTest";
        this.pauseButton.onclick = fnBindAsEventListener(this.continueCurrentTest, this);
    },

    stepCurrentTest: function () {
        this.setToPauseAtNextCommand();
        currentTest.resume();
    },

    isAutomatedRun: function() {
        return this._isQueryParameterTrue("auto");
    },

    shouldSaveResultsToFile: function() {
        return this._isQueryParameterTrue("save");
    },

    closeAfterTests: function() {
        return this._isQueryParameterTrue("close");
    },

    getTestSuiteName: function() {
        return this._getQueryParameter("test");
    },

    getSingleTestName: function() {
        return this._getQueryParameter("singletest");
    },

    getAutoUrl: function() {
        return this._getQueryParameter("autoURL");
    },

    getResultsUrl: function() {
        return this._getQueryParameter("resultsUrl");
    },

    _acquireQueryString: function() {
        if (this.queryString) return;
        if (browserVersion.isHTA) {
            var args = this._extractArgs();
            if (args.length < 2) return null;
            this.queryString = args[1];
        } else {
            this.queryString = location.search.substr(1);
        }
    }

});

var AbstractResultAwareRow = classCreate();
objectExtend(AbstractResultAwareRow.prototype, {

    initialize: function(trElement) {
        this.trElement = trElement;
    },

    setStatus: function(status) {
        this.unselect();
        this.trElement.className = this.trElement.className.replace(/status_[a-z]+/, "");
        if (status) {
            addClassName(this.trElement, "status_" + status);
        }
    },

    select: function() {
        addClassName(this.trElement, "selected");
        safeScrollIntoView(this.trElement);
    },

    unselect: function() {
        removeClassName(this.trElement, "selected");
    },

    markPassed: function() {
        this.setStatus("passed");
    },

    markDone: function() {
        this.setStatus("done");
    },

    markFailed: function() {
        this.setStatus("failed");
    }

});

var TitleRow = classCreate();
objectExtend(TitleRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(TitleRow.prototype, {

    initialize: function(trElement) {
        this.trElement = trElement;
        trElement.className = "title";
    }

});

var HtmlTestCaseRow = classCreate();
objectExtend(HtmlTestCaseRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(HtmlTestCaseRow.prototype, {

    getCommand: function () {
        return new SeleniumCommand(getText(this.trElement.cells[0]),
                getText(this.trElement.cells[1]),
                getText(this.trElement.cells[2]),
                this.isBreakpoint());
    },

    markFailed: function(errorMsg) {
        AbstractResultAwareRow.prototype.markFailed.call(this, errorMsg);
        this.setMessage(errorMsg);
    },

    setMessage: function(message) {
        setText(this.trElement.cells[2], message);
    },

    reset: function() {
        this.setStatus(null);
        var thirdCell = this.trElement.cells[2];
        if (thirdCell) {
            if (thirdCell.originalHTML) {
                thirdCell.innerHTML = thirdCell.originalHTML;
            } else {
                thirdCell.originalHTML = thirdCell.innerHTML;
            }
        }
    },

    onClick: function() {
        if (this.trElement.isBreakpoint == undefined) {
            this.trElement.isBreakpoint = true;
            addClassName(this.trElement, "breakpoint");
        } else {
            this.trElement.isBreakpoint = undefined;
            removeClassName(this.trElement, "breakpoint");
        }
    },

    addBreakpointSupport: function() {
        elementSetStyle(this.trElement, {"cursor" : "pointer"});
        this.trElement.onclick = fnBindAsEventListener(function() {
            this.onClick();
        }, this);
    },

    isBreakpoint: function() {
        if (this.trElement.isBreakpoint == undefined || this.trElement.isBreakpoint == null) {
            return false
        }
        return this.trElement.isBreakpoint;
    }
});

var HtmlTestSuiteRow = classCreate();
objectExtend(HtmlTestSuiteRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(HtmlTestSuiteRow.prototype, {

    initialize: function(trElement, testFrame, htmlTestSuite) {
        this.trElement = trElement;
        this.testFrame = testFrame;
        this.htmlTestSuite = htmlTestSuite;
        this.link = trElement.getElementsByTagName("a")[0];
        this.link.onclick = fnBindAsEventListener(this._onClick, this);
    },

    reset: function() {
        this.setStatus(null);
    },

    _onClick: function() {
        this.loadTestCase(null);
        return false;
    },

    loadTestCase: function(onloadFunction) {
        this.htmlTestSuite.unselectCurrentRow();
        this.select();
        this.htmlTestSuite.currentRowInSuite = this.trElement.rowIndex - 1;
        // If the row has a stored results table, use that
        var resultsFromPreviousRun = this.trElement.cells[1];
        if (resultsFromPreviousRun) {
            // todo: delegate to TestFrame, e.g.
            //   this.testFrame.restoreTestCase(resultsFromPreviousRun.innerHTML);
            var testBody = this.testFrame.getDocument().body;
            testBody.innerHTML = resultsFromPreviousRun.innerHTML;
            this.testFrame._onLoad();
            if (onloadFunction) {
                onloadFunction();
            }
        } else {
            this.testFrame.load(this.link.href, onloadFunction);
        }
    },

    saveTestResults: function() {
        // todo: GLOBAL ACCESS!
        var resultHTML = this.testFrame.getDocument().body.innerHTML;
        if (!resultHTML) return;

        // todo: why create this div?
        var divElement = this.trElement.ownerDocument.createElement("div");
        divElement.innerHTML = resultHTML;

        var hiddenCell = this.trElement.ownerDocument.createElement("td");
        hiddenCell.appendChild(divElement);
        hiddenCell.style.display = "none";

        this.trElement.appendChild(hiddenCell);
    }

});

var HtmlTestSuite = classCreate();
objectExtend(HtmlTestSuite.prototype, {

    initialize: function(suiteDocument) {
        this.suiteDocument = suiteDocument;
        this.suiteRows = this._collectSuiteRows();
        this.titleRow = new TitleRow(this.getTestTable().rows[0]);
        this.reset();
    },

    reset: function() {
        this.failed = false;
        this.currentRowInSuite = -1;
        this.titleRow.setStatus(null);
        for (var i = 0; i < this.suiteRows.length; i++) {
            var row = this.suiteRows[i];
            row.reset();
        }
    },

    getSuiteRows: function() {
        return this.suiteRows;
    },

    getTestTable: function() {
        var tables = $A(this.suiteDocument.getElementsByTagName("table"));
        return tables[0];
    },

    isAvailable: function() {
        return this.getTestTable() != null;
    },

    _collectSuiteRows: function () {
        var result = [];
        for (rowNum = 1; rowNum < this.getTestTable().rows.length; rowNum++) {
            var rowElement = this.getTestTable().rows[rowNum];
            result.push(new HtmlTestSuiteRow(rowElement, testFrame, this));
        }
        return result;
    },

    getCurrentRow: function() {<commit_msg>Fixed bug where you'd get Permission Denied when refreshing Selenium Core.  Also fixed a bug where the "skipped" tests couldn't be run manually.<commit_after>/*
* Copyright 2004 ThoughtWorks, Inc
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

// An object representing the current test, used external
var currentTest = null; // TODO: get rid of this global, which mirrors the htmlTestRunner.currentTest
var selenium = null;

var htmlTestRunner;
var HtmlTestRunner = classCreate();
objectExtend(HtmlTestRunner.prototype, {
    initialize: function() {
        this.metrics = new Metrics();
        this.controlPanel = new HtmlTestRunnerControlPanel();
        this.testFailed = false;
        this.currentTest = null;
        this.runAllTests = false;
        this.appWindow = null;
        // we use a timeout here to make sure the LOG has loaded first, so we can see _every_ error
        setTimeout(fnBind(function() {
            this.loadSuiteFrame();
        }, this), 500);
    },

    getTestSuite: function() {
        return suiteFrame.getCurrentTestSuite();
    },

    markFailed: function() {
        this.testFailed = true;
        this.getTestSuite().markFailed();
    },

    loadSuiteFrame: function() {
        if (selenium == null) {
            var appWindow = this._getApplicationWindow();
            try { appWindow.location; }
            catch (e) { 
                // when reloading, we may be pointing at an old window (Perm Denied)
                setTimeout(fnBind(function() {
                    this.loadSuiteFrame();
                }, this), 500);
                return;
            }
            selenium = Selenium.createForWindow(appWindow);
            this._registerCommandHandlers();
        }
        this.controlPanel.setHighlightOption();
        var testSuiteName = this.controlPanel.getTestSuiteName();
        if (testSuiteName) {
            suiteFrame.load(testSuiteName, fnBind(this._onloadTestSuite, this));
        }
    },

    _getApplicationWindow: function () {
        if (this.controlPanel.isMultiWindowMode()) {
            return this._getSeparateApplicationWindow();
        }
        return $('myiframe').contentWindow;
    },

    _getSeparateApplicationWindow: function () {
        if (this.appWindow == null) {
            this.appWindow = openSeparateApplicationWindow('TestRunner-splash.html');
        }
        return this.appWindow;
    },

    _onloadTestSuite:function () {
        if (! this.getTestSuite().isAvailable()) {
            return;
        }
        if (this.controlPanel.isAutomatedRun()) {
            this.startTestSuite();
        } else if (this.controlPanel.getAutoUrl()) {
            //todo what is the autourl doing, left to check it out
            addLoadListener(this._getApplicationWindow(), fnBind(this._startSingleTest, this));
            this._getApplicationWindow().src = this.controlPanel.getAutoUrl();
        } else {
            this.getTestSuite().getSuiteRows()[0].loadTestCase();
        }
    },

    _startSingleTest:function () {
        removeLoadListener(getApplicationWindow(), fnBind(this._startSingleTest, this));
        var singleTestName = this.controlPanel.getSingleTestName();
        testFrame.load(singleTestName, fnBind(this.startTest, this));
    },

    _registerCommandHandlers: function () {
        this.commandFactory = new CommandHandlerFactory();
        this.commandFactory.registerAll(selenium);
    },

    startTestSuite: function() {
        this.controlPanel.reset();
        this.metrics.resetMetrics();
        this.getTestSuite().reset();
        this.runAllTests = true;
        this.runNextTest();
    },

    runNextTest: function () {
        this.getTestSuite().updateSuiteWithResultOfPreviousTest();
        if (!this.runAllTests) {
            return;
        }
        this.getTestSuite().runNextTestInSuite();
    },

    startTest: function () {
        this.controlPanel.reset();
        testFrame.scrollToTop();
        //todo: move testFailed and storedVars to TestCase
        this.testFailed = false;
        storedVars = new Object();
        this.currentTest = new HtmlRunnerTestLoop(testFrame.getCurrentTestCase(), this.metrics, this.commandFactory);
        currentTest = this.currentTest;
        this.currentTest.start();
    },

    runSingleTest:function() {
        this.runAllTests = false;
        this.metrics.resetMetrics();
        this.startTest();
    }
});

var runInterval = 0;

/** SeleniumFrame encapsulates an iframe element */
var SeleniumFrame = classCreate();
objectExtend(SeleniumFrame.prototype, {

    initialize : function(frame) {
        this.frame = frame;
        addLoadListener(this.frame, fnBind(this._handleLoad, this));
    },

    getDocument : function() {
        return this.frame.contentWindow.document;
    },

    _handleLoad: function() {
        this._attachStylesheet();
        this._onLoad();
        if (this.loadCallback) {
            this.loadCallback();
            this.loadCallback = null;
        }
    },

    _attachStylesheet: function() {
        var d = this.getDocument();
        var head = d.getElementsByTagName('head').item(0);
        var styleLink = d.createElement("link");
        styleLink.rel = "stylesheet";
        styleLink.type = "text/css";
        styleLink.href = window.location.pathname.replace(/[^\/\\]+$/, "selenium-test.css");
        head.appendChild(styleLink);
    },

    _onLoad: function() {
    },

    scrollToTop : function() {
        this.frame.contentWindow.scrollTo(0, 0);
    },

    _setLocation: function(location) {
        if (browserVersion.isSafari) {
            // safari doesn't reload the page when the location equals to current location.
            // hence, set the location to blank so that the page will reload automatically.
            this.frame.src = "about:blank";
            this.frame.src = location;
        } else {
            this.frame.contentWindow.location.replace(location);
        }
    },

    load: function(/* url, [callback] */) {
        if (arguments.length > 1) {
            this.loadCallback = arguments[1];

        }
        this._setLocation(arguments[0]);
    }

});

/** HtmlTestSuiteFrame - encapsulates the suite iframe element */
var HtmlTestSuiteFrame = classCreate();
objectExtend(HtmlTestSuiteFrame.prototype, SeleniumFrame.prototype);
objectExtend(HtmlTestSuiteFrame.prototype, {

    _onLoad: function() {
        this.currentTestSuite = new HtmlTestSuite(this.getDocument());
    },

    getCurrentTestSuite: function() {
        return this.currentTestSuite;
    }

});

/** HtmlTestFrame - encapsulates the test-case iframe element */
var HtmlTestFrame = classCreate();
objectExtend(HtmlTestFrame.prototype, SeleniumFrame.prototype);
objectExtend(HtmlTestFrame.prototype, {

    _onLoad: function() {
        this.currentTestCase = new HtmlTestCase(this.getDocument(), htmlTestRunner.getTestSuite().getCurrentRow());
    },

    getCurrentTestCase: function() {
        return this.currentTestCase;
    }

});

function onSeleniumLoad() {
    suiteFrame = new HtmlTestSuiteFrame(getSuiteFrame());
    testFrame = new HtmlTestFrame(getTestFrame());
    htmlTestRunner = new HtmlTestRunner();
}

var suiteFrame;
var testFrame;

function getSuiteFrame() {
    var f = $('testSuiteFrame');
    if (f == null) {
        f = top;
        // proxyInjection mode does not set myiframe
    }
    return f;
}

function getTestFrame() {
    var f = $('testFrame');
    if (f == null) {
        f = top;
        // proxyInjection mode does not set myiframe
    }
    return f;
}

var HtmlTestRunnerControlPanel = classCreate();
objectExtend(HtmlTestRunnerControlPanel.prototype, URLConfiguration.prototype);
objectExtend(HtmlTestRunnerControlPanel.prototype, {
    initialize: function() {
        this._acquireQueryString();

        this.runInterval = 0;

        this.highlightOption = $('highlightOption');
        this.pauseButton = $('pauseTest');
        this.stepButton = $('stepTest');

        this.highlightOption.onclick = fnBindAsEventListener((function() {
            this.setHighlightOption();
        }), this);
        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);
        this.stepButton.onclick = fnBindAsEventListener(this.stepCurrentTest, this);


        this.speedController = new Control.Slider('speedHandle', 'speedTrack', {
            range: $R(0, 1000),
            onSlide: fnBindAsEventListener(this.setRunInterval, this),
            onChange: fnBindAsEventListener(this.setRunInterval, this)
        });

        this._parseQueryParameter();
    },

    setHighlightOption: function () {
        var isHighlight = this.highlightOption.checked;
        selenium.browserbot.getCurrentPage().setHighlightElement(isHighlight);
    },

    _parseQueryParameter: function() {
        var tempRunInterval = this._getQueryParameter("runInterval");
        if (tempRunInterval) {
            this.setRunInterval(tempRunInterval);
        }
        this.highlightOption.checked = this._getQueryParameter("highlight");
    },

    setRunInterval: function(runInterval) {
        this.runInterval = runInterval;
    },

    setToPauseAtNextCommand: function() {
        this.runInterval = -1;
    },

    pauseCurrentTest: function () {
        this.setToPauseAtNextCommand();
        this._switchPauseButtonToContinue();
    },

    continueCurrentTest: function () {
        this.reset();
        currentTest.resume();
    },

    reset: function() {
        // this.runInterval = this.speedController.value;
        this._switchContinueButtonToPause();
    },

    _switchContinueButtonToPause: function() {
        this.pauseButton.className = "cssPauseTest";
        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);
    },

    _switchPauseButtonToContinue: function() {
        $('stepTest').disabled = false;
        this.pauseButton.className = "cssContinueTest";
        this.pauseButton.onclick = fnBindAsEventListener(this.continueCurrentTest, this);
    },

    stepCurrentTest: function () {
        this.setToPauseAtNextCommand();
        currentTest.resume();
    },

    isAutomatedRun: function() {
        return this._isQueryParameterTrue("auto");
    },

    shouldSaveResultsToFile: function() {
        return this._isQueryParameterTrue("save");
    },

    closeAfterTests: function() {
        return this._isQueryParameterTrue("close");
    },

    getTestSuiteName: function() {
        return this._getQueryParameter("test");
    },

    getSingleTestName: function() {
        return this._getQueryParameter("singletest");
    },

    getAutoUrl: function() {
        return this._getQueryParameter("autoURL");
    },

    getResultsUrl: function() {
        return this._getQueryParameter("resultsUrl");
    },

    _acquireQueryString: function() {
        if (this.queryString) return;
        if (browserVersion.isHTA) {
            var args = this._extractArgs();
            if (args.length < 2) return null;
            this.queryString = args[1];
        } else {
            this.queryString = location.search.substr(1);
        }
    }

});

var AbstractResultAwareRow = classCreate();
objectExtend(AbstractResultAwareRow.prototype, {

    initialize: function(trElement) {
        this.trElement = trElement;
    },

    setStatus: function(status) {
        this.unselect();
        this.trElement.className = this.trElement.className.replace(/status_[a-z]+/, "");
        if (status) {
            addClassName(this.trElement, "status_" + status);
        }
    },

    select: function() {
        addClassName(this.trElement, "selected");
        safeScrollIntoView(this.trElement);
    },

    unselect: function() {
        removeClassName(this.trElement, "selected");
    },

    markPassed: function() {
        this.setStatus("passed");
    },

    markDone: function() {
        this.setStatus("done");
    },

    markFailed: function() {
        this.setStatus("failed");
    }

});

var TitleRow = classCreate();
objectExtend(TitleRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(TitleRow.prototype, {

    initialize: function(trElement) {
        this.trElement = trElement;
        trElement.className = "title";
    }

});

var HtmlTestCaseRow = classCreate();
objectExtend(HtmlTestCaseRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(HtmlTestCaseRow.prototype, {

    getCommand: function () {
        return new SeleniumCommand(getText(this.trElement.cells[0]),
                getText(this.trElement.cells[1]),
                getText(this.trElement.cells[2]),
                this.isBreakpoint());
    },

    markFailed: function(errorMsg) {
        AbstractResultAwareRow.prototype.markFailed.call(this, errorMsg);
        this.setMessage(errorMsg);
    },

    setMessage: function(message) {
        setText(this.trElement.cells[2], message);
    },

    reset: function() {
        this.setStatus(null);
        var thirdCell = this.trElement.cells[2];
        if (thirdCell) {
            if (thirdCell.originalHTML) {
                thirdCell.innerHTML = thirdCell.originalHTML;
            } else {
                thirdCell.originalHTML = thirdCell.innerHTML;
            }
        }
    },

    onClick: function() {
        if (this.trElement.isBreakpoint == undefined) {
            this.trElement.isBreakpoint = true;
            addClassName(this.trElement, "breakpoint");
        } else {
            this.trElement.isBreakpoint = undefined;
            removeClassName(this.trElement, "breakpoint");
        }
    },

    addBreakpointSupport: function() {
        elementSetStyle(this.trElement, {"cursor" : "pointer"});
        this.trElement.onclick = fnBindAsEventListener(function() {
            this.onClick();
        }, this);
    },

    isBreakpoint: function() {
        if (this.trElement.isBreakpoint == undefined || this.trElement.isBreakpoint == null) {
            return false
        }
        return this.trElement.isBreakpoint;
    }
});

var HtmlTestSuiteRow = classCreate();
objectExtend(HtmlTestSuiteRow.prototype, AbstractResultAwareRow.prototype);
objectExtend(HtmlTestSuiteRow.prototype, {

    initialize: function(trElement, testFrame, htmlTestSuite) {
        this.trElement = trElement;
        this.testFrame = testFrame;
        this.htmlTestSuite = htmlTestSuite;
        this.link = trElement.getElementsByTagName("a")[0];
        this.link.onclick = fnBindAsEventListener(this._onClick, this);
    },

    reset: function() {
        this.setStatus(null);
    },

    _onClick: function() {
        this.loadTestCase(null);
        return false;
    },

    loadTestCase: function(onloadFunction) {
        this.htmlTestSuite.unselectCurrentRow();
        this.select();
        this.htmlTestSuite.currentRowInSuite = this.trElement.rowIndex - 1;
        // If the row has a stored results table, use that
        var resultsFromPreviousRun = this.trElement.cells[1];
        if (resultsFromPreviousRun) {
            // todo: delegate to TestFrame, e.g.
            //   this.testFrame.restoreTestCase(resultsFromPreviousRun.innerHTML);
            var testBody = this.testFrame.getDocument().body;
            testBody.innerHTML = resultsFromPreviousRun.innerHTML;
            this.testFrame._onLoad();
            if (onloadFunction) {
                onloadFunction();
            }
        } else {
            this.testFrame.load(this.link.href, onloadFunction);
        }
    },

    saveTestResults: function() {
        // todo: GLOBAL ACCESS!
        var resultHTML = this.testFrame.getDocument().body.innerHTML;
        if (!resultHTML) return;

        // todo: why create this div?
        var divElement = this.trElement.ownerDocument.createElement("div");
        divElement.innerHTML = resultHTML;

        var hiddenCell = this.trElement.ownerDocument.createElement("td");
        hiddenCell.appendChild(divElement);
        hiddenCell.style.display = "none";

        this.trElement.appendChild(hiddenCell);
    }

});

var HtmlTestSuite = classCreate();
objectExtend(HtmlTestSuite.prototype, {

    initialize: function(suiteDocument) {
        this.suiteDocument = suiteDocument;
        this.suiteRows = this._collectSuiteRows();
        this.titleRow = new TitleRow(this.getTestTable().rows[0]);
        this.reset();
    },

    reset: function() {
        this.failed = false;
        this.currentRowInSuite = -1;
        this.titleRow.setStatus(null);
        for (var i = 0; i < this.suiteRows.length; i++) {
            var row = this.suiteRows[i];
            row.reset();
        }
    },

    getSuiteRows: function() {
        return this.suiteRows;
    },

    getTestTable: function() {
        var tables = $A(this.suiteDocument.getElementsByTagName("table"));
        return tables[0];
    },

    isAvailable: function() {
        return this.getTestTable() != null;
    },

    _collectSuiteRows: function () {
        var result = [];
        var tables = $A(this.suiteDocument.getElementsByTagName("table"));
        var testTable = tables[0];
        for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {
            var rowElement = testTable.rows[rowNum];
            result.push(new HtmlTestSuiteRow(rowElement, testFrame, this));
        }
        
        // process the unsuited rows as well
        for (var tableNum = 1; tableNum < $A(this.suiteDocument.getElementsByTagName("table")).length; tableNum++) {
            testTable = tables[tableNum];
            for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {
                var rowElement = testTable.rows[rowNum];
                new HtmlTestSuiteRow(rowElement, testFrame, this);
            }
        }
        return result;
    },

    getCurrentRow: function() {
{'fraction_non_alphanumeric': 0.11649559706096808, 'fraction_numerical': 0.002523977788995457, 'mean_word_length': 2.579861459692802, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1455698', 'n_tokens_mistral': 9998, 'n_tokens_neox': 9678, 'n_words': 1902}