All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.jstestdriver.javascript.runner.js Maven / Gradle / Ivy

/*
 * Copyright 2011 Google 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.
 */
/**
 * The first half of the angular json wrapper.
 * @author [email protected] (Cory Smith)
 */

jstestdriver.angular = (function (angular, JSON, jQuery) {
  angular = angular || {};
  var _null = null;
  var $null = 'null';
  var _undefined;
  var $undefined = 'undefined';
  var $function = 'function';
  
  // library functions for angular.
  var isNumber = function (obj) {
    return (typeof obj).toLowerCase() == 'number' || obj instanceof Number;
  };
  
  var isObject = function (obj) {
    return obj != null && (typeof obj).toLowerCase() == 'object';
  };

  var isString = function (obj) {
    return (typeof obj).toLowerCase() == 'string' || obj instanceof String;
  };

  var isArray = function (obj) {
    return obj instanceof Array;
  };

  var isFunction = function (obj) {
    return (typeof obj).toLowerCase() == 'function';
  }

  var isBoolean = function (obj) {
    return (typeof obj).toLowerCase() == 'boolean' || obj instanceof Boolean;
  };

  var isUndefined = function (obj) {
    return (typeof obj).toLowerCase() == 'undefined';
  };

  var isDate = function (obj) {
    return obj instanceof Date;
  };

  var forEach = function (coll, callback) {
    jQuery.each(coll, function (index, value){
      return callback(value, index);
    });
  }

  function includes(arr, obj) {
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] === obj) {
        return true;
      }
    }
    return false;
  }

  // extracted from https://github.com/angular/angular.js/blob/master/src/filters.js
  // Lines 106..129, 
  function padNumber(num, digits, trim) {
    var neg = '';
    if (num < 0) {
      neg =  '-';
      num = -num;
    }
    num = '' + num;
    while(num.length < digits) num = '0' + num;
    if (trim)
      num = num.substr(num.length - digits);
    return neg + num;
  }
  
  // extracted from https://github.com/angular/angular.js/blob/master/src/apis.js
  // Lines 721..782, 
  var R_ISO8061_STR = /^(\d{4})-(\d\d)-(\d\d)(?:T(\d\d)(?:\:(\d\d)(?:\:(\d\d)(?:\.(\d{3}))?)?)?Z)?$/;

  angular['String'] = {
    'quote':function(string) {
      return '"' + string.replace(/\\/g, '\\\\').
                          replace(/"/g, '\\"').
                          replace(/\n/g, '\\n').
                          replace(/\f/g, '\\f').
                          replace(/\r/g, '\\r').
                          replace(/\t/g, '\\t').
                          replace(/\v/g, '\\v') +
               '"';
    },
    'quoteUnicode':function(string) {
      var str = angular['String']['quote'](string);
      var chars = [];
      for ( var i = 0; i < str.length; i++) {
        var ch = str.charCodeAt(i);
        if (ch < 128) {
          chars.push(str.charAt(i));
        } else {
          var encode = "000" + ch.toString(16);
          chars.push("\\u" + encode.substring(encode.length - 4));
        }
      }
      return chars.join('');
    },

    /**
     * Tries to convert input to date and if successful returns the date, otherwise returns the input.
     * @param {string} string
     * @return {(Date|string)}
     */
    'toDate':function(string){
      var match;
      if (isString(string) && (match = string.match(R_ISO8061_STR))){
        var date = new Date(0);
        date.setUTCFullYear(match[1], match[2] - 1, match[3]);
        date.setUTCHours(match[4]||0, match[5]||0, match[6]||0, match[7]||0);
        return date;
      }
      return string;
    }
  };

  angular['Date'] = {
      'toString':function(date){
        return !date ?
                  date :
                  date.toISOString ?
                    date.toISOString() :
                    padNumber(date.getUTCFullYear(), 4) + '-' +
                    padNumber(date.getUTCMonth() + 1, 2) + '-' +
                    padNumber(date.getUTCDate(), 2) + 'T' +
                    padNumber(date.getUTCHours(), 2) + ':' +
                    padNumber(date.getUTCMinutes(), 2) + ':' +
                    padNumber(date.getUTCSeconds(), 2) + '.' +
                    padNumber(date.getUTCMilliseconds(), 3) + 'Z';
      }
    };
  /*The MIT License

Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/

var array = [].constructor;

/**
 * @workInProgress
 * @ngdoc function
 * @name angular.toJson
 * @function
 *
 * @description
 * Serializes the input into a JSON formated string.
 *
 * @param {Object|Array|Date|string|number} obj Input to jsonify.
 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
 * @returns {string} Jsonified string representing `obj`.
 */
function toJson(obj, pretty) {
  var buf = [];
  toJsonArray(buf, obj, pretty ? "\n  " : _null, []);
  return buf.join('');
}

/**
 * @workInProgress
 * @ngdoc function
 * @name angular.fromJson
 * @function
 *
 * @description
 * Deserializes a string in the JSON format.
 *
 * @param {string} json JSON string to deserialize.
 * @param {boolean} [useNative=false] Use native JSON parser if available
 * @returns {Object|Array|Date|string|number} Deserialized thingy.
 */
function fromJson(json, useNative) {
  if (!isString(json)) return json;

  var obj, p, expression;

  try {
    if (useNative && JSON && JSON.parse) {
      obj = JSON.parse(json);
      return transformDates(obj);
    }

    p = parser(json, true);
    expression =  p.primary();
    p.assertAllConsumed();
    return expression();

  } catch (e) {
    error("fromJson error: ", json, e);
    throw e;
  }

  // TODO make forEach optionally recursive and remove this function
  function transformDates(obj) {
    if (isString(obj) && obj.length === DATE_ISOSTRING_LN) {
      return angularString.toDate(obj);
    } else if (isArray(obj) || isObject(obj)) {
      forEach(obj, function(val, name) {
        obj[name] = transformDates(val);
      });
    }
    return obj;
  }
}

angular['toJson'] = toJson;
angular['fromJson'] = fromJson;

function toJsonArray(buf, obj, pretty, stack) {
  if (isObject(obj)) {
    if (obj === window) {
      buf.push(angular['String']['quote']('WINDOW'));
      return;
    }

    if (obj === document) {
      buf.push(angular['String']['quote']('DOCUMENT'));
      return;
    }

    if (includes(stack, obj)) {
      buf.push(angular['String']['quote']('RECURSION'));
      return;
    }
    stack.push(obj);
  }
  if (obj === _null) {
    buf.push($null);
  } else if (obj instanceof RegExp) {
    buf.push(angular['String']['quoteUnicode'](obj.toString()));
  } else if (isFunction(obj)) {
    return;
  } else if (isBoolean(obj)) {
    buf.push('' + obj);
  } else if (isNumber(obj)) {
    if (isNaN(obj)) {
      buf.push($null);
    } else {
      buf.push('' + obj);
    }
  } else if (isString(obj)) {
    return buf.push(angular['String']['quoteUnicode'](obj));
  } else if (isObject(obj)) {
    if (isArray(obj)) {
      buf.push("[");
      var len = obj.length;
      var sep = false;
      for(var i=0; i..."}catch(h){return"[Element]"+(!!d?" "+d:"")}}function prettyPrintEntity_(a){if(isElement_(a)){return formatElement_(a)}var c;if(typeof a=="function"){try{c=a.toString().match(/(function [^\(]+\(\))/)[1]}catch(b){}return c||"[function]"}try{c=JSON.stringify(a)}catch(b){}return c||"["+typeof a+"]"}function argsWithOptionalMsg_(b,e){var a=[];for(var d=0;d0){this.loadFile_(this.files_.shift())}else{this.onAllFilesLoaded_({loadedFiles:[]})}};jstestdriver.FileLoader.prototype.loadFile_=function(a){this.pluginRegistrar_.loadSource(a,this.boundOnFileLoaded)};jstestdriver.FileLoader.prototype.onFileLoaded_=function(a){this.loadedFiles_.push(a);if(this.files_.length==0){this.onAllFilesLoaded_({loadedFiles:this.loadedFiles_})}else{this.loadFile_(this.files_.shift())}};goog.provide("jstestdriver.TestRunFilter");goog.require("jstestdriver");jstestdriver.TestRunFilter=function(a){this.testCaseInfo_=a};jstestdriver.TestRunFilter.prototype.getDefaultTestRunConfiguration=function(){return this.createTestRunConfiguration_(this.testCaseInfo_.getTestNames())};jstestdriver.TestRunFilter.prototype.getTestRunConfigurationFor=function(e){var d=this.filter_(e,this.regexMatcher_(/^[^-].*/));if(d.length<1){d.push("all")}var c=this.filter_(e,this.regexMatcher_(/^-.*/));var b=this.buildTestMethodMap_();var f=this.getExcludedTestIds_(b,c);var a=this.getMatchedTests_(b,d,f);return a.length>0?this.createTestRunConfiguration_(a):null};jstestdriver.TestRunFilter.prototype.createTestRunConfiguration_=function(a){return new jstestdriver.TestRunConfiguration(this.testCaseInfo_,a)};jstestdriver.TestRunFilter.prototype.regexMatcher_=function(a){return function(b){return a.test(b)}};jstestdriver.TestRunFilter.prototype.buildTestMethodMap_=function(){var a={};var d=this.testCaseInfo_.getTestNames();var e=d.length;for(var c=0;c-1){throw new Error("Test case names must not contain '"+a+"'")}};jstestdriver.TestCaseBuilder.prototype.AsyncTestCase=function(b,a){return this.TestCase(b,a,jstestdriver.TestCaseInfo.ASYNC_TYPE)};jstestdriver.TestCaseBuilder.prototype.ConditionalTestCase=function(c,d,a,b){if(d()){return this.TestCase(c,a,b)}this.testCaseManager_.add(new jstestdriver.TestCaseInfo(c,jstestdriver.TestCaseBuilder.PlaceHolderCase,b));return function(){}};jstestdriver.TestCaseBuilder.prototype.ConditionalAsyncTestCase=function(b,c,a){return this.ConditionalTestCase(b,c,a,jstestdriver.TestCaseInfo.ASYNC_TYPE)};jstestdriver.TestCaseBuilder.PlaceHolderCase=function(){};jstestdriver.TestCaseBuilder.PlaceHolderCase.prototype.testExcludedByCondition=jstestdriver.EMPTY_FUNC;jstestdriver.TestRunner=function(a){this.pluginRegistrar_=a;this.boundRunNextConfiguration_=jstestdriver.bind(this,this.runNextConfiguration_)};jstestdriver.TestRunner.prototype.runTests=function(a,c,d,b){this.pluginRegistrar_.onTestsStart();this.testRunsConfiguration_=a;this.onTestDone_=c;this.onComplete_=d;this.captureConsole_=b;this.runNextConfiguration_()};jstestdriver.TestRunner.prototype.finish_=function(){var a=this.onComplete_;this.pluginRegistrar_.onTestsFinish();this.testRunsConfiguration_=null;this.onTestDone_=null;this.onComplete_=null;this.captureConsole_=false;a()};jstestdriver.TestRunner.prototype.runNextConfiguration_=function(){if(this.testRunsConfiguration_.length==0){this.finish_();return}this.runConfiguration(this.testRunsConfiguration_.shift(),this.onTestDone_,this.boundRunNextConfiguration_)};jstestdriver.TestRunner.prototype.runConfiguration=function(b,a,c){if(this.captureConsole_){this.overrideConsole_()}jstestdriver.log("running configuration "+b);this.pluginRegistrar_.runTestConfiguration(b,a,c);if(this.captureConsole_){this.resetConsole_()}};jstestdriver.TestRunner.prototype.overrideConsole_=function(){this.logMethod_=console.log;this.logDebug_=console.debug;this.logInfo_=console.info;this.logWarn_=console.warn;this.logError_=console.error;console.log=function(){jstestdriver.console.log.apply(jstestdriver.console,arguments)};console.debug=function(){jstestdriver.console.debug.apply(jstestdriver.console,arguments)};console.info=function(){jstestdriver.console.info.apply(jstestdriver.console,arguments)};console.warn=function(){jstestdriver.console.warn.apply(jstestdriver.console,arguments)};console.error=function(){jstestdriver.console.error.apply(jstestdriver.console,arguments)}};jstestdriver.TestRunner.prototype.resetConsole_=function(){console.log=this.logMethod_;console.debug=this.logDebug_;console.info=this.logInfo_;console.warn=this.logWarn_;console.error=this.logError_};jstestdriver.TestRunner.TestCaseMap=function(){this.testCases_={}};jstestdriver.TestRunner.TestCaseMap.prototype.startCase=function(a){this.testCases_[a]=true};jstestdriver.TestRunner.TestCaseMap.prototype.stopCase=function(a){this.testCases_[a]=false};jstestdriver.TestRunner.TestCaseMap.prototype.hasActiveCases=function(){for(var a in this.testCases_){if(this.testCases_.hasOwnProperty(a)&&this.testCases_[a]){return true}}return false};jstestdriver.testBreather=function(c,a){var d=new Date();function b(f){var e=new Date();if((e-d)>a){c(f,1);d=e}else{f()}}return b};jstestdriver.TIMEOUT=500;jstestdriver.NOOP_COMMAND={command:"noop",parameters:[]};jstestdriver.CommandExecutor=function(b,g,f,a,c,d,e){this.streamingService_=b;this.__testCaseManager=g;this.__testRunner=f;this.__pluginRegistrar=a;this.__boundExecuteCommand=jstestdriver.bind(this,this.executeCommand);this.__boundExecute=jstestdriver.bind(this,this.execute);this.__boundEvaluateCommand=jstestdriver.bind(this,this.evaluateCommand);this.boundCleanTestManager=jstestdriver.bind(this,this.cleanTestManager);this.boundOnFileLoaded_=jstestdriver.bind(this,this.onFileLoaded);this.boundOnFileLoadedRunnerMode_=jstestdriver.bind(this,this.onFileLoadedRunnerMode);this.boundOnTestDone=jstestdriver.bind(this,this.onTestDone_);this.boundOnComplete=jstestdriver.bind(this,this.onComplete_);this.boundOnTestDoneRunnerMode=jstestdriver.bind(this,this.onTestDoneRunnerMode_);this.boundOnCompleteRunnerMode=jstestdriver.bind(this,this.onCompleteRunnerMode_);this.boundSendTestResults=jstestdriver.bind(this,this.sendTestResults);this.commandMap_={};this.testsDone_=[];this.debug_=false;this.now_=c;this.lastTestResultsSent_=0;this.getBrowserInfo=d;this.currentActionSignal_=e;this.currentCommand=null};jstestdriver.CommandExecutor.prototype.executeCommand=function(b){var f;if(b&&b.length){f=jsonParse(b)}else{f=jstestdriver.NOOP_COMMAND}this.currentCommand=f.command;jstestdriver.log("current command "+f.command);try{this.commandMap_[f.command](f.parameters)}catch(d){var c="Exception "+d.name+": "+d.message+"\n"+d.fileName+"("+d.lineNumber+"):\n"+d.stack;var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.LOG,jstestdriver.JSON.stringify(new jstestdriver.BrowserLog(1000,"jstestdriver.CommandExecutor",c,this.getBrowserInfo())),this.getBrowserInfo());if(top.console&&top.console.log){top.console.log(c)}this.streamingService_.close(a,this.__boundExecuteCommand);throw d}};jstestdriver.CommandExecutor.prototype.execute=function(b){var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.COMMAND_RESULT,JSON.stringify(this.__boundEvaluateCommand(b)),this.getBrowserInfo());this.streamingService_.close(a,this.__boundExecuteCommand)};jstestdriver.CommandExecutor.prototype.evaluateCommand=function(cmd){var res="";try{var evaluatedCmd=eval("("+cmd+")");if(evaluatedCmd){res=evaluatedCmd.toString()}}catch(e){res="Exception "+e.name+": "+e.message+"\n"+e.fileName+"("+e.lineNumber+"):\n"+e.stack}return res};jstestdriver.CommandExecutor.prototype.registerCommand=function(a,b,c){this.commandMap_[a]=jstestdriver.bind(b,c)};jstestdriver.CommandExecutor.prototype.registerTracedCommand=function(a,b,d){var c=jstestdriver.bind(b,d);var e=this.currentActionSignal_;this.commandMap_[a]=function(){e.set(a);return c.apply(null,arguments)}};jstestdriver.CommandExecutor.prototype.dryRun=function(){var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.TEST_QUERY_RESULT,JSON.stringify(this.__testCaseManager.getCurrentlyLoadedTest()),this.getBrowserInfo());this.streamingService_.close(a,this.__boundExecuteCommand)};jstestdriver.CommandExecutor.prototype.dryRunFor=function(b){var d=jsonParse('{"expressions":'+b[0]+"}").expressions;var c=JSON.stringify(this.__testCaseManager.getCurrentlyLoadedTestFor(d));var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.TEST_QUERY_RESULT,c,this.getBrowserInfo());this.streamingService_.close(a,this.__boundExecuteCommand)};jstestdriver.CommandExecutor.prototype.listen=function(b){var a;if(window.location.href.search("refresh")!=-1){a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.RESET_RESULT,'{"loadedFiles":'+JSON.stringify(b)+"}",this.getBrowserInfo(),true);jstestdriver.log("Runner reset: "+window.location.href)}else{a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.BROWSER_READY,'{"loadedFiles":'+JSON.stringify(b)+"}",this.getBrowserInfo(),true)}this.streamingService_.close(a,this.__boundExecuteCommand)};jstestdriver.ManualScriptLoader=function(c,b,a){this.win_=c;this.testCaseManager_=b;this.now_=a;this.onFileLoaded_=null;this.started_=-1;this.file_=null};jstestdriver.ManualScriptLoader.prototype.beginLoad=function(a,c){this.testCaseManager_.removeTestCaseForFilename(a.fileSrc);var b=this.createErrorHandler();this.win_.onerror=b;this.file_=a;this.started_=this.now_();this.onFileLoaded_=c};jstestdriver.ManualScriptLoader.prototype.endLoad=function(){if(this.file_){var b=this.now_()-this.started_;if(b>50){jstestdriver.log("slow load "+this.file_.fileSrc+" in "+b)}var c=this.file_;this.file_=null;this.testCaseManager_.updateLatestTestCase(c.fileSrc);var a=new jstestdriver.FileResult(c,true,"",this.now_()-this.started_);this.win_.onerror=jstestdriver.EMPTY_FUNC;this.onFileLoaded_(a)}};jstestdriver.ManualScriptLoader.prototype.createErrorHandler=function(){function a(g,e,d){var f=this.file_;jstestdriver.log("failed load "+f.fileSrc+" in "+(this.now_()-this.started_));var c=this.started_;this.started_=-1;var f=this.file_;this.file_=null;var b="error loading file: "+f.fileSrc;if(d!=undefined&&d!=null){b+=":"+d}if(g!=undefined&&g!=null){b+=": "+g}this.win_.onerror=jstestdriver.EMPTY_FUNC;this.onFileLoaded_(new jstestdriver.FileResult(f,false,b,this.now_()-c))}return jstestdriver.bind(this,a)};jstestdriver.ManualResourceTracker=function(e,d,b,c,a){this.parse_=e;this.serialize_=d;this.getBrowserInfo_=c;this.manualScriptLoader_=a;this.boundOnComplete_=jstestdriver.bind(this,this.onComplete_);this.results_=[]};jstestdriver.ManualResourceTracker.prototype.startResourceLoad=function(a){var b=this.parse_(a);this.manualScriptLoader_.beginLoad(b,jstestdriver.bind(this,this.onComplete_))};jstestdriver.ManualResourceTracker.prototype.onComplete_=function(a){this.results_.push(a)};jstestdriver.ManualResourceTracker.prototype.finishResourceLoad=function(){this.manualScriptLoader_.endLoad()};jstestdriver.ManualResourceTracker.prototype.getResults=function(){return this.results_};jstestdriver.LoadTestsCommand=function(c,a,b,d){this.jsonParse_=c;this.pluginRegistrar_=a;this.boundOnFileLoaded_=jstestdriver.bind(this,this.onFileLoaded);this.boundOnFileLoadedRunnerMode_=jstestdriver.bind(this,this.onFileLoadedRunnerMode);this.getBrowserInfo=b;this.onLoadComplete_=d};jstestdriver.LoadTestsCommand.prototype.loadTest=function(c){var e=c[0];var d=c[1]=="true"?true:false;var b=this.jsonParse_('{"f":'+e+"}").f;this.removeScripts(document,b);var a=new jstestdriver.FileLoader(this.pluginRegistrar_,this.boundOnFileLoaded_);a.load(b)};jstestdriver.LoadTestsCommand.prototype.onFileLoaded=function(a){var b=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.FILE_LOAD_RESULT,JSON.stringify(a),this.getBrowserInfo());this.onLoadComplete_(b)};jstestdriver.LoadTestsCommand.prototype.onFileLoadedRunnerMode=function(a){this.streamingService_.close(null,this.__boundExecuteCommand)};jstestdriver.LoadTestsCommand.prototype.findScriptTagsToRemove_=function(e,l){var c=e.getElementsByTagName("script");var a=l.length;var k=c.length;var b=[];for(var g=0;g0){var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.TEST_RESULT,JSON.stringify(this.testsDone_),this.getBrowserInfo_());this.testsDone_=[];this.streamContinue_(a)}};jstestdriver.RunTestsCommand.prototype.onTestDone_=function(a){this.addTestResult(a);var b=this.now_()-this.lastTestResultsSent_;if((a.result=="error"||a.log!=""||this.debug_||b>jstestdriver.TIMEOUT)){this.lastTestResultsSent_=this.now_();this.sendTestResults()}};jstestdriver.RunTestsCommand.prototype.addTestResult=function(a){this.pluginRegistrar_.processTestResult(a);this.testsDone_.push(a)};jstestdriver.RunTestsCommand.prototype.sendTestResultsOnComplete_=function(){var a=new jstestdriver.Response(jstestdriver.RESPONSE_TYPES.TEST_RESULT,JSON.stringify(this.testsDone_),this.getBrowserInfo_());this.testsDone_=[];this.streamStop_(a)};jstestdriver.RunTestsCommand.prototype.onComplete_=function(){this.sendTestResultsOnComplete_()};jstestdriver.config=(function(b){var a=b||{};a.createRunner=function(h,f){var g=f||jstestdriver.plugins.defaultRunTestLoop;jstestdriver.pluginRegistrar=new jstestdriver.PluginRegistrar();jstestdriver.testCaseManager=new jstestdriver.TestCaseManager(jstestdriver.pluginRegistrar);jstestdriver.testRunner=new jstestdriver.TestRunner(jstestdriver.pluginRegistrar);jstestdriver.testCaseBuilder=new jstestdriver.TestCaseBuilder(jstestdriver.testCaseManager);jstestdriver.global.TestCase=jstestdriver.bind(jstestdriver.testCaseBuilder,jstestdriver.testCaseBuilder.TestCase);jstestdriver.global.AsyncTestCase=jstestdriver.bind(jstestdriver.testCaseBuilder,jstestdriver.testCaseBuilder.AsyncTestCase);jstestdriver.global.ConditionalTestCase=jstestdriver.bind(jstestdriver.testCaseBuilder,jstestdriver.testCaseBuilder.ConditionalTestCase);jstestdriver.global.ConditionalAsyncTestCase=jstestdriver.bind(jstestdriver.testCaseBuilder,jstestdriver.testCaseBuilder.ConditionalAsyncTestCase);var c=new jstestdriver.plugins.ScriptLoader(window,document,jstestdriver.testCaseManager,jstestdriver.now);var k=new jstestdriver.plugins.StylesheetLoader(window,document,jstestdriver.jQuery.browser.mozilla||jstestdriver.jQuery.browser.safari);var i=new jstestdriver.plugins.FileLoaderPlugin(c,k,jstestdriver.now);var e=new jstestdriver.plugins.TestRunnerPlugin(Date,function(){jstestdriver.log(jstestdriver.jQuery("body")[0].innerHTML);jstestdriver.jQuery("body").children().remove();jstestdriver.jQuery(document).unbind();jstestdriver.jQuery(document).die()},g);jstestdriver.pluginRegistrar.register(new jstestdriver.plugins.DefaultPlugin(i,e,new jstestdriver.plugins.AssertsPlugin(),new jstestdriver.plugins.TestCaseManagerPlugin()));jstestdriver.pluginRegistrar.register(new jstestdriver.plugins.async.AsyncTestRunnerPlugin(Date,function(){jstestdriver.jQuery("body").children().remove();jstestdriver.jQuery(document).unbind();jstestdriver.jQuery(document).die()},jstestdriver.utils.serializeObject));jstestdriver.testCaseManager.TestCase=jstestdriver.global.TestCase;var d=parseInt(jstestdriver.extractId(top.location.toString()));function j(){return new jstestdriver.BrowserInfo(d)}jstestdriver.manualResourceTracker=new jstestdriver.ManualResourceTracker(jstestdriver.JSON.parse,jstestdriver.JSON.stringify,jstestdriver.pluginRegistrar,j,new jstestdriver.ManualScriptLoader(window,jstestdriver.testCaseManager,jstestdriver.now));return jstestdriver.executor=h(jstestdriver.testCaseManager,jstestdriver.testRunner,jstestdriver.pluginRegistrar,jstestdriver.now,window.location.toString(),j,d)};a.createExecutor=function(d,t,k,f,c,u,r){var g=jstestdriver.createPath(top.location.toString(),jstestdriver.SERVER_URL+r);var p=new jstestdriver.StreamingService(g,f,jstestdriver.convertToJson(jstestdriver.jQuery.post),jstestdriver.createSynchPost(jstestdriver.jQuery));var e=new jstestdriver.CommandExecutor(p,d,t,k,f,u);var j=new jstestdriver.Signal(null);var s=jstestdriver.bind(e,e.executeCommand);function h(x){p.close(x,s)}function m(x){p.stream(x,s)}var w=new jstestdriver.LoadTestsCommand(jsonParse,k,u,h);var v=new jstestdriver.RunTestsCommand(d,t,k,u,jstestdriver.now,jsonParse,m,h);var n=new jstestdriver.Signal(false);var i=new jstestdriver.ResetCommand(window.location,n,jstestdriver.now);var q=new jstestdriver.NoopCommand(h,u);e.registerCommand("execute",e,e.execute);e.registerCommand("noop",q,q.sendNoop);e.registerCommand("runAllTests",v,v.runAllTests);e.registerCommand("runTests",v,v.runTests);e.registerCommand("loadTest",w,w.loadTest);e.registerCommand("reset",i,i.reset);e.registerCommand("dryRun",e,e.dryRun);e.registerCommand("dryRunFor",e,e.dryRunFor);e.registerCommand("unknownBrowser",null,function(){});e.registerCommand("stop",null,function(){if(window.console&&window.console.log){window.console.log("Stopping executor by server request.")}});e.registerCommand("streamAcknowledged",p,p.streamAcknowledged);function l(){return j.get()}var o=new jstestdriver.PageUnloadHandler(p,u,l,n);jstestdriver.jQuery(window).bind("unload",jstestdriver.bind(o,o.onUnload));jstestdriver.jQuery(window).bind("beforeunload",jstestdriver.bind(o,o.onUnload));window.onbeforeunload=jstestdriver.bind(o,o.onUnload);return e};a.createVisualExecutor=function(h,g,d,e,c,f,i){return a.createStandAloneExecutorWithReporter(h,g,d,e,c,new jstestdriver.VisualTestReporter(function(j){return document.createElement(j)},function(j){return document.body.appendChild(j)},jstestdriver.jQuery,JSON.parse),f,i)};a.createStandAloneExecutor=function(h,g,d,e,c,f,i){return a.createStandAloneExecutorWithReporter(h,g,d,e,c,new jstestdriver.StandAloneTestReporter(),f,i)};a.createStandAloneExecutorWithReporter=function(o,m,p,g,q,k,s,f){var d=jstestdriver.createPath(top.location.toString(),jstestdriver.SERVER_URL+f);var h=new jstestdriver.StreamingService(d,g,jstestdriver.convertToJson(jstestdriver.jQuery.post));window.top.G_testRunner=k;jstestdriver.reporter=k;var i=new jstestdriver.Signal(null);var j=new jstestdriver.CommandExecutor(h,o,m,p,g,s,i);var n=jstestdriver.bind(j,j.executeCommand);function e(t){h.close(t,n)}function c(t){h.stream(t,n)}var r=new jstestdriver.StandAloneLoadTestsCommand(jsonParse,p,s,e,k,jstestdriver.now);var l=new jstestdriver.StandAloneRunTestsCommand(o,m,p,s,k,g,jsonParse,c,e);j.registerTracedCommand("execute",j,j.execute);j.registerTracedCommand("noop",null,e);j.registerTracedCommand("runAllTests",l,l.runAllTests);j.registerTracedCommand("runTests",l,l.runTests);j.registerTracedCommand("loadTest",r,r.loadTest);j.registerTracedCommand("reset",j,j.reset);j.registerTracedCommand("dryRun",j,j.dryRun);j.registerTracedCommand("dryRunFor",j,j.dryRunFor);j.registerCommand("streamAcknowledged",h,h.streamAcknowledged);j.registerCommand("unknownBrowser",null,function(){});j.registerCommand("stop",null,function(){if(window.console&&window.console.log){window.console.log("Stopping executor by server request.")}});return j};return a})(jstestdriver.config);/*
 * Copyright 2010 Google 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.
 */

/**
 * @fileoverview Defines the FiniteUseCallback class, which decorates a
 * Javascript function by notifying the test runner about any exceptions thrown
 * when the function executes.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.CatchingCallback');

goog.require('jstestdriver');

/**
 * Constructs a CatchingCallback.
 *
 * @param {Object} testCase the testCase to use as 'this' when calling the
 *    wrapped function.
 * @param {jstestdriver.plugins.async.CallbackPool} pool the pool to which this
 *    callback belongs.
 * @param {Function} wrapped the wrapped callback function.
 * @constructor
 */
jstestdriver.plugins.async.CatchingCallback = function(
    testCase, pool, wrapped) {
  this.testCase_ = testCase;
  this.pool_ = pool;
  this.callback_ = wrapped;
};


/**
 * Invokes the wrapped callback, catching any exceptions and reporting the
 * status to the pool.
 * @return {*} The return value of the original callback.
 */
jstestdriver.plugins.async.CatchingCallback.prototype.invoke = function() {
  var result;
  var message;
  try {
    result = this.callback_.apply(this.testCase_, arguments);
    message = 'success.';
    return result;
  } catch (e) {
    this.pool_.onError(e);
    message = 'failure: ' + e;
    throw e;
  } finally {
    this.pool_.remove(message);
  }
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the ExpiringCallback class, which decorates a
 * Javascript function by restricting the length of time the asynchronous system
 * may delay before calling the function.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.ExpiringCallback');

goog.require('jstestdriver');

/**
 * Constructs an ExpiringCallback.
 *
 * @param {jstestdriver.plugins.async.CallbackPool} pool The pool to which this
 *     callback belongs.
 * @param {jstestdriver.plugins.async.FiniteUseCallback} callback A
 *     FiniteUseCallback.
 * @param {jstestdriver.plugins.async.Timeout} timeout A Timeout object.
 * @param {string} stepDescription A description of the current test step.
 * @constructor
 */
jstestdriver.plugins.async.ExpiringCallback = function(
    pool, callback, timeout, stepDescription, callbackDescription) {
  this.pool_ = pool;
  this.callback_ = callback;
  this.timeout_ = timeout;
  this.stepDescription_ = stepDescription;
  this.callbackDescription_ = callbackDescription;
};


/**
 * Arms this callback to expire after the given delay.
 *
 * @param {number} delay The amount of time (ms) before this callback expires.
 */
jstestdriver.plugins.async.ExpiringCallback.prototype.arm = function(delay) {
  var callback = this;
  this.timeout_.arm(function() {
    callback.pool_.onError(new Error('Callback \'' +
        callback.callbackDescription_ + '\' expired after ' + delay +
        ' ms during test step \'' + callback.stepDescription_ + '\''));
    callback.pool_.remove('expired.', callback.callback_.getRemainingUses());
    callback.callback_.deplete();
  }, delay);
};


/**
 * Invokes this callback.
 * @return {*} The return value of the FiniteUseCallback.
 */
jstestdriver.plugins.async.ExpiringCallback.prototype.invoke = function() {
  return this.callback_.invoke.apply(this.callback_, arguments);
};

/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the FiniteUseCallback class, which decorates a
 * Javascript function by restricting the number of times the asynchronous
 * system may call it.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.FiniteUseCallback');

goog.require('jstestdriver');

/**
 * Constructs a FiniteUseCallback.
 *
 * @param {jstestdriver.plugins.async.CatchingCallback} callback A
 *     CatchingCallback.
 * @param {Function} onDepleted a function to execute when this
 *     FiniteUseCallback depletes.
 * @param {?number} opt_remainingUses the number of permitted uses remaining;
 *     defaults to one.
 * @constructor
 */
jstestdriver.plugins.async.FiniteUseCallback = function(
    callback, onDepleted, opt_remainingUses) {
  this.callback_ = callback;
  this.onDepleted_ = onDepleted;
  this.remainingUses_ = opt_remainingUses || 1;
};


/**
 * Depletes the remaining permitted uses.  Calls onDepleted.
 */
jstestdriver.plugins.async.FiniteUseCallback.prototype.deplete = function() {
  this.remainingUses_ = 0;
  if (this.onDepleted_) {
    this.onDepleted_.apply();
  }
};


/**
 * @return {number} The number of remaining permitted uses.
 */
jstestdriver.plugins.async.FiniteUseCallback.prototype.getRemainingUses =
    function() {
  return this.remainingUses_;
};


/**
 * Invokes this callback if it is usable. Calls onDepleted if invoking this
 * callback depletes its remaining permitted uses.
 * @param {...*} var_args The original callback arguments.
 * @return {*} The return value of the CatchingCallback or null.
 */
jstestdriver.plugins.async.FiniteUseCallback.prototype.invoke =
    function(var_args) {
  if (this.isUsable()) {
    try {
      this.remainingUses_ -= 1;
      return this.callback_.invoke.apply(this.callback_, arguments);
    } finally {
      if (this.onDepleted_ && !this.isUsable()) {
        this.onDepleted_.apply();
      }
    }
  }
};


/**
 * @return {boolean} True if any permitted uses remain.
 */
jstestdriver.plugins.async.FiniteUseCallback.prototype.isUsable = function() {
  return this.remainingUses_ > 0;
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the Timeout class.  The arm() method is equivalent to
 * window.setTimeout() and maybeDisarm() is equivalent to window.clearTimeout().
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.Timeout');

goog.require('jstestdriver');

/**
 * Constructs a Timeout. Accepts alternate implementations of setTimeout and
 * clearTimeout.
 *
 * @param {Function} setTimeout The global setTimeout function to use.
 * @param {Function} clearTimeout The global clearTimeout function to use.
 * @constructor
 */
jstestdriver.plugins.async.Timeout = function(setTimeout, clearTimeout) {
  this.setTimeout_ = setTimeout;
  this.clearTimeout_ = clearTimeout;
  this.handle_ = null;
};


/**
 * Arms this Timeout to fire after the specified delay.
 *
 * @param {Function} callback The callback to call after the delay passes.
 * @param {number} delay The timeout delay in milliseconds.
 */
jstestdriver.plugins.async.Timeout.prototype.arm = function(callback, delay) {
  var self = this;
  this.handle_ = this.setTimeout_(function() {
    self.maybeDisarm();
    return callback.apply(null, arguments);
  }, delay);
};

/**
 * Explicitly disarms the timeout.
 * @private
 */
jstestdriver.plugins.async.Timeout.prototype.disarm_ = function() {
  this.clearTimeout_(this.handle_);
  this.handle_ = null;
};


/**
 * @return {boolean} True if the timeout is armed.
 */
jstestdriver.plugins.async.Timeout.prototype.isArmed = function() {
  return this.handle_ != null;
};


/**
 * Disarms the timeout if it is armed.
 */
jstestdriver.plugins.async.Timeout.prototype.maybeDisarm = function() {
  if (this.isArmed()) {
    this.disarm_();
  }
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the TestSafeCallbackBuilder class. It decorates a
 * Javascript function with several safeguards so that it may be safely executed
 * asynchronously within a test.
 *
 * The safeguards include:
 *   1) notifying the test runner about any exceptions thrown when the function
 *      executes
 *   2) restricting the number of times the asynchronous system may call the
 *      function
 *   3) restricting the length of time the asynchronous system may delay before
 *      calling the function
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.TestSafeCallbackBuilder');

goog.require('jstestdriver');
goog.require('jstestdriver.plugins.async.CatchingCallback');
goog.require('jstestdriver.plugins.async.ExpiringCallback');
goog.require('jstestdriver.plugins.async.FiniteUseCallback');
goog.require('jstestdriver.plugins.async.Timeout');

/**
 * Constructs a TestSafeCallbackBuilder.
 *
 * @param {Function} opt_setTimeout the global setTimeout function to use.
 * @param {Function} opt_clearTimeout the global clearTimeout function to use.
 * @param {Function} opt_timeoutConstructor a constructor for obtaining new the
 *     Timeouts.
 * @constructor
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder = function(
    opt_setTimeout, opt_clearTimeout, opt_timeoutConstructor) {
  this.setTimeout_ = opt_setTimeout || jstestdriver.setTimeout;
  this.clearTimeout_ = opt_clearTimeout || jstestdriver.clearTimeout;
  this.timeoutConstructor_ = opt_timeoutConstructor ||
      jstestdriver.plugins.async.Timeout;
  this.callbackDescription = 'Unknown callback.';
  this.stepDescription_ = 'Unknown step.';
  this.pool_ = null;
  this.remainingUses_ = null;
  this.testCase_ = null;
  this.wrapped_ = null;
};


/**
 * Returns the original function decorated with safeguards.
 * @return {*} The return value of the original callback.
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder.prototype.build =
    function() {
  var catchingCallback = new jstestdriver.plugins.async.CatchingCallback(
      this.testCase_, this.pool_, this.wrapped_);
  var timeout = new (this.timeoutConstructor_)(
      this.setTimeout_, this.clearTimeout_);
  var onDepleted = function() {
    timeout.maybeDisarm();
  };
  var finiteUseCallback = new jstestdriver.plugins.async.FiniteUseCallback(
      catchingCallback, onDepleted, this.remainingUses_);
  return new jstestdriver.plugins.async.ExpiringCallback(
      this.pool_, finiteUseCallback, timeout,
      this.stepDescription_, this.callbackDescription_);
};


jstestdriver.plugins.async.TestSafeCallbackBuilder.
    prototype.setCallbackDescription = function(callbackDescription) {
  this.callbackDescription_ = callbackDescription;
  return this;
};


jstestdriver.plugins.async.TestSafeCallbackBuilder.
    prototype.setStepDescription = function(stepDescription) {
  this.stepDescription_ = stepDescription;
  return this;
};


/**
 * @param {jstestdriver.plugins.async.CallbackPool} pool the CallbackPool to
 *     contain the callback.
 * @return {jstestdriver.plugins.async.TestSafeCallbackBuilder} This.
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder.prototype.setPool = function(
    pool) {
  this.pool_ = pool;
  return this;
};


/**
 * @param {number} remainingUses The remaining number of permitted calls.
 * @return {jstestdriver.plugins.async.TestSafeCallbackBuilder} This.
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder.prototype.setRemainingUses =
    function(remainingUses) {
  this.remainingUses_ = remainingUses;
  return this;
};


/**
 * @param {Object} testCase The test case instance available as 'this' within
 *     the function's scope.
 * @return {jstestdriver.plugins.async.TestSafeCallbackBuilder} This.
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder.prototype.setTestCase =
    function(testCase) {
  this.testCase_ = testCase;
  return this;
};


/**
 * @param {Function} wrapped The function wrapped by the above safeguards.
 * @return {jstestdriver.plugins.async.TestSafeCallbackBuilder} This.
 */
jstestdriver.plugins.async.TestSafeCallbackBuilder.prototype.setWrapped =
    function(wrapped) {
  this.wrapped_ = wrapped;
  return this;
};
/*
 * Copyright 2011 Google 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.
 */


/**
 * @fileoverview Defines the CallbackPool class, which decorates given callback
 * functions with safeguards and tracks them until they execute or expire.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.CallbackPool');

goog.require('jstestdriver');
goog.require('jstestdriver.plugins.async.TestSafeCallbackBuilder');

/**
 * Constructs a CallbackPool.
 *
 * @param {Function} setTimeout The global setTimeout function.
 * @param {Object} testCase The test case instance.
 * @param {Function} onPoolComplete A function to call when the pool empties.
 * @param {string} stepDescription A description of the current test step.
 * @param {boolean} opt_pauseForHuman Whether or not to pause for debugging.
 * @param {Function} opt_callbackBuilderConstructor An optional constructor for
 *     a callback builder.
 * @constructor
 */
jstestdriver.plugins.async.CallbackPool = function(setTimeout, testCase,
      onPoolComplete, stepDescription, opt_pauseForHuman,
      opt_callbackBuilderConstructor) {
  this.setTimeout_ = setTimeout;
  this.testCase_ = testCase;
  this.onPoolComplete_ = onPoolComplete;
  this.stepDescription_ = stepDescription;
  this.pauseForHuman_ = !!opt_pauseForHuman;
  this.callbackBuilderConstructor_ = opt_callbackBuilderConstructor ||
      jstestdriver.plugins.async.TestSafeCallbackBuilder;
  this.errors_ = [];
  this.count_ = 0;
  this.callbackIndex_ = 1;
  this.active_ = false;
};


/**
 * The number of milliseconds to wait before expiring a delinquent callback.
 */
jstestdriver.plugins.async.CallbackPool.TIMEOUT = 30000;


/**
 * Calls onPoolComplete if the pool is active and empty.
 */
jstestdriver.plugins.async.CallbackPool.prototype.maybeComplete = function() {
  if (this.active_ && this.count_ == 0 && this.onPoolComplete_) {
    var pool = this;
    this.setTimeout_(function() {
      pool.active_ = false;
      pool.onPoolComplete_(pool.errors_);
    }, 0);
  }
};


/**
 * Activates the pool and calls maybeComplete.
 */
jstestdriver.plugins.async.CallbackPool.prototype.activate = function() {
    this.active_ = true;
    this.maybeComplete();
};


/**
 * @return {number} The number of outstanding callbacks in the pool.
 */
jstestdriver.plugins.async.CallbackPool.prototype.count = function() {
  return this.count_;
};


/**
 * Accepts errors to later report them to the test runner via onPoolComplete.
 * @param {Error} error The error to report.
 */
jstestdriver.plugins.async.CallbackPool.prototype.onError = function(error) {
  this.errors_.push(error);
  this.count_ = 0;
  this.maybeComplete();
};


/**
 * Adds a callback function to the pool, optionally more than once.
 *
 * @param {Function} wrapped The callback function to decorate with safeguards
 *     and to add to the pool.
 * @param {number} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @param {number} opt_timeout The timeout in milliseconds.
 * @return {Function} A test safe callback.
 */
jstestdriver.plugins.async.CallbackPool.prototype.addCallback = function(
    wrapped, opt_n, opt_timeout, opt_description) {
  this.count_ += opt_n || 1;
  var callback = new (this.callbackBuilderConstructor_)()
      .setCallbackDescription(opt_description || '#' + this.callbackIndex_++)
      .setStepDescription(this.stepDescription_)
      .setPool(this)
      .setRemainingUses(opt_n)
      .setTestCase(this.testCase_)
      .setWrapped(wrapped)
      .build();
  if (!this.pauseForHuman_) {
    callback.arm(opt_timeout ||
        jstestdriver.plugins.async.CallbackPool.TIMEOUT);
  }
  return function() {
    return callback.invoke.apply(callback, arguments);
  };
};


/**
 * Adds a callback function to the pool, optionally more than once.
 *
 * @param {Function} wrapped The callback function to decorate with safeguards
 *     and to add to the pool.
 * @param {number} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @deprecated Use CallbackPool#addCallback().
 */
jstestdriver.plugins.async.CallbackPool.prototype.add =
    jstestdriver.plugins.async.CallbackPool.prototype.addCallback;


/**
 * @return {Function} An errback function to attach to an asynchronous system so
 *     that the test runner can be notified in the event of error.
 * @param {string} message A message to report to the user upon error.
 */
jstestdriver.plugins.async.CallbackPool.prototype.addErrback = function(
    message) {
  var pool = this;
  return function() {
    pool.onError(new Error(
        'Errback ' + message + ' called with arguments: ' +
            Array.prototype.slice.call(arguments)));
  };
};


/**
 * Removes a callback from the pool, optionally more than one.
 *
 * @param {string} message A message to pass to the pool for logging purposes;
 *     usually the reason that the callback was removed from the pool.
 * @param {number} opt_n The number of callbacks to remove from the pool.
 */
jstestdriver.plugins.async.CallbackPool.prototype.remove = function(
    message, opt_n) {
  if (this.count_ > 0) {
    this.count_ -= opt_n || 1;
    this.maybeComplete();
  }
};
/*
 * Copyright 2011 Google 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.
 */


/**
 * @fileoverview Defines the CallbackPoolArmor class. Encapsulates a
 * CallbackPool behind a narrower interface. Also, validates arguments.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.CallbackPoolArmor');

goog.require('jstestdriver');

/**
 * Constructs a CallbackPoolArmor.
 * @param {jstestdriver.plugins.async.CallbackPool} pool The pool.
 * @constructor
 */
jstestdriver.plugins.async.CallbackPoolArmor = function(pool) {
  this.pool_ = pool;
};


/**
 * Adds a callback to the pool.
 * @param {Object|Function} callback The callback to wrap.
 * @param {number=} opt_n An optional number of times to wait for the callback to
 *     be called.
 * @param {number=} opt_timeout The timeout in milliseconds.
 * @param {string=} opt_description The callback description.
 * @return {Function} The wrapped callback.
 */
jstestdriver.plugins.async.CallbackPoolArmor.prototype.addCallback = function(
    callback, opt_n, opt_timeout, opt_description) {
  if (typeof callback == 'object') {
    var params = callback;
    callback = params['callback'];
    opt_n = params['invocations'];
    opt_timeout = params['timeout'] ? params['timeout'] * 1000 : undefined;
    opt_description = params['description'];
  }

  if (typeof callback == 'function' && callback) {
    return this.pool_.addCallback(
        callback, opt_n, opt_timeout, opt_description);
  }

  return null;
};


/**
 * @return {Function} An errback function to attach to an asynchronous system so
 *     that the test runner can be notified in the event of error.
 * @param {string} message A message to report to the user upon error.
 */
jstestdriver.plugins.async.CallbackPoolArmor.prototype.addErrback = function(
    message) {
  return this.pool_.addErrback(message);
};


/**
 * Adds a callback to the pool.
 * @param {Function} callback The callback to wrap.
 * @param {Number} opt_n An optional number of times to wait for the callback to
 *     be called.
 * @return {Function} The wrapped callback.
 * @deprecated Use CallbackPoolArmor#addCallback().
 */
jstestdriver.plugins.async.CallbackPoolArmor.prototype.add =
    jstestdriver.plugins.async.CallbackPoolArmor.prototype.addCallback;


/**
 * A no-op callback that's useful for waiting until an asynchronous operation
 * completes without performing any action.
 * @param {Object|number=} opt_n An optional number of times to wait for the
 *     callback to be called.
 * @param {number=} opt_timeout The timeout in milliseconds.
 * @param {string=} opt_description The description.
 * @return {Function} A noop callback.
 */
jstestdriver.plugins.async.CallbackPoolArmor.prototype.noop = function(
    opt_n, opt_timeout, opt_description) {
  if (typeof opt_n == 'object') {
    var params = opt_n;
    opt_timeout = params['timeout'] ? params['timeout'] * 1000 : undefined;
    opt_description = params['description'];
    opt_n = params['invocations'];
  }
  return this.pool_.addCallback(
      jstestdriver.EMPTY_FUNC, opt_n, opt_timeout, opt_description);
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the DeferredQueue class.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.DeferredQueue');

goog.require('jstestdriver');
goog.require('jstestdriver.plugins.async.DeferredQueueArmor');
goog.require('jstestdriver.plugins.async.CallbackPool');
goog.require('jstestdriver.plugins.async.CallbackPoolArmor');

/**
 * Constructs a DeferredQueue.
 * @param {Function} setTimeout The setTimeout function.
 * @param {Object} testCase The test case that owns this queue.
 * @param {Function} onQueueComplete The queue complete callback.
 * @param {jstestdriver.plugins.async.DeferredQueueArmor} armor The armor
 *     wrapping all DeferredQueues for this test run0.
 * @param {boolean} opt_pauseForHuman Whether or not to pause for debugging.
 * @param {Function} opt_queueConstructor The DeferredQueue constructor.
 * @param {Function} opt_queueArmorConstructor The DeferredQueueArmor
 *     constructor.
 * @param {Function} opt_poolConstructor The CallbackPool constructor.
 * @param {Function} opt_poolArmorConstructor The CallbackPoolArmor constructor.
 * @constructor
 */
jstestdriver.plugins.async.DeferredQueue = function(setTimeout, testCase,
    onQueueComplete, armor, opt_pauseForHuman, opt_queueConstructor,
    opt_queueArmorConstructor, opt_poolConstructor, opt_poolArmorConstructor) {
  this.setTimeout_ = setTimeout;
  this.testCase_ = testCase;
  this.onQueueComplete_ = onQueueComplete;
  this.armor_ = armor;
  this.pauseForHuman_ = !!opt_pauseForHuman;
  this.queueConstructor_ = opt_queueConstructor ||
      jstestdriver.plugins.async.DeferredQueue;
  this.queueArmorConstructor_ = opt_queueArmorConstructor ||
      jstestdriver.plugins.async.DeferredQueueArmor;
  this.poolConstructor_ = opt_poolConstructor ||
      jstestdriver.plugins.async.CallbackPool;
  this.poolArmorConstructor_ = opt_poolArmorConstructor ||
      jstestdriver.plugins.async.CallbackPoolArmor;
  this.descriptions_ = [];
  this.operations_ = [];
  this.errors_ = [];
};


/**
 * Executes a step of the test.
 * @param {Function} operation The next test step.
 * @param {Function} onQueueComplete The queue complete callback.
 * @private
 */
jstestdriver.plugins.async.DeferredQueue.prototype.execute_ = function(
    description, operation, onQueueComplete) {
  var queue = new (this.queueConstructor_)(this.setTimeout_,
      this.testCase_, onQueueComplete, this.armor_, this.pauseForHuman_);
  this.armor_.setQueue(queue);

  var onPoolComplete = function(errors) {
    queue.finishStep_(errors);
  };
  var pool = new (this.poolConstructor_)(
      this.setTimeout_, this.testCase_, onPoolComplete, description, this.pauseForHuman_);
  var poolArmor = new (this.poolArmorConstructor_)(pool);

  if (operation) {
    try {
      operation.call(this.testCase_, poolArmor, this.armor_);
    } catch (e) {
      pool.onError(e);
    }
  }

  pool.activate();
};


/**
 * Enqueues a test step.
 * @param {string} description The test step description.
 * @param {Function} operation The test step to add to the queue.
 */
jstestdriver.plugins.async.DeferredQueue.prototype.defer = function(
    description, operation) {
  this.descriptions_.push(description);
  this.operations_.push(operation);
};


/**
 * Starts the next test step.
 */
jstestdriver.plugins.async.DeferredQueue.prototype.startStep = function() {
  var nextDescription = this.descriptions_.shift();
  var nextOp = this.operations_.shift();
  if (nextOp) {
    var q = this;
    this.execute_(nextDescription, nextOp, function(errors) {
      q.finishStep_(errors);
    });
  } else {
    this.onQueueComplete_([]);
  }
};


/**
 * Finishes the current test step.
 * @param {Array.} errors An array of any errors that occurred during the
 *     previous test step.
 * @private
 */
jstestdriver.plugins.async.DeferredQueue.prototype.finishStep_ = function(
    errors) {
  this.errors_ = this.errors_.concat(errors);
  if (this.errors_.length) {
    this.onQueueComplete_(this.errors_);
  } else {
    this.startStep();
  }
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the DeferredQueueArmor class. Encapsulates a
 * DeferredQueue behind a narrower interface. Also, validates arguments.
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.DeferredQueueArmor');

goog.require('jstestdriver');

/**
 * Constructs a DeferredQueueArmor.
 * @param {function(Object)} toJson a function to convert objects to JSON.
 * @constructor
 */
jstestdriver.plugins.async.DeferredQueueArmor = function(toJson) {
  this.toJson_ = toJson;
  this.q_ = null;
  this.step_ = 1;
};


/**
 * Sets the current queue instance.
 * @param {jstestdriver.plugins.async.DeferredQueue} queue The queue.
 */
jstestdriver.plugins.async.DeferredQueueArmor.prototype.setQueue = function(
    queue) {
  this.q_ = queue;
};


/**
 * Adds a function to the queue to call later.
 * @param {string|Function} description The description or function.
 * @param {Function=} operation The function.
 * @return {jstestdriver.plugins.async.DeferredQueueArmor} This.
 */
jstestdriver.plugins.async.DeferredQueueArmor.prototype.call = function(
    description, operation) {
  if (!this.q_) {
    throw new Error('Queue undefined!');
  }

  if (typeof description == 'function') {
    operation = description;
    description = this.nextDescription_();
  }

  if (typeof description == 'object') {
    operation = description.operation;
    description = description.description;
  }

  if (!description) {
    description = this.nextDescription_();
  }

  if (operation) {
    this.q_.defer(description, operation);
    this.step_ += 1;
  }

  return this;
};


/**
 * @return {string} A description for the next step.
 */
jstestdriver.plugins.async.DeferredQueueArmor.prototype.nextDescription_ =
    function() {
  return '#' + this.step_;
};


/**
 * Adds a function to the queue to call later.
 * @param {string|Function} description The description or function.
 * @param {Function=} operation The function.
 * @deprecated Use DeferredQueueArmor#call().
 */
jstestdriver.plugins.async.DeferredQueueArmor.prototype.defer =
    jstestdriver.plugins.async.DeferredQueueArmor.prototype.call;
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the TestStage class.
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.TestStage');
goog.provide('jstestdriver.plugins.async.TestStage.Builder');

goog.require('jstestdriver');
goog.require('jstestdriver.setTimeout');
goog.require('jstestdriver.plugins.async.DeferredQueueArmor');
goog.require('jstestdriver.plugins.async.DeferredQueue');

/**
 * Constructs a TestStage.
 *
 * A TestStage is an executable portion of a test, such as setUp, tearDown, or
 * the test method.
 *
 * @param {Function} onError An error handler.
 * @param {Function} onStageComplete A callback for stage completion.
 * @param {Object} testCase The test case that owns this test stage.
 * @param {Function} testMethod The test method this stage represents.
 * @param {function(Object)} toJson a function to convert objects to JSON.
 * @param {Object} opt_argument An argument to pass to the test method.
 * @param {boolean} opt_pauseForHuman Whether to pause for debugging.
 * @param {Function} opt_armorConstructor The constructor of DeferredQueueArmor.
 * @param {Function} opt_queueConstructor The constructor of DeferredQueue.
 * @param {Function} opt_setTimeout The setTimeout function or suitable
 *     replacement.
 * @constructor
 */
jstestdriver.plugins.async.TestStage = function(
    onError, onStageComplete, testCase, testMethod, toJson, opt_argument,
    opt_pauseForHuman, opt_armorConstructor, opt_queueConstructor,
    opt_setTimeout) {
  this.onError_ = onError;
  this.onStageComplete_ = onStageComplete;
  this.testCase_ = testCase;
  this.testMethod_ = testMethod;
  this.toJson_ = toJson;
  this.argument_ = opt_argument;
  this.pauseForHuman_ = !!opt_pauseForHuman;
  this.armorConstructor_ = opt_armorConstructor ||
      jstestdriver.plugins.async.DeferredQueueArmor;
  this.queueConstructor_ = opt_queueConstructor ||
      jstestdriver.plugins.async.DeferredQueue;
  this.setTimeout_ = opt_setTimeout || jstestdriver.setTimeout;
};


/**
 * Executes this TestStage.
 */
jstestdriver.plugins.async.TestStage.prototype.execute = function() {
  var armor = new (this.armorConstructor_)(this.toJson_);
  var queue = new (this.queueConstructor_)(this.setTimeout_, this.testCase_,
      this.onStageComplete_, armor, this.pauseForHuman_);
  armor.setQueue(queue);

  if (this.testMethod_) {
    try {
      this.testMethod_.call(this.testCase_, armor, this.argument_);
    } catch (e) {
      this.onError_(e);
    }
  }

  queue.startStep();
};



/**
 * Constructor for a Builder of TestStages. Used to avoid confusion when
 * trying to construct TestStage objects (as the constructor takes a lot
 * of parameters of similar types).
 * @constructor
 */
jstestdriver.plugins.async.TestStage.Builder = function() {
  this.onError_ = null;
  this.onStageComplete_ = null;
  this.testCase_ = null;
  this.testMethod_ = null;
  this.toJson_ = null;
  this.opt_argument_ = null;
  this.opt_pauseForHuman_ = null;
  this.opt_armorConstructor_ = jstestdriver.plugins.async.DeferredQueueArmor;
  this.opt_queueConstructor_ = jstestdriver.plugins.async.DeferredQueue;
  this.opt_setTimeout_ = jstestdriver.setTimeout;
};


// Setters for the various fields; they return the Builder instance to allow
// method call chaining.
jstestdriver.plugins.async.TestStage.Builder.prototype.setOnError =
    function(onError) {
  this.onError_ = onError;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setOnStageComplete =
    function(onStageComplete) {
  this.onStageComplete_ = onStageComplete;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setTestCase =
    function(testCase) {
  this.testCase_ = testCase;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setTestMethod =
    function(testMethod) {
  this.testMethod_ = testMethod;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setToJson =
    function(toJson) {
  this.toJson_ = toJson;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setArgument =
    function(argument) {
  this.opt_argument_ = argument;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setPauseForHuman =
    function(pauseForHuman) {
  this.opt_pauseForHuman_ = pauseForHuman;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setArmorConstructor =
    function(armorConstructor) {
  this.opt_armorConstructor_ = armorConstructor;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setQueueConstructor =
    function(queueConstructor) {
  this.opt_queueConstructor_ = queueConstructor;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.setTimeoutSetter =
    function(setTimeout) {
  this.opt_setTimeout_ = setTimeout;
  return this;
};


jstestdriver.plugins.async.TestStage.Builder.prototype.build = function() {
  return new jstestdriver.plugins.async.TestStage(
      this.onError_, this.onStageComplete_, this.testCase_, this.testMethod_,
      this.toJson_, this.opt_argument_, this.opt_pauseForHuman_,
      this.opt_armorConstructor_, this.opt_queueConstructor_,
      this.opt_setTimeout_);
};
/*
 * Copyright 2009 Google 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.
 */
jstestdriver.plugins.ScriptLoader = function(win, dom, testCaseManager, now) {
  this.win_ = win;
  this.dom_ = dom;
  this.testCaseManager_ = testCaseManager;
  this.now_ = now;
};


jstestdriver.plugins.ScriptLoader.prototype.load = function(file, callback) {
  this.testCaseManager_.removeTestCaseForFilename(file.fileSrc);
  this.fileResult_ = null;
  var head = this.dom_.getElementsByTagName('head')[0];
  var script = this.dom_.createElement('script');
  var start = this.now_();

  if (!jstestdriver.jQuery.browser.opera) {
    script.onload = jstestdriver.bind(this, function() {
      this.cleanCallBacks(script)
      this.onLoad_(file, callback, start);
    });
  }
  script.onreadystatechange = jstestdriver.bind(this, function() {
    if (script.readyState === "loaded" || script.readyState === "complete") {
      this.cleanCallBacks(script)
      this.onLoad_(file, callback, start);
    }
  });

  var handleError = jstestdriver.bind(this, function(msg, url, line) {
    this.testCaseManager_.removeTestCaseForFilename(file.fileSrc);
    var loadMsg = 'error loading file: ' + file.fileSrc;

    if (line != undefined && line != null) {
      loadMsg += ':' + line;
    }
    if (msg != undefined && msg != null) {
      loadMsg += ': ' + msg;
    }
    this.cleanCallBacks(script)
    callback(new jstestdriver.FileResult(file, false, loadMsg));
  });
  this.win_.onerror = handleError; 
  script.onerror = handleError;

  script.type = "text/javascript";
  script.src = file.fileSrc;
  head.appendChild(script);

};

jstestdriver.plugins.ScriptLoader.prototype.cleanCallBacks = function(script) {
  script.onerror = jstestdriver.EMPTY_FUNC;
  script.onload = jstestdriver.EMPTY_FUNC;
  script.onreadystatechange = jstestdriver.EMPTY_FUNC;
  this.win_.onerror = jstestdriver.EMPTY_FUNC;
};


jstestdriver.plugins.ScriptLoader.prototype.onLoad_ =
    function(file, callback, start) {
  this.testCaseManager_.updateLatestTestCase(file.fileSrc);
  var result = new jstestdriver.FileResult(file, true, '', this.now_() - start);
  this.win_.onerror = jstestdriver.EMPTY_FUNC;
  callback(result);
};


jstestdriver.plugins.ScriptLoader.prototype.updateResult_ = function(fileResult) {
  if (this.fileResult_ == null) {
    this.fileResult_ = fileResult;
  }
};
/*
 * Copyright 2009 Google 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.
 */
jstestdriver.plugins.StylesheetLoader = function(win, dom, synchronousCallback) {
  this.win_ = win;
  this.dom_ = dom;
  this.synchronousCallback_ = synchronousCallback;
};


jstestdriver.plugins.StylesheetLoader.prototype.load = function(file, callback) {
  this.fileResult_ = null;
  var head = this.dom_.getElementsByTagName('head')[0];
  var link = this.dom_.createElement('link');
  var handleError = jstestdriver.bind(this, function(msg, url, line) {
    var loadMsg = 'error loading file: ' + file.fileSrc;

    if (line != undefined && line != null) {
      loadMsg += ':' + line;
    }
    if (msg != undefined && msg != null) {
      loadMsg += ': ' + msg;
    }
    this.updateResult_(new jstestdriver.FileResult(file, false, loadMsg));
  });

  this.win_.onerror = handleError;
  link.onerror = handleError;
  if (!jstestdriver.jQuery.browser.opera) {
    link.onload = jstestdriver.bind(this, function() {
      this.onLoad_(file, callback);
    });
  }
  link.onreadystatechange = jstestdriver.bind(this, function() {
    if (link.readyState == 'loaded') {
      this.onLoad_(file, callback);
    }
  });
  link.type = "text/css";
  link.rel = "stylesheet";
  link.href = file.fileSrc;
  head.appendChild(link);

  // Firefox and Safari don't seem to support onload or onreadystatechange for link
  if (this.synchronousCallback_) {
    this.onLoad_(file, callback);
  }
};


jstestdriver.plugins.StylesheetLoader.prototype.onLoad_ = function(file, callback) {
  this.updateResult_(new jstestdriver.FileResult(file, true, ''));
  this.win_.onerror = jstestdriver.EMPTY_FUNC;
  callback(this.fileResult_);  
};


jstestdriver.plugins.StylesheetLoader.prototype.updateResult_ = function(fileResult) {
  if (this.fileResult_ == null) {
    this.fileResult_ = fileResult;
  }
};
/*
 * Copyright 2009 Google 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.
 */
jstestdriver.plugins.FileLoaderPlugin = function(scriptLoader, stylesheetLoader) {
  this.scriptLoader_ = scriptLoader;
  this.stylesheetLoader_ = stylesheetLoader;
};


jstestdriver.plugins.FileLoaderPlugin.prototype.loadSource = function(file, onSourceLoaded) {
  if (file.fileSrc.match(/\.css$/)) {
    this.stylesheetLoader_.load(file, onSourceLoaded);
  } else {
    this.scriptLoader_.load(file, onSourceLoaded);
  }
};
/*
 * Copyright 2009 Google 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.
 */

/**
 * @param dateObj
 * @param clearBody
 * @param opt_runTestLoop
 * @constructor
 */
jstestdriver.plugins.TestRunnerPlugin = function(dateObj, clearBody, opt_runTestLoop) {
  this.dateObj_ = dateObj;
  this.clearBody_ = clearBody;
  this.boundRunTest_ = jstestdriver.bind(this, this.runTest);
  this.runTestLoop_ = opt_runTestLoop || jstestdriver.plugins.defaultRunTestLoop;
};


jstestdriver.plugins.createPausingRunTestLoop =
    function (interval, now, setTimeout) {
  var lastPause;
  function pausingRunTestLoop(testCaseName,
                              template,
                              tests,
                              runTest,
                              onTest,
                              onComplete) {
    var i = 0;
    lastPause = now();
    function nextTest() {
      if (tests[i]) {
        var test = tests[i++];
        jstestdriver.log("running " + testCaseName + '.' + test);
        onTest(runTest(testCaseName, template, test));
        if (now() - lastPause >= interval) {
          jstestdriver.log("pausing after " + testCaseName + '.' + test);
          lastPause = now();
          setTimeout(nextTest, 1);
        } else {
          nextTest();
        }
      } else {
        onComplete();
      }
    }
    nextTest();
  }
  return pausingRunTestLoop;
};


jstestdriver.plugins.pausingRunTestLoop =
    jstestdriver.plugins.createPausingRunTestLoop(
        0,
        jstestdriver.now,
        jstestdriver.setTimeout);


jstestdriver.plugins.defaultRunTestLoop =
    function(testCaseName, template, tests, runTest, onTest, onComplete) {
  for (var i = 0; tests[i]; i++) {
    onTest(runTest(testCaseName, template, tests[i]));
  }
  onComplete();
};


jstestdriver.plugins.TestRunnerPlugin.prototype.runTestConfiguration =
    function(testRunConfiguration, onTestDone, onTestRunConfigurationComplete) {
  var testCaseInfo = testRunConfiguration.getTestCaseInfo();
  var tests = testRunConfiguration.getTests();
  var size = tests.length;

  if (testCaseInfo.getType() != jstestdriver.TestCaseInfo.DEFAULT_TYPE) {
    for (var i = 0; tests[i]; i++) {
      onTestDone(new jstestdriver.TestResult(
          testCaseInfo.getTestCaseName(),
          tests[i],
          'error',
          testCaseInfo.getTestCaseName() +
            ' is an unhandled test case: ' +
            testCaseInfo.getType(),
          '',
          0));
    }
    onTestRunConfigurationComplete();
    return;
  }

  this.runTestLoop_(testCaseInfo.getTestCaseName(),
                    testCaseInfo.getTemplate(),
                    tests,
                    this.boundRunTest_,
                    onTestDone,
                    onTestRunConfigurationComplete)
};


jstestdriver.plugins.TestRunnerPlugin.prototype.runTest =
    function(testCaseName, testCase, testName) {
  var testCaseInstance;
  var errors = [];
  try {
    try {
      testCaseInstance = new testCase();
    } catch (e) {
      return new jstestdriver.TestResult(
          testCaseName,
          testName,
          jstestdriver.TestResult.RESULT.ERROR,
          testCaseName + ' is not a test case',
          '',
          0);
    }
    var start = new this.dateObj_().getTime();
  
    jstestdriver.expectedAssertCount = -1;
    jstestdriver.assertCount = 0;
    var res = jstestdriver.TestResult.RESULT.PASSED;
    try {
      if (testCaseInstance.setUp) {
        testCaseInstance.setUp();
      }
      if (!(testName in testCaseInstance)) {
        var err = new Error(testName + ' not found in ' + testCaseName);
        err.name = 'AssertError';
        throw err;
      }
      testCaseInstance[testName]();
      if (jstestdriver.expectedAssertCount != -1 &&
          jstestdriver.expectedAssertCount != jstestdriver.assertCount) {
        var err = new Error("Expected '" +
            jstestdriver.expectedAssertCount +
            "' asserts but '" +
            jstestdriver.assertCount +
            "' encountered.");
  
        err.name = 'AssertError';
        throw err;
      }
    } catch (e) {
      // We use the global here because of a circular dependency. The isFailure plugin should be
      // refactored.
      res = jstestdriver.pluginRegistrar.isFailure(e) ?
          jstestdriver.TestResult.RESULT.FAILED :
            jstestdriver.TestResult.RESULT.ERROR;
      errors.push(e);
    }
    try {
      if (testCaseInstance.tearDown) {
        testCaseInstance.tearDown();
      }
      this.clearBody_();
    } catch (e) {
      if (res == jstestdriver.TestResult.RESULT.PASSED) {
        res = jstestdriver.TestResult.RESULT.ERROR;
      }
      errors.push(e);
    }
    var end = new this.dateObj_().getTime();
    var msg = this.serializeError(errors);
    return new jstestdriver.TestResult(testCaseName, testName, res, msg,
            jstestdriver.console.getAndResetLog(), end - start);
  } catch (e) {
    errors.push(e);
    return new jstestdriver.TestResult(testCaseName, testName,
            'error', 'Unexpected runner error: ' + this.serializeError(errors),
            jstestdriver.console.getAndResetLog(), 0);
  }
};

/**
 *@param {Error} e
 */
jstestdriver.plugins.TestRunnerPlugin.prototype.serializeError = function(e) {
  return jstestdriver.utils.serializeObject(e);
};
/*
 * Copyright 2010 Google 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.
 */


/**
 * @fileoverview Defines the AsyncTestRunnerPlugin class, which executes
 * asynchronous test cases within JsTestDriver.
 *
 *     +----------------------------- more tests? ------------ nextTest() <--------------+
 *     |                                                                                 |
 *     v                                                                                 |
 * startSetUp() ---- execute ---> finishSetUp(errors)                                    |
 *                                     |                                                 |
 * startTestMethod() <--- no errors ---+---- errors ----+                                |
 *        |                                             |                                |
 *     execute                                          |                                |
 *        |                                             |                                |
 *        v                                             v                                |
 * finishTestMethod(errors) -- errors or no errors -> startTearDown() -- execute -> finishTearDown(errors)
 *
 * @author [email protected] (Robert Dionne)
 */

goog.provide('jstestdriver.plugins.async.AsyncTestRunnerPlugin');

goog.require('jstestdriver');
goog.require('jstestdriver.setTimeout');
goog.require('jstestdriver.TestCaseInfo');
goog.require('jstestdriver.TestResult');
goog.require('jstestdriver.plugins.async.CallbackPool');
goog.require('jstestdriver.plugins.async.CallbackPoolArmor');
goog.require('jstestdriver.plugins.async.DeferredQueue');
goog.require('jstestdriver.plugins.async.DeferredQueueArmor');
goog.require('jstestdriver.plugins.async.TestStage');
goog.require('jstestdriver.plugins.async.TestStage.Builder');

/**
 * Constructs an AsyncTestRunnerPlugin.
 *
 * @param {Function} dateObj the date object constructor
 * @param {Function} clearBody a function to call to clear the document body.
 * @param {Function} toJson a function to call to convert an object to JSON.
 * @param {boolean} opt_pauseForHuman Whether to pause for debugging.
 * @param {Function} opt_setTimeout window.setTimeout replacement.
 * @param {Function} opt_queueConstructor a constructor for obtaining new
 *     DeferredQueues.
 * @param {Function} opt_armorConstructor a constructor for obtaining new
 *     DeferredQueueArmors.
 * @constructor
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin = function(dateObj, clearBody,
      toJson, opt_pauseForHuman, opt_setTimeout, opt_queueConstructor,
      opt_armorConstructor) {
  this.name = "AsyncTestRunnerPlugin";
  this.dateObj_ = dateObj;
  this.clearBody_ = clearBody;
  this.toJson_ = toJson;
  this.pauseForHuman_ = !!opt_pauseForHuman;
  this.setTimeout_ = opt_setTimeout || jstestdriver.setTimeout;
  this.queueConstructor_ = opt_queueConstructor || jstestdriver.plugins.async.DeferredQueue;
  this.armorConstructor_ = opt_armorConstructor || jstestdriver.plugins.async.DeferredQueueArmor;
  this.testRunConfiguration_ = null;
  this.testCaseInfo_ = null;
  this.onTestDone_ = null;
  this.onTestRunConfigurationComplete_ = null;
  this.testIndex_ = 0;
  this.testCase_ = null;
  this.testName_ = null;
  this.start_ = null;
  this.errors_ = null;
};

/**
 * Runs a test case.
 *
 * @param {jstestdriver.TestRunConfiguration} testRunConfiguration the test 
 *        case configuration
 * @param {function(jstestdriver.TestResult)} onTestDone the function to call to 
 *        report a test is complete
 * @param {function()=} opt_onTestRunConfigurationComplete the function to call 
 *        to report a test case is complete. A no-op will be used if this is
 *        not specified.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.runTestConfiguration = function(
    testRunConfiguration, onTestDone, opt_onTestRunConfigurationComplete) {
  if (testRunConfiguration.getTestCaseInfo().getType() == jstestdriver.TestCaseInfo.ASYNC_TYPE) {
    this.testRunConfiguration_ = testRunConfiguration;
    this.testCaseInfo_ = testRunConfiguration.getTestCaseInfo();
    this.onTestDone_ = onTestDone;
    this.onTestRunConfigurationComplete_ = opt_onTestRunConfigurationComplete ||
        function() {};
    this.testIndex_ = 0;
    this.nextTest();
    return true;
  }

  return false;
};

/**
 * Runs the next test in the current test case.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.nextTest = function() {
  this.start_ = new this.dateObj_().getTime();
  if (this.testIndex_ < this.testRunConfiguration_.getTests().length) {
    jstestdriver.expectedAssertCount = -1;
    jstestdriver.assertCount = 0;
    this.testCase_ = new (this.testCaseInfo_.getTemplate());
    this.testName_ = this.testRunConfiguration_.getTests()[this.testIndex_];
    this.errors_ = [];
    this.startSetUp();
  } else {
    this.testRunConfiguration_ = null;
    this.testCaseInfo_ = null;
    this.onTestDone_ = null;
    this.testIndex_ = 0;
    this.testCase_ = null;
    this.testName_ = null;
    this.start_ = null;
    this.errors_ = null;

    // Unset this callback before running it because the next callback may be
    // set by the code run by the callback.
    var onTestRunConfigurationComplete = this.onTestRunConfigurationComplete_;
    this.onTestRunConfigurationComplete_ = null;
    onTestRunConfigurationComplete.call(this);
  }
};


/**
 * Starts the next phase of the current test in the current test case. Creates a
 * DeferredQueue to manage the steps of this phase, executes the phase
 * catching any exceptions, and then hands the control over to the queue to
 * call onQueueComplete when it empties.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.execute_ = function(
    onStageComplete, invokeMethod) {
  var runner = this;
  var onError = function(error) {runner.errors_.push(error);};
  var stage = new jstestdriver.plugins.async.TestStage.Builder().
      setOnError(onError).
      setOnStageComplete(onStageComplete).
      setTestCase(this.testCase_).
      setTestMethod(invokeMethod).
      setPauseForHuman(this.pauseForHuman_).
      setArmorConstructor(this.armorConstructor_).
      setQueueConstructor(this.queueConstructor_).
      setTimeoutSetter(this.setTimeout_).
      setToJson(this.toJson_).
      build();
  stage.execute();
};


/**
 * Starts the setUp phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.startSetUp = function() {
  var runner = this;
  this.execute_(function(errors) {
    runner.finishSetUp(errors);
  }, this.testCase_['setUp']);
};

/**
 * Finishes the setUp phase and reports any errors. If there are errors it
 * initiates the tearDown phase, otherwise initiates the testMethod phase.
 *
 * @param errors errors caught during the current asynchronous phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.finishSetUp = function(errors) {
  this.errors_ = this.errors_.concat(errors);
  if (this.errors_.length) {
    this.startTearDown();
  } else {
    this.startTestMethod();
  }
};

/**
 * Starts the testMethod phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.startTestMethod = function() {
  var runner = this;
  this.execute_(function(errors) {
    runner.finishTestMethod(errors);
  }, this.testCase_[this.testName_]);
};

/**
 * Finishes the testMethod phase and reports any errors. Continues with the
 * tearDown phase.
 *
 * @param errors errors caught during the current asynchronous phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.finishTestMethod = function(errors) {
  this.errors_ = this.errors_.concat(errors);
  this.startTearDown();
};


/**
 * Start the tearDown phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.startTearDown = function() {
  var runner = this;
  this.execute_(function(errors){
    runner.finishTearDown(errors);
  }, this.testCase_['tearDown']);
};


/**
 * Finishes the tearDown phase and reports any errors. Submits the test results
 * to the test runner. Continues with the next test.
 *
 * @param errors errors caught during the current asynchronous phase.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.finishTearDown = function(errors) {
  this.errors_ = this.errors_.concat(errors);
  this.clearBody_();
  this.onTestDone_(this.buildResult());
  this.testIndex_ += 1;
  this.nextTest();
};

/**
 * Builds a test result.
 */
jstestdriver.plugins.async.AsyncTestRunnerPlugin.prototype.buildResult = function() {
  var end = new this.dateObj_().getTime();
  var result = jstestdriver.TestResult.RESULT.PASSED;
  var message = '';
  if (this.errors_.length) {
    result = jstestdriver.TestResult.RESULT.FAILED;
    message = this.toJson_(this.errors_);
  } else if (jstestdriver.expectedAssertCount != -1 &&
             jstestdriver.expectedAssertCount != jstestdriver.assertCount) {
    result = jstestdriver.TestResult.RESULT.FAILED;
    message = this.toJson_([new Error("Expected '" +
        jstestdriver.expectedAssertCount +
        "' asserts but '" +
        jstestdriver.assertCount +
        "' encountered.")]);
  }
  return new jstestdriver.TestResult(
      this.testCaseInfo_.getTestCaseName(), this.testName_, result, message,
      jstestdriver.console.getAndResetLog(), end - this.start_);
};
/*
 * Copyright 2009 Google 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.
 */
jstestdriver.plugins.DefaultPlugin = function(fileLoaderPlugin,
                                              testRunnerPlugin,
                                              assertsPlugin,
                                              testCaseManagerPlugin) {
  this.fileLoaderPlugin_ = fileLoaderPlugin;
  this.testRunnerPlugin_ = testRunnerPlugin;
  this.assertsPlugin_ = assertsPlugin;
  this.testCaseManagerPlugin_ = testCaseManagerPlugin;
};


jstestdriver.plugins.DefaultPlugin.prototype.name = 'defaultPlugin';


jstestdriver.plugins.DefaultPlugin.prototype.loadSource = function(file, onSourceLoaded) {
  return this.fileLoaderPlugin_.loadSource(file, onSourceLoaded);
};


jstestdriver.plugins.DefaultPlugin.prototype.runTestConfiguration = function(testRunConfiguration,
    onTestDone, onTestRunConfigurationComplete) {
  return this.testRunnerPlugin_.runTestConfiguration(testRunConfiguration, onTestDone,
      onTestRunConfigurationComplete);
};


jstestdriver.plugins.DefaultPlugin.prototype.isFailure = function(exception) {
  return this.assertsPlugin_.isFailure(exception);
};


jstestdriver.plugins.DefaultPlugin.prototype.getTestRunsConfigurationFor =
    function(testCaseInfos, expressions, testRunsConfiguration) {
  return this.testCaseManagerPlugin_.getTestRunsConfigurationFor(testCaseInfos,
                                                                expressions,
                                                                testRunsConfiguration);
};


jstestdriver.plugins.DefaultPlugin.prototype.onTestsStart =
    jstestdriver.EMPTY_FUNC;


jstestdriver.plugins.DefaultPlugin.prototype.onTestsFinish =
  jstestdriver.EMPTY_FUNC;
/*
 * Copyright 2009 Google 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.
 */
jstestdriver.plugins.AssertsPlugin = function() {
};


jstestdriver.plugins.AssertsPlugin.prototype.isFailure = function(e) {
  return e.name == 'AssertError';
};
/*
 * Copyright 2009 Google 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.
 */


/**
 * Plugin that handles the default behavior for the TestCaseManager.
 * @author [email protected] (Cory Smith)
 */
jstestdriver.plugins.TestCaseManagerPlugin = function() {};


/**
 * Write testRunconfigurations retrieved from testCaseInfos defined by expressions.
 * @param {Array.} testCaseInfos The loaded test case infos.
 * @param {Array.} The expressions that define the TestRunConfigurations
 * @parma {Array.} The resultant array of configurations.
 */
jstestdriver.plugins.TestCaseManagerPlugin.prototype.getTestRunsConfigurationFor =
    function(testCaseInfos, expressions, testRunsConfiguration) {
  var size = testCaseInfos.length;
  for (var i = 0; i < size; i++) {
    var testCaseInfo = testCaseInfos[i];
    var testRunConfiguration = testCaseInfo.getTestRunConfigurationFor(expressions);

    if (testRunConfiguration != null) {
      testRunsConfiguration.push(testRunConfiguration);
    }
  }
  return true;
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy