src/cm/media/js/lib/yui/yui3-3.15.0/build/test/test-debug.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('test', function (Y, NAME) {
       
     2 
       
     3 
       
     4 
       
     5 /**
       
     6  * YUI Test Framework
       
     7  * @module test
       
     8  * @main test
       
     9  */
       
    10 
       
    11 /*
       
    12  * The root namespace for YUI Test.
       
    13  */
       
    14 
       
    15 //So we only ever have one YUITest object that's shared
       
    16 if (YUI.YUITest) {
       
    17     Y.Test = YUI.YUITest;
       
    18 } else { //Ends after the YUITest definitions
       
    19 
       
    20     //Make this global for back compat
       
    21     YUITest = {
       
    22         version: "@VERSION@",
       
    23         guid: function(pre) {
       
    24             return Y.guid(pre);
       
    25         }
       
    26     };
       
    27 
       
    28 Y.namespace('Test');
       
    29 
       
    30 
       
    31 //Using internal YUI methods here
       
    32 YUITest.Object = Y.Object;
       
    33 YUITest.Array = Y.Array;
       
    34 YUITest.Util = {
       
    35     mix: Y.mix,
       
    36     JSON: Y.JSON
       
    37 };
       
    38 
       
    39 /**
       
    40  * Simple custom event implementation.
       
    41  * @namespace Test
       
    42  * @module test
       
    43  * @class EventTarget
       
    44  * @constructor
       
    45  */
       
    46 YUITest.EventTarget = function(){
       
    47 
       
    48     /**
       
    49      * Event handlers for the various events.
       
    50      * @type Object
       
    51      * @private
       
    52      * @property _handlers
       
    53      * @static
       
    54      */
       
    55     this._handlers = {};
       
    56 
       
    57 };
       
    58 
       
    59 YUITest.EventTarget.prototype = {
       
    60 
       
    61     //restore prototype
       
    62     constructor: YUITest.EventTarget,
       
    63 
       
    64     //-------------------------------------------------------------------------
       
    65     // Event Handling
       
    66     //-------------------------------------------------------------------------
       
    67 
       
    68     /**
       
    69      * Adds a listener for a given event type.
       
    70      * @param {String} type The type of event to add a listener for.
       
    71      * @param {Function} listener The function to call when the event occurs.
       
    72      * @method attach
       
    73      */
       
    74     attach: function(type, listener){
       
    75         if (typeof this._handlers[type] == "undefined"){
       
    76             this._handlers[type] = [];
       
    77         }
       
    78 
       
    79         this._handlers[type].push(listener);
       
    80     },
       
    81 
       
    82     /**
       
    83      * Adds a listener for a given event type.
       
    84      * @param {String} type The type of event to add a listener for.
       
    85      * @param {Function} listener The function to call when the event occurs.
       
    86      * @method subscribe
       
    87      * @deprecated
       
    88      */
       
    89     subscribe: function(type, listener){
       
    90         this.attach.apply(this, arguments);
       
    91     },
       
    92 
       
    93     /**
       
    94      * Fires an event based on the passed-in object.
       
    95      * @param {Object|String} event An object with at least a 'type' attribute
       
    96      *      or a string indicating the event name.
       
    97      * @method fire
       
    98      */
       
    99     fire: function(event){
       
   100         if (typeof event == "string"){
       
   101             event = { type: event };
       
   102         }
       
   103         if (!event.target){
       
   104             event.target = this;
       
   105         }
       
   106 
       
   107         if (!event.type){
       
   108             throw new Error("Event object missing 'type' property.");
       
   109         }
       
   110 
       
   111         if (this._handlers[event.type] instanceof Array){
       
   112             var handlers = this._handlers[event.type];
       
   113             for (var i=0, len=handlers.length; i < len; i++){
       
   114                 handlers[i].call(this, event);
       
   115             }
       
   116         }
       
   117     },
       
   118 
       
   119     /**
       
   120      * Removes a listener for a given event type.
       
   121      * @param {String} type The type of event to remove a listener from.
       
   122      * @param {Function} listener The function to remove from the event.
       
   123      * @method detach
       
   124      */
       
   125     detach: function(type, listener){
       
   126         if (this._handlers[type] instanceof Array){
       
   127             var handlers = this._handlers[type];
       
   128             for (var i=0, len=handlers.length; i < len; i++){
       
   129                 if (handlers[i] === listener){
       
   130                     handlers.splice(i, 1);
       
   131                     break;
       
   132                 }
       
   133             }
       
   134         }
       
   135     },
       
   136 
       
   137     /**
       
   138      * Removes a listener for a given event type.
       
   139      * @param {String} type The type of event to remove a listener from.
       
   140      * @param {Function} listener The function to remove from the event.
       
   141      * @method unsubscribe
       
   142      * @deprecated
       
   143      */
       
   144     unsubscribe: function(type, listener){
       
   145         this.detach.apply(this, arguments);
       
   146     }
       
   147 
       
   148 };
       
   149 
       
   150 
       
   151 /**
       
   152  * A test suite that can contain a collection of TestCase and TestSuite objects.
       
   153  * @param {String||Object} data The name of the test suite or an object containing
       
   154  *      a name property as well as setUp and tearDown methods.
       
   155  * @namespace Test
       
   156  * @module test
       
   157  * @class TestSuite
       
   158  * @constructor
       
   159  */
       
   160 YUITest.TestSuite = function (data) {
       
   161 
       
   162     /**
       
   163      * The name of the test suite.
       
   164      * @type String
       
   165      * @property name
       
   166      */
       
   167     this.name = "";
       
   168 
       
   169     /**
       
   170      * Array of test suites and test cases.
       
   171      * @type Array
       
   172      * @property items
       
   173      * @private
       
   174      */
       
   175     this.items = [];
       
   176 
       
   177     //initialize the properties
       
   178     if (typeof data == "string"){
       
   179         this.name = data;
       
   180     } else if (data instanceof Object){
       
   181         for (var prop in data){
       
   182             if (data.hasOwnProperty(prop)){
       
   183                 this[prop] = data[prop];
       
   184             }
       
   185         }
       
   186     }
       
   187 
       
   188     //double-check name
       
   189     if (this.name === "" || !this.name) {
       
   190         this.name = YUITest.guid("testSuite_");
       
   191     }
       
   192 
       
   193 };
       
   194 
       
   195 YUITest.TestSuite.prototype = {
       
   196 
       
   197     //restore constructor
       
   198     constructor: YUITest.TestSuite,
       
   199 
       
   200     /**
       
   201      * Adds a test suite or test case to the test suite.
       
   202      * @param {Test.TestSuite||YUITest.TestCase} testObject The test suite or test case to add.
       
   203      * @method add
       
   204      */
       
   205     add : function (testObject) {
       
   206         if (testObject instanceof YUITest.TestSuite || testObject instanceof YUITest.TestCase) {
       
   207             this.items.push(testObject);
       
   208         }
       
   209         return this;
       
   210     },
       
   211 
       
   212     //-------------------------------------------------------------------------
       
   213     // Stub Methods
       
   214     //-------------------------------------------------------------------------
       
   215 
       
   216     /**
       
   217      * Function to run before each test is executed.
       
   218      * @method setUp
       
   219      */
       
   220     setUp : function () {
       
   221     },
       
   222 
       
   223     /**
       
   224      * Function to run after each test is executed.
       
   225      * @method tearDown
       
   226      */
       
   227     tearDown: function () {
       
   228     }
       
   229 
       
   230 };
       
   231 /**
       
   232  * Test case containing various tests to run.
       
   233  * @param template An object containing any number of test methods, other methods,
       
   234  *                 an optional name, and anything else the test case needs.
       
   235  * @module test
       
   236  * @class TestCase
       
   237  * @namespace Test
       
   238  * @constructor
       
   239  */
       
   240 
       
   241 
       
   242 
       
   243 YUITest.TestCase = function (template) {
       
   244 
       
   245     /*
       
   246      * Special rules for the test case. Possible subobjects
       
   247      * are fail, for tests that should fail, and error, for
       
   248      * tests that should throw an error.
       
   249      */
       
   250     this._should = {};
       
   251 
       
   252     //copy over all properties from the template to this object
       
   253     for (var prop in template) {
       
   254         this[prop] = template[prop];
       
   255     }
       
   256 
       
   257     //check for a valid name
       
   258     if (typeof this.name != "string") {
       
   259         this.name = YUITest.guid("testCase_");
       
   260     }
       
   261 
       
   262 };
       
   263 
       
   264 /**
       
   265 Default delay for a test failure when `wait()` is called without a _delay_.
       
   266 
       
   267 @property DEFAULT_WAIT
       
   268 @type {Number}
       
   269 @default 10000
       
   270 @static
       
   271 **/
       
   272 YUITest.TestCase.DEFAULT_WAIT = 10000;
       
   273 
       
   274 /**
       
   275 Calls `YUITest.Assert.fail()` with a message indicating `wait()` was called,
       
   276 but `resume()` was never called.
       
   277  
       
   278 @method _waitTimeout
       
   279 @static
       
   280 @protected
       
   281 **/
       
   282 YUITest.TestCase._waitTimeout = function () {
       
   283      YUITest.Assert.fail("Timeout: wait() called but resume() never called.");
       
   284 };
       
   285 
       
   286 YUITest.TestCase.prototype = {
       
   287 
       
   288     //restore constructor
       
   289     constructor: YUITest.TestCase,
       
   290 
       
   291     /**
       
   292      * Method to call from an async init method to
       
   293      * restart the test case. When called, returns a function
       
   294      * that should be called when tests are ready to continue.
       
   295      * @method callback
       
   296      * @return {Function} The function to call as a callback.
       
   297      */
       
   298     callback: function(){
       
   299         return YUITest.TestRunner.callback.apply(YUITest.TestRunner,arguments);
       
   300     },
       
   301 
       
   302     /**
       
   303      * Resumes a paused test and runs the given function.
       
   304      * @param {Function} segment (Optional) The function to run.
       
   305      *      If omitted, the test automatically passes.
       
   306      * @method resume
       
   307      */
       
   308     resume : function (segment) {
       
   309         YUITest.TestRunner.resume(segment);
       
   310     },
       
   311 
       
   312     /**
       
   313      * Causes the test case to wait a specified amount of time and then
       
   314      * continue executing the given code.
       
   315      * @param {Function} segment (Optional) The function to run after the delay.
       
   316      *      If omitted, the TestRunner will wait until resume() is called.
       
   317      * @param {Number} delay (Optional) The number of milliseconds to wait before running
       
   318      *      the function. If omitted, defaults to `DEFAULT_WAIT` ms (10s).
       
   319      * @method wait
       
   320      */
       
   321     wait : function (segment, delay){
       
   322         delay = (typeof segment === 'number') ? segment :
       
   323                 (typeof delay   === 'number') ? delay :
       
   324                 YUITest.TestCase.DEFAULT_WAIT;
       
   325 
       
   326         if (typeof segment !== 'function') {
       
   327             segment = YUITest.TestCase._waitTimeout;
       
   328         }
       
   329 
       
   330         throw new YUITest.Wait(segment, delay);
       
   331     },
       
   332 
       
   333     /**
       
   334     Creates a callback that automatically resumes the test. Parameters as passed
       
   335     on to the callback.
       
   336 
       
   337     @method next
       
   338     @param {Function} callback Callback to call after resuming the test.
       
   339     @return {Function} wrapped callback that resumes the test.
       
   340     @example
       
   341     ```
       
   342     // using test.resume()
       
   343     Y.jsonp(uri, function (response) {
       
   344         test.resume(function () {
       
   345             Y.Assert.isObject(response);
       
   346         });
       
   347     });
       
   348     test.wait();
       
   349 
       
   350     // using test.next()
       
   351     Y.jsonp(uri, test.next(function (response) {
       
   352         Y.Assert.isObject(response);
       
   353     }));
       
   354     test.wait();
       
   355     ```
       
   356     **/
       
   357     next: function (callback) {
       
   358         var self = this;
       
   359         return function () {
       
   360             var args = arguments;
       
   361             self.resume(function () {
       
   362                 callback.apply(this, args);
       
   363             });
       
   364         };
       
   365     },
       
   366 
       
   367     /**
       
   368     Delays the current test until _condition_ returns a truthy value. If
       
   369     _condition_ fails to return a truthy value before _timeout_ milliseconds
       
   370     have passed, the test fails. Default _timeout_ is 10s.
       
   371     
       
   372     _condition_ will be executed every _increment_ milliseconds (default 100).
       
   373     
       
   374     @method waitFor
       
   375     @param {Function} condition Function executed to indicate whether to
       
   376                         execute _segment_
       
   377     @param {Function} segment Function to check the success or failure of this
       
   378                         test
       
   379     @param {Number} [timeout=10000] Maximum number of milliseconds to wait for
       
   380                         _condition_ to return true
       
   381     @param {Number} [increment=100] Milliseconds to wait before checking
       
   382                         _condition_
       
   383     **/
       
   384     waitFor: function (condition, segment, timeout, increment) {
       
   385         var self = this,
       
   386             endTime;
       
   387  
       
   388         if ((typeof condition !== 'function') ||
       
   389             (typeof segment !== 'function')) {
       
   390             self.fail('waitFor() called with invalid parameters.');
       
   391         }
       
   392         
       
   393         if (typeof timeout !== 'number') {
       
   394             timeout = YUITest.TestCase.DEFAULT_WAIT;
       
   395         }
       
   396         
       
   397         endTime = (+new Date()) + timeout;
       
   398         
       
   399         if (typeof increment !== 'number') {
       
   400             increment = 100;
       
   401         }
       
   402         
       
   403         self.wait(function () {
       
   404             var now;
       
   405 
       
   406             if (condition.call(self)) {
       
   407                 segment.call(self);
       
   408             } else {
       
   409                 now = (+new Date());
       
   410                 
       
   411                 if (now > endTime) {
       
   412                     YUITest.TestCase._waitTimeout();
       
   413                 } else {
       
   414                     self.waitFor(condition, segment, endTime - now, increment);
       
   415                 }
       
   416             }
       
   417         }, increment);
       
   418     },
       
   419 
       
   420     //-------------------------------------------------------------------------
       
   421     // Assertion Methods
       
   422     //-------------------------------------------------------------------------
       
   423 
       
   424     /**
       
   425      * Asserts that a given condition is true. If not, then a YUITest.AssertionError object is thrown
       
   426      * and the test fails.
       
   427      * @method assert
       
   428      * @param {Boolean} condition The condition to test.
       
   429      * @param {String} message The message to display if the assertion fails.
       
   430      */
       
   431     assert : function (condition, message){
       
   432         YUITest.Assert._increment();
       
   433         if (!condition){
       
   434             throw new YUITest.AssertionError(YUITest.Assert._formatMessage(message, "Assertion failed."));
       
   435         }
       
   436     },
       
   437 
       
   438     /**
       
   439      * Forces an assertion error to occur. Shortcut for YUITest.Assert.fail().
       
   440      * @method fail
       
   441      * @param {String} message (Optional) The message to display with the failure.
       
   442      */
       
   443     fail: function (message) {
       
   444         YUITest.Assert.fail(message);
       
   445     },
       
   446 
       
   447     //-------------------------------------------------------------------------
       
   448     // Stub Methods
       
   449     //-------------------------------------------------------------------------
       
   450 
       
   451     /**
       
   452      * Function to run once before tests start to run.
       
   453      * This executes before the first call to setUp().
       
   454      * @method init
       
   455      */
       
   456     init: function(){
       
   457         //noop
       
   458     },
       
   459 
       
   460     /**
       
   461      * Function to run once after tests finish running.
       
   462      * This executes after the last call to tearDown().
       
   463      * @method destroy
       
   464      */
       
   465     destroy: function(){
       
   466         //noop
       
   467     },
       
   468 
       
   469     /**
       
   470      * Function to run before each test is executed.
       
   471      * @method setUp
       
   472      */
       
   473     setUp : function () {
       
   474         //noop
       
   475     },
       
   476 
       
   477     /**
       
   478      * Function to run after each test is executed.
       
   479      * @method tearDown
       
   480      */
       
   481     tearDown: function () {
       
   482         //noop
       
   483     }
       
   484 };
       
   485 /**
       
   486  * An object object containing test result formatting methods.
       
   487  * @namespace Test
       
   488  * @module test
       
   489  * @class TestFormat
       
   490  * @static
       
   491  */
       
   492 YUITest.TestFormat = function(){
       
   493 
       
   494     /* (intentionally not documented)
       
   495      * Basic XML escaping method. Replaces quotes, less-than, greater-than,
       
   496      * apostrophe, and ampersand characters with their corresponding entities.
       
   497      * @param {String} text The text to encode.
       
   498      * @return {String} The XML-escaped text.
       
   499      */
       
   500     function xmlEscape(text){
       
   501 
       
   502         return text.replace(/[<>"'&]/g, function(value){
       
   503             switch(value){
       
   504                 case "<":   return "&lt;";
       
   505                 case ">":   return "&gt;";
       
   506                 case "\"":  return "&quot;";
       
   507                 case "'":   return "&apos;";
       
   508                 case "&":   return "&amp;";
       
   509             }
       
   510         });
       
   511 
       
   512     }
       
   513 
       
   514 
       
   515     return {
       
   516 
       
   517         /**
       
   518          * Returns test results formatted as a JSON string. Requires JSON utility.
       
   519          * @param {Object} result The results object created by TestRunner.
       
   520          * @return {String} A JSON-formatted string of results.
       
   521          * @method JSON
       
   522          * @static
       
   523          */
       
   524         JSON: function(results) {
       
   525             return YUITest.Util.JSON.stringify(results);
       
   526         },
       
   527 
       
   528         /**
       
   529          * Returns test results formatted as an XML string.
       
   530          * @param {Object} result The results object created by TestRunner.
       
   531          * @return {String} An XML-formatted string of results.
       
   532          * @method XML
       
   533          * @static
       
   534          */
       
   535         XML: function(results) {
       
   536 
       
   537             function serializeToXML(results){
       
   538                 var xml = "<" + results.type + " name=\"" + xmlEscape(results.name) + "\"";
       
   539 
       
   540                 if (typeof(results.duration)=="number"){
       
   541                     xml += " duration=\"" + results.duration + "\"";
       
   542                 }
       
   543 
       
   544                 if (results.type == "test"){
       
   545                     xml += " result=\"" + results.result + "\" message=\"" + xmlEscape(results.message) + "\">";
       
   546                 } else {
       
   547                     xml += " passed=\"" + results.passed + "\" failed=\"" + results.failed + "\" ignored=\"" + results.ignored + "\" total=\"" + results.total + "\">";
       
   548                     for (var prop in results){
       
   549                         if (results.hasOwnProperty(prop)){
       
   550                             if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   551                                 xml += serializeToXML(results[prop]);
       
   552                             }
       
   553                         }
       
   554                     }
       
   555                 }
       
   556 
       
   557                 xml += "</" + results.type + ">";
       
   558 
       
   559                 return xml;
       
   560             }
       
   561 
       
   562             return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToXML(results);
       
   563 
       
   564         },
       
   565 
       
   566 
       
   567         /**
       
   568          * Returns test results formatted in JUnit XML format.
       
   569          * @param {Object} result The results object created by TestRunner.
       
   570          * @return {String} An XML-formatted string of results.
       
   571          * @method JUnitXML
       
   572          * @static
       
   573          */
       
   574         JUnitXML: function(results) {
       
   575 
       
   576             function serializeToJUnitXML(results){
       
   577                 var xml = "";
       
   578 
       
   579                 switch (results.type){
       
   580                     //equivalent to testcase in JUnit
       
   581                     case "test":
       
   582                         if (results.result != "ignore"){
       
   583                             xml = "<testcase name=\"" + xmlEscape(results.name) + "\" time=\"" + (results.duration/1000) + "\">";
       
   584                             if (results.result == "fail"){
       
   585                                 xml += "<failure message=\"" + xmlEscape(results.message) + "\"><![CDATA[" + results.message + "]]></failure>";
       
   586                             }
       
   587                             xml+= "</testcase>";
       
   588                         }
       
   589                         break;
       
   590 
       
   591                     //equivalent to testsuite in JUnit
       
   592                     case "testcase":
       
   593 
       
   594                         xml = "<testsuite name=\"" + xmlEscape(results.name) + "\" tests=\"" + results.total + "\" failures=\"" + results.failed + "\" time=\"" + (results.duration/1000) + "\">";
       
   595 
       
   596                         for (var prop in results){
       
   597                             if (results.hasOwnProperty(prop)){
       
   598                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   599                                     xml += serializeToJUnitXML(results[prop]);
       
   600                                 }
       
   601                             }
       
   602                         }
       
   603 
       
   604                         xml += "</testsuite>";
       
   605                         break;
       
   606 
       
   607                     //no JUnit equivalent, don't output anything
       
   608                     case "testsuite":
       
   609                         for (var prop in results){
       
   610                             if (results.hasOwnProperty(prop)){
       
   611                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   612                                     xml += serializeToJUnitXML(results[prop]);
       
   613                                 }
       
   614                             }
       
   615                         }
       
   616                         break;
       
   617 
       
   618                     //top-level, equivalent to testsuites in JUnit
       
   619                     case "report":
       
   620 
       
   621                         xml = "<testsuites>";
       
   622 
       
   623                         for (var prop in results){
       
   624                             if (results.hasOwnProperty(prop)){
       
   625                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   626                                     xml += serializeToJUnitXML(results[prop]);
       
   627                                 }
       
   628                             }
       
   629                         }
       
   630 
       
   631                         xml += "</testsuites>";
       
   632 
       
   633                     //no default
       
   634                 }
       
   635 
       
   636                 return xml;
       
   637 
       
   638             }
       
   639 
       
   640             return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToJUnitXML(results);
       
   641         },
       
   642 
       
   643         /**
       
   644          * Returns test results formatted in TAP format.
       
   645          * For more information, see <a href="http://testanything.org/">Test Anything Protocol</a>.
       
   646          * @param {Object} result The results object created by TestRunner.
       
   647          * @return {String} A TAP-formatted string of results.
       
   648          * @method TAP
       
   649          * @static
       
   650          */
       
   651         TAP: function(results) {
       
   652 
       
   653             var currentTestNum = 1;
       
   654 
       
   655             function serializeToTAP(results){
       
   656                 var text = "";
       
   657 
       
   658                 switch (results.type){
       
   659 
       
   660                     case "test":
       
   661                         if (results.result != "ignore"){
       
   662 
       
   663                             text = "ok " + (currentTestNum++) + " - " + results.name;
       
   664 
       
   665                             if (results.result == "fail"){
       
   666                                 text = "not " + text + " - " + results.message;
       
   667                             }
       
   668 
       
   669                             text += "\n";
       
   670                         } else {
       
   671                             text = "#Ignored test " + results.name + "\n";
       
   672                         }
       
   673                         break;
       
   674 
       
   675                     case "testcase":
       
   676 
       
   677                         text = "#Begin testcase " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";
       
   678 
       
   679                         for (var prop in results){
       
   680                             if (results.hasOwnProperty(prop)){
       
   681                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   682                                     text += serializeToTAP(results[prop]);
       
   683                                 }
       
   684                             }
       
   685                         }
       
   686 
       
   687                         text += "#End testcase " + results.name + "\n";
       
   688 
       
   689 
       
   690                         break;
       
   691 
       
   692                     case "testsuite":
       
   693 
       
   694                         text = "#Begin testsuite " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";
       
   695 
       
   696                         for (var prop in results){
       
   697                             if (results.hasOwnProperty(prop)){
       
   698                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   699                                     text += serializeToTAP(results[prop]);
       
   700                                 }
       
   701                             }
       
   702                         }
       
   703 
       
   704                         text += "#End testsuite " + results.name + "\n";
       
   705                         break;
       
   706 
       
   707                     case "report":
       
   708 
       
   709                         for (var prop in results){
       
   710                             if (results.hasOwnProperty(prop)){
       
   711                                 if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
       
   712                                     text += serializeToTAP(results[prop]);
       
   713                                 }
       
   714                             }
       
   715                         }
       
   716 
       
   717                     //no default
       
   718                 }
       
   719 
       
   720                 return text;
       
   721 
       
   722             }
       
   723 
       
   724             return "1.." + results.total + "\n" + serializeToTAP(results);
       
   725         }
       
   726 
       
   727     };
       
   728 }();
       
   729 
       
   730     /**
       
   731      * An object capable of sending test results to a server.
       
   732      * @param {String} url The URL to submit the results to.
       
   733      * @param {Function} format (Optiona) A function that outputs the results in a specific format.
       
   734      *      Default is YUITest.TestFormat.XML.
       
   735      * @constructor
       
   736      * @namespace Test
       
   737      * @module test
       
   738  * @class Reporter
       
   739      */
       
   740     YUITest.Reporter = function(url, format) {
       
   741 
       
   742         /**
       
   743          * The URL to submit the data to.
       
   744          * @type String
       
   745          * @property url
       
   746          */
       
   747         this.url = url;
       
   748 
       
   749         /**
       
   750          * The formatting function to call when submitting the data.
       
   751          * @type Function
       
   752          * @property format
       
   753          */
       
   754         this.format = format || YUITest.TestFormat.XML;
       
   755 
       
   756         /**
       
   757          * Extra fields to submit with the request.
       
   758          * @type Object
       
   759          * @property _fields
       
   760          * @private
       
   761          */
       
   762         this._fields = new Object();
       
   763 
       
   764         /**
       
   765          * The form element used to submit the results.
       
   766          * @type HTMLFormElement
       
   767          * @property _form
       
   768          * @private
       
   769          */
       
   770         this._form = null;
       
   771 
       
   772         /**
       
   773          * Iframe used as a target for form submission.
       
   774          * @type HTMLIFrameElement
       
   775          * @property _iframe
       
   776          * @private
       
   777          */
       
   778         this._iframe = null;
       
   779     };
       
   780 
       
   781     YUITest.Reporter.prototype = {
       
   782 
       
   783         //restore missing constructor
       
   784         constructor: YUITest.Reporter,
       
   785 
       
   786         /**
       
   787          * Adds a field to the form that submits the results.
       
   788          * @param {String} name The name of the field.
       
   789          * @param {Any} value The value of the field.
       
   790          * @method addField
       
   791          */
       
   792         addField : function (name, value){
       
   793             this._fields[name] = value;
       
   794         },
       
   795 
       
   796         /**
       
   797          * Removes all previous defined fields.
       
   798          * @method clearFields
       
   799          */
       
   800         clearFields : function(){
       
   801             this._fields = new Object();
       
   802         },
       
   803 
       
   804         /**
       
   805          * Cleans up the memory associated with the TestReporter, removing DOM elements
       
   806          * that were created.
       
   807          * @method destroy
       
   808          */
       
   809         destroy : function() {
       
   810             if (this._form){
       
   811                 this._form.parentNode.removeChild(this._form);
       
   812                 this._form = null;
       
   813             }
       
   814             if (this._iframe){
       
   815                 this._iframe.parentNode.removeChild(this._iframe);
       
   816                 this._iframe = null;
       
   817             }
       
   818             this._fields = null;
       
   819         },
       
   820 
       
   821         /**
       
   822          * Sends the report to the server.
       
   823          * @param {Object} results The results object created by TestRunner.
       
   824          * @method report
       
   825          */
       
   826         report : function(results){
       
   827 
       
   828             //if the form hasn't been created yet, create it
       
   829             if (!this._form){
       
   830                 this._form = document.createElement("form");
       
   831                 this._form.method = "post";
       
   832                 this._form.style.visibility = "hidden";
       
   833                 this._form.style.position = "absolute";
       
   834                 this._form.style.top = 0;
       
   835                 document.body.appendChild(this._form);
       
   836 
       
   837                 //IE won't let you assign a name using the DOM, must do it the hacky way
       
   838                 try {
       
   839                     this._iframe = document.createElement("<iframe name=\"yuiTestTarget\" />");
       
   840                 } catch (ex){
       
   841                     this._iframe = document.createElement("iframe");
       
   842                     this._iframe.name = "yuiTestTarget";
       
   843                 }
       
   844 
       
   845                 this._iframe.src = "javascript:false";
       
   846                 this._iframe.style.visibility = "hidden";
       
   847                 this._iframe.style.position = "absolute";
       
   848                 this._iframe.style.top = 0;
       
   849                 document.body.appendChild(this._iframe);
       
   850 
       
   851                 this._form.target = "yuiTestTarget";
       
   852             }
       
   853 
       
   854             //set the form's action
       
   855             this._form.action = this.url;
       
   856 
       
   857             //remove any existing fields
       
   858             while(this._form.hasChildNodes()){
       
   859                 this._form.removeChild(this._form.lastChild);
       
   860             }
       
   861 
       
   862             //create default fields
       
   863             this._fields.results = this.format(results);
       
   864             this._fields.useragent = navigator.userAgent;
       
   865             this._fields.timestamp = (new Date()).toLocaleString();
       
   866 
       
   867             //add fields to the form
       
   868             for (var prop in this._fields){
       
   869                 var value = this._fields[prop];
       
   870                 if (this._fields.hasOwnProperty(prop) && (typeof value != "function")){
       
   871                     var input = document.createElement("input");
       
   872                     input.type = "hidden";
       
   873                     input.name = prop;
       
   874                     input.value = value;
       
   875                     this._form.appendChild(input);
       
   876                 }
       
   877             }
       
   878 
       
   879             //remove default fields
       
   880             delete this._fields.results;
       
   881             delete this._fields.useragent;
       
   882             delete this._fields.timestamp;
       
   883 
       
   884             if (arguments[1] !== false){
       
   885                 this._form.submit();
       
   886             }
       
   887 
       
   888         }
       
   889 
       
   890     };
       
   891 
       
   892     /**
       
   893      * Runs test suites and test cases, providing events to allowing for the
       
   894      * interpretation of test results.
       
   895      * @namespace Test
       
   896      * @module test
       
   897  * @class TestRunner
       
   898      * @static
       
   899      */
       
   900     YUITest.TestRunner = function(){
       
   901 
       
   902         /*(intentionally not documented)
       
   903          * Determines if any of the array of test groups appears
       
   904          * in the given TestRunner filter.
       
   905          * @param {Array} testGroups The array of test groups to
       
   906          *      search for.
       
   907          * @param {String} filter The TestRunner groups filter.
       
   908          */
       
   909         function inGroups(testGroups, filter){
       
   910             if (!filter.length){
       
   911                 return true;
       
   912             } else {
       
   913                 if (testGroups){
       
   914                     for (var i=0, len=testGroups.length; i < len; i++){
       
   915                         if (filter.indexOf("," + testGroups[i] + ",") > -1){
       
   916                             return true;
       
   917                         }
       
   918                     }
       
   919                 }
       
   920                 return false;
       
   921             }
       
   922         }
       
   923 
       
   924         /**
       
   925          * A node in the test tree structure. May represent a TestSuite, TestCase, or
       
   926          * test function.
       
   927          * @param {Any} testObject A TestSuite, TestCase, or the name of a test function.
       
   928          * @module test
       
   929  * @class TestNode
       
   930          * @constructor
       
   931          * @private
       
   932          */
       
   933         function TestNode(testObject){
       
   934 
       
   935             /**
       
   936              * The TestSuite, TestCase, or test function represented by this node.
       
   937              * @type {Any}
       
   938              * @property testObject
       
   939              */
       
   940             this.testObject = testObject;
       
   941 
       
   942             /**
       
   943              * Pointer to this node's first child.
       
   944              * @type TestNode
       
   945              * @property firstChild
       
   946              */
       
   947             this.firstChild = null;
       
   948 
       
   949             /**
       
   950              * Pointer to this node's last child.
       
   951              * @type TestNode
       
   952              * @property lastChild
       
   953              */
       
   954             this.lastChild = null;
       
   955 
       
   956             /**
       
   957              * Pointer to this node's parent.
       
   958              * @type TestNode
       
   959              * @property parent
       
   960              */
       
   961             this.parent = null;
       
   962 
       
   963             /**
       
   964              * Pointer to this node's next sibling.
       
   965              * @type TestNode
       
   966              * @property next
       
   967              */
       
   968             this.next = null;
       
   969 
       
   970             /**
       
   971              * Test results for this test object.
       
   972              * @type object
       
   973              * @property results
       
   974              */
       
   975             this.results = new YUITest.Results();
       
   976 
       
   977             //initialize results
       
   978             if (testObject instanceof YUITest.TestSuite){
       
   979                 this.results.type = "testsuite";
       
   980                 this.results.name = testObject.name;
       
   981             } else if (testObject instanceof YUITest.TestCase){
       
   982                 this.results.type = "testcase";
       
   983                 this.results.name = testObject.name;
       
   984             }
       
   985 
       
   986         }
       
   987 
       
   988         TestNode.prototype = {
       
   989 
       
   990             /**
       
   991              * Appends a new test object (TestSuite, TestCase, or test function name) as a child
       
   992              * of this node.
       
   993              * @param {Any} testObject A TestSuite, TestCase, or the name of a test function.
       
   994              * @method appendChild
       
   995              */
       
   996             appendChild : function (testObject){
       
   997                 var node = new TestNode(testObject);
       
   998                 if (this.firstChild === null){
       
   999                     this.firstChild = this.lastChild = node;
       
  1000                 } else {
       
  1001                     this.lastChild.next = node;
       
  1002                     this.lastChild = node;
       
  1003                 }
       
  1004                 node.parent = this;
       
  1005                 return node;
       
  1006             }
       
  1007         };
       
  1008 
       
  1009         /**
       
  1010          * Runs test suites and test cases, providing events to allowing for the
       
  1011          * interpretation of test results.
       
  1012          * @namespace Test
       
  1013          * @module test
       
  1014  * @class Runner
       
  1015          * @static
       
  1016          */
       
  1017         function TestRunner(){
       
  1018 
       
  1019             //inherit from EventTarget
       
  1020             YUITest.EventTarget.call(this);
       
  1021 
       
  1022             /**
       
  1023              * Suite on which to attach all TestSuites and TestCases to be run.
       
  1024              * @type YUITest.TestSuite
       
  1025              * @property masterSuite
       
  1026              * @static
       
  1027              * @private
       
  1028              */
       
  1029             this.masterSuite = new YUITest.TestSuite(YUITest.guid('testSuite_'));
       
  1030 
       
  1031             /**
       
  1032              * Pointer to the current node in the test tree.
       
  1033              * @type TestNode
       
  1034              * @private
       
  1035              * @property _cur
       
  1036              * @static
       
  1037              */
       
  1038             this._cur = null;
       
  1039 
       
  1040             /**
       
  1041              * Pointer to the root node in the test tree.
       
  1042              * @type TestNode
       
  1043              * @private
       
  1044              * @property _root
       
  1045              * @static
       
  1046              */
       
  1047             this._root = null;
       
  1048 
       
  1049             /**
       
  1050              * Indicates if the TestRunner will log events or not.
       
  1051              * @type Boolean
       
  1052              * @property _log
       
  1053              * @private
       
  1054              * @static
       
  1055              */
       
  1056             this._log = true;
       
  1057 
       
  1058             /**
       
  1059              * Indicates if the TestRunner is waiting as a result of
       
  1060              * wait() being called.
       
  1061              * @type Boolean
       
  1062              * @property _waiting
       
  1063              * @private
       
  1064              * @static
       
  1065              */
       
  1066             this._waiting = false;
       
  1067 
       
  1068             /**
       
  1069              * Indicates if the TestRunner is currently running tests.
       
  1070              * @type Boolean
       
  1071              * @private
       
  1072              * @property _running
       
  1073              * @static
       
  1074              */
       
  1075             this._running = false;
       
  1076 
       
  1077             /**
       
  1078              * Holds copy of the results object generated when all tests are
       
  1079              * complete.
       
  1080              * @type Object
       
  1081              * @private
       
  1082              * @property _lastResults
       
  1083              * @static
       
  1084              */
       
  1085             this._lastResults = null;
       
  1086 
       
  1087             /**
       
  1088              * Data object that is passed around from method to method.
       
  1089              * @type Object
       
  1090              * @private
       
  1091              * @property _data
       
  1092              * @static
       
  1093              */
       
  1094             this._context = null;
       
  1095 
       
  1096             /**
       
  1097              * The list of test groups to run. The list is represented
       
  1098              * by a comma delimited string with commas at the start and
       
  1099              * end.
       
  1100              * @type String
       
  1101              * @private
       
  1102              * @property _groups
       
  1103              * @static
       
  1104              */
       
  1105             this._groups = "";
       
  1106 
       
  1107         }
       
  1108 
       
  1109         TestRunner.prototype = YUITest.Util.mix(new YUITest.EventTarget(), {
       
  1110 
       
  1111             /**
       
  1112             * If true, YUITest will not fire an error for tests with no Asserts.
       
  1113             * @property _ignoreEmpty
       
  1114             * @private
       
  1115             * @type Boolean
       
  1116             * @static
       
  1117             */
       
  1118             _ignoreEmpty: false,
       
  1119 
       
  1120             //restore prototype
       
  1121             constructor: YUITest.TestRunner,
       
  1122 
       
  1123             //-------------------------------------------------------------------------
       
  1124             // Constants
       
  1125             //-------------------------------------------------------------------------
       
  1126 
       
  1127             /**
       
  1128              * Fires when a test case is opened but before the first
       
  1129              * test is executed.
       
  1130              * @event testcasebegin
       
  1131              * @static
       
  1132              */
       
  1133             TEST_CASE_BEGIN_EVENT : "testcasebegin",
       
  1134 
       
  1135             /**
       
  1136              * Fires when all tests in a test case have been executed.
       
  1137              * @event testcasecomplete
       
  1138              * @static
       
  1139              */
       
  1140             TEST_CASE_COMPLETE_EVENT : "testcasecomplete",
       
  1141 
       
  1142             /**
       
  1143              * Fires when a test suite is opened but before the first
       
  1144              * test is executed.
       
  1145              * @event testsuitebegin
       
  1146              * @static
       
  1147              */
       
  1148             TEST_SUITE_BEGIN_EVENT : "testsuitebegin",
       
  1149 
       
  1150             /**
       
  1151              * Fires when all test cases in a test suite have been
       
  1152              * completed.
       
  1153              * @event testsuitecomplete
       
  1154              * @static
       
  1155              */
       
  1156             TEST_SUITE_COMPLETE_EVENT : "testsuitecomplete",
       
  1157 
       
  1158             /**
       
  1159              * Fires when a test has passed.
       
  1160              * @event pass
       
  1161              * @static
       
  1162              */
       
  1163             TEST_PASS_EVENT : "pass",
       
  1164 
       
  1165             /**
       
  1166              * Fires when a test has failed.
       
  1167              * @event fail
       
  1168              * @static
       
  1169              */
       
  1170             TEST_FAIL_EVENT : "fail",
       
  1171 
       
  1172             /**
       
  1173              * Fires when a non-test method has an error.
       
  1174              * @event error
       
  1175              * @static
       
  1176              */
       
  1177             ERROR_EVENT : "error",
       
  1178 
       
  1179             /**
       
  1180              * Fires when a test has been ignored.
       
  1181              * @event ignore
       
  1182              * @static
       
  1183              */
       
  1184             TEST_IGNORE_EVENT : "ignore",
       
  1185 
       
  1186             /**
       
  1187              * Fires when all test suites and test cases have been completed.
       
  1188              * @event complete
       
  1189              * @static
       
  1190              */
       
  1191             COMPLETE_EVENT : "complete",
       
  1192 
       
  1193             /**
       
  1194              * Fires when the run() method is called.
       
  1195              * @event begin
       
  1196              * @static
       
  1197              */
       
  1198             BEGIN_EVENT : "begin",
       
  1199 
       
  1200             //-------------------------------------------------------------------------
       
  1201             // Test Tree-Related Methods
       
  1202             //-------------------------------------------------------------------------
       
  1203 
       
  1204             /**
       
  1205              * Adds a test case to the test tree as a child of the specified node.
       
  1206              * @param {TestNode} parentNode The node to add the test case to as a child.
       
  1207              * @param {Test.TestCase} testCase The test case to add.
       
  1208              * @static
       
  1209              * @private
       
  1210              * @method _addTestCaseToTestTree
       
  1211              */
       
  1212            _addTestCaseToTestTree : function (parentNode, testCase){
       
  1213 
       
  1214                 //add the test suite
       
  1215                 var node = parentNode.appendChild(testCase),
       
  1216                     prop,
       
  1217                     testName;
       
  1218 
       
  1219                 //iterate over the items in the test case
       
  1220                 for (prop in testCase){
       
  1221                     if ((prop.indexOf("test") === 0 || prop.indexOf(" ") > -1) && typeof testCase[prop] == "function"){
       
  1222                         node.appendChild(prop);
       
  1223                     }
       
  1224                 }
       
  1225 
       
  1226             },
       
  1227 
       
  1228             /**
       
  1229              * Adds a test suite to the test tree as a child of the specified node.
       
  1230              * @param {TestNode} parentNode The node to add the test suite to as a child.
       
  1231              * @param {Test.TestSuite} testSuite The test suite to add.
       
  1232              * @static
       
  1233              * @private
       
  1234              * @method _addTestSuiteToTestTree
       
  1235              */
       
  1236             _addTestSuiteToTestTree : function (parentNode, testSuite) {
       
  1237 
       
  1238                 //add the test suite
       
  1239                 var node = parentNode.appendChild(testSuite);
       
  1240 
       
  1241                 //iterate over the items in the master suite
       
  1242                 for (var i=0; i < testSuite.items.length; i++){
       
  1243                     if (testSuite.items[i] instanceof YUITest.TestSuite) {
       
  1244                         this._addTestSuiteToTestTree(node, testSuite.items[i]);
       
  1245                     } else if (testSuite.items[i] instanceof YUITest.TestCase) {
       
  1246                         this._addTestCaseToTestTree(node, testSuite.items[i]);
       
  1247                     }
       
  1248                 }
       
  1249             },
       
  1250 
       
  1251             /**
       
  1252              * Builds the test tree based on items in the master suite. The tree is a hierarchical
       
  1253              * representation of the test suites, test cases, and test functions. The resulting tree
       
  1254              * is stored in _root and the pointer _cur is set to the root initially.
       
  1255              * @static
       
  1256              * @private
       
  1257              * @method _buildTestTree
       
  1258              */
       
  1259             _buildTestTree : function () {
       
  1260 
       
  1261                 this._root = new TestNode(this.masterSuite);
       
  1262                 //this._cur = this._root;
       
  1263 
       
  1264                 //iterate over the items in the master suite
       
  1265                 for (var i=0; i < this.masterSuite.items.length; i++){
       
  1266                     if (this.masterSuite.items[i] instanceof YUITest.TestSuite) {
       
  1267                         this._addTestSuiteToTestTree(this._root, this.masterSuite.items[i]);
       
  1268                     } else if (this.masterSuite.items[i] instanceof YUITest.TestCase) {
       
  1269                         this._addTestCaseToTestTree(this._root, this.masterSuite.items[i]);
       
  1270                     }
       
  1271                 }
       
  1272 
       
  1273             },
       
  1274 
       
  1275             //-------------------------------------------------------------------------
       
  1276             // Private Methods
       
  1277             //-------------------------------------------------------------------------
       
  1278 
       
  1279             /**
       
  1280              * Handles the completion of a test object's tests. Tallies test results
       
  1281              * from one level up to the next.
       
  1282              * @param {TestNode} node The TestNode representing the test object.
       
  1283              * @method _handleTestObjectComplete
       
  1284              * @private
       
  1285              */
       
  1286             _handleTestObjectComplete : function (node) {
       
  1287                 var parentNode;
       
  1288 
       
  1289                 if (node && (typeof node.testObject == "object")) {
       
  1290                     parentNode = node.parent;
       
  1291 
       
  1292                     if (parentNode){
       
  1293                         parentNode.results.include(node.results);
       
  1294                         parentNode.results[node.testObject.name] = node.results;
       
  1295                     }
       
  1296 
       
  1297                     if (node.testObject instanceof YUITest.TestSuite){
       
  1298                         this._execNonTestMethod(node, "tearDown", false);
       
  1299                         node.results.duration = (new Date()) - node._start;
       
  1300                         this.fire({ type: this.TEST_SUITE_COMPLETE_EVENT, testSuite: node.testObject, results: node.results});
       
  1301                     } else if (node.testObject instanceof YUITest.TestCase){
       
  1302                         this._execNonTestMethod(node, "destroy", false);
       
  1303                         node.results.duration = (new Date()) - node._start;
       
  1304                         this.fire({ type: this.TEST_CASE_COMPLETE_EVENT, testCase: node.testObject, results: node.results});
       
  1305                     }
       
  1306                 }
       
  1307             },
       
  1308 
       
  1309             //-------------------------------------------------------------------------
       
  1310             // Navigation Methods
       
  1311             //-------------------------------------------------------------------------
       
  1312 
       
  1313             /**
       
  1314              * Retrieves the next node in the test tree.
       
  1315              * @return {TestNode} The next node in the test tree or null if the end is reached.
       
  1316              * @private
       
  1317              * @static
       
  1318              * @method _next
       
  1319              */
       
  1320             _next : function () {
       
  1321 
       
  1322                 if (this._cur === null){
       
  1323                     this._cur = this._root;
       
  1324                 } else if (this._cur.firstChild) {
       
  1325                     this._cur = this._cur.firstChild;
       
  1326                 } else if (this._cur.next) {
       
  1327                     this._cur = this._cur.next;
       
  1328                 } else {
       
  1329                     while (this._cur && !this._cur.next && this._cur !== this._root){
       
  1330                         this._handleTestObjectComplete(this._cur);
       
  1331                         this._cur = this._cur.parent;
       
  1332                     }
       
  1333 
       
  1334                     this._handleTestObjectComplete(this._cur);
       
  1335 
       
  1336                     if (this._cur == this._root){
       
  1337                         this._cur.results.type = "report";
       
  1338                         this._cur.results.timestamp = (new Date()).toLocaleString();
       
  1339                         this._cur.results.duration = (new Date()) - this._cur._start;
       
  1340                         this._lastResults = this._cur.results;
       
  1341                         this._running = false;
       
  1342                         this.fire({ type: this.COMPLETE_EVENT, results: this._lastResults});
       
  1343                         this._cur = null;
       
  1344                     } else if (this._cur) {
       
  1345                         this._cur = this._cur.next;
       
  1346                     }
       
  1347                 }
       
  1348 
       
  1349                 return this._cur;
       
  1350             },
       
  1351 
       
  1352             /**
       
  1353              * Executes a non-test method (init, setUp, tearDown, destroy)
       
  1354              * and traps an errors. If an error occurs, an error event is
       
  1355              * fired.
       
  1356              * @param {Object} node The test node in the testing tree.
       
  1357              * @param {String} methodName The name of the method to execute.
       
  1358              * @param {Boolean} allowAsync Determines if the method can be called asynchronously.
       
  1359              * @return {Boolean} True if an async method was called, false if not.
       
  1360              * @method _execNonTestMethod
       
  1361              * @private
       
  1362              */
       
  1363             _execNonTestMethod: function(node, methodName, allowAsync){
       
  1364                 var testObject = node.testObject,
       
  1365                     event = { type: this.ERROR_EVENT };
       
  1366                 try {
       
  1367                     if (allowAsync && testObject["async:" + methodName]){
       
  1368                         testObject["async:" + methodName](this._context);
       
  1369                         return true;
       
  1370                     } else {
       
  1371                         testObject[methodName](this._context);
       
  1372                     }
       
  1373                 } catch (ex){
       
  1374                     node.results.errors++;
       
  1375                     event.error = ex;
       
  1376                     event.methodName = methodName;
       
  1377                     if (testObject instanceof YUITest.TestCase){
       
  1378                         event.testCase = testObject;
       
  1379                     } else {
       
  1380                         event.testSuite = testSuite;
       
  1381                     }
       
  1382 
       
  1383                     this.fire(event);
       
  1384                 }
       
  1385 
       
  1386                 return false;
       
  1387             },
       
  1388 
       
  1389             /**
       
  1390              * Runs a test case or test suite, returning the results.
       
  1391              * @param {Test.TestCase|YUITest.TestSuite} testObject The test case or test suite to run.
       
  1392              * @return {Object} Results of the execution with properties passed, failed, and total.
       
  1393              * @private
       
  1394              * @method _run
       
  1395              * @static
       
  1396              */
       
  1397             _run : function () {
       
  1398 
       
  1399                 //flag to indicate if the TestRunner should wait before continuing
       
  1400                 var shouldWait = false;
       
  1401 
       
  1402                 //get the next test node
       
  1403                 var node = this._next();
       
  1404 
       
  1405                 if (node !== null) {
       
  1406 
       
  1407                     //set flag to say the testrunner is running
       
  1408                     this._running = true;
       
  1409 
       
  1410                     //eliminate last results
       
  1411                     this._lastResult = null;
       
  1412 
       
  1413                     var testObject = node.testObject;
       
  1414 
       
  1415                     //figure out what to do
       
  1416                     if (typeof testObject == "object" && testObject !== null){
       
  1417                         if (testObject instanceof YUITest.TestSuite){
       
  1418                             this.fire({ type: this.TEST_SUITE_BEGIN_EVENT, testSuite: testObject });
       
  1419                             node._start = new Date();
       
  1420                             this._execNonTestMethod(node, "setUp" ,false);
       
  1421                         } else if (testObject instanceof YUITest.TestCase){
       
  1422                             this.fire({ type: this.TEST_CASE_BEGIN_EVENT, testCase: testObject });
       
  1423                             node._start = new Date();
       
  1424 
       
  1425                             //regular or async init
       
  1426                             /*try {
       
  1427                                 if (testObject["async:init"]){
       
  1428                                     testObject["async:init"](this._context);
       
  1429                                     return;
       
  1430                                 } else {
       
  1431                                     testObject.init(this._context);
       
  1432                                 }
       
  1433                             } catch (ex){
       
  1434                                 node.results.errors++;
       
  1435                                 this.fire({ type: this.ERROR_EVENT, error: ex, testCase: testObject, methodName: "init" });
       
  1436                             }*/
       
  1437                             if(this._execNonTestMethod(node, "init", true)){
       
  1438                                 return;
       
  1439                             }
       
  1440                         }
       
  1441 
       
  1442                         //some environments don't support setTimeout
       
  1443                         if (typeof setTimeout != "undefined"){
       
  1444                             setTimeout(function(){
       
  1445                                 YUITest.TestRunner._run();
       
  1446                             }, 0);
       
  1447                         } else {
       
  1448                             this._run();
       
  1449                         }
       
  1450                     } else {
       
  1451                         this._runTest(node);
       
  1452                     }
       
  1453 
       
  1454                 }
       
  1455             },
       
  1456 
       
  1457             _resumeTest : function (segment) {
       
  1458 
       
  1459                 //get relevant information
       
  1460                 var node = this._cur;
       
  1461 
       
  1462                 //we know there's no more waiting now
       
  1463                 this._waiting = false;
       
  1464 
       
  1465                 //if there's no node, it probably means a wait() was called after resume()
       
  1466                 if (!node){
       
  1467                     //TODO: Handle in some way?
       
  1468                     //console.log("wait() called after resume()");
       
  1469                     //this.fire("error", { testCase: "(unknown)", test: "(unknown)", error: new Error("wait() called after resume()")} );
       
  1470                     return;
       
  1471                 }
       
  1472 
       
  1473                 var testName = node.testObject;
       
  1474                 var testCase = node.parent.testObject;
       
  1475 
       
  1476                 //cancel other waits if available
       
  1477                 if (testCase.__yui_wait){
       
  1478                     clearTimeout(testCase.__yui_wait);
       
  1479                     delete testCase.__yui_wait;
       
  1480                 }
       
  1481 
       
  1482                 //get the "should" test cases
       
  1483                 var shouldFail = testName.indexOf("fail:") === 0 ||
       
  1484                                     (testCase._should.fail || {})[testName];
       
  1485                 var shouldError = (testCase._should.error || {})[testName];
       
  1486 
       
  1487                 //variable to hold whether or not the test failed
       
  1488                 var failed = false;
       
  1489                 var error = null;
       
  1490 
       
  1491                 //try the test
       
  1492                 try {
       
  1493 
       
  1494                     //run the test
       
  1495                     segment.call(testCase, this._context);
       
  1496 
       
  1497                     //if the test hasn't already failed and doesn't have any asserts...
       
  1498                     if(YUITest.Assert._getCount() == 0 && !this._ignoreEmpty){
       
  1499                         throw new YUITest.AssertionError("Test has no asserts.");
       
  1500                     }
       
  1501                     //if it should fail, and it got here, then it's a fail because it didn't
       
  1502                      else if (shouldFail){
       
  1503                         error = new YUITest.ShouldFail();
       
  1504                         failed = true;
       
  1505                     } else if (shouldError){
       
  1506                         error = new YUITest.ShouldError();
       
  1507                         failed = true;
       
  1508                     }
       
  1509 
       
  1510                 } catch (thrown){
       
  1511 
       
  1512                     //cancel any pending waits, the test already failed
       
  1513                     if (testCase.__yui_wait){
       
  1514                         clearTimeout(testCase.__yui_wait);
       
  1515                         delete testCase.__yui_wait;
       
  1516                     }
       
  1517 
       
  1518                     //figure out what type of error it was
       
  1519                     if (thrown instanceof YUITest.AssertionError) {
       
  1520                         if (!shouldFail){
       
  1521                             error = thrown;
       
  1522                             failed = true;
       
  1523                         }
       
  1524                     } else if (thrown instanceof YUITest.Wait){
       
  1525 
       
  1526                         if (typeof thrown.segment == "function"){
       
  1527                             if (typeof thrown.delay == "number"){
       
  1528 
       
  1529                                 //some environments don't support setTimeout
       
  1530                                 if (typeof setTimeout != "undefined"){
       
  1531                                     testCase.__yui_wait = setTimeout(function(){
       
  1532                                         YUITest.TestRunner._resumeTest(thrown.segment);
       
  1533                                     }, thrown.delay);
       
  1534                                     this._waiting = true;
       
  1535                                 } else {
       
  1536                                     throw new Error("Asynchronous tests not supported in this environment.");
       
  1537                                 }
       
  1538                             }
       
  1539                         }
       
  1540 
       
  1541                         return;
       
  1542 
       
  1543                     } else {
       
  1544                         //first check to see if it should error
       
  1545                         if (!shouldError) {
       
  1546                             error = new YUITest.UnexpectedError(thrown);
       
  1547                             failed = true;
       
  1548                         } else {
       
  1549                             //check to see what type of data we have
       
  1550                             if (typeof shouldError == "string"){
       
  1551 
       
  1552                                 //if it's a string, check the error message
       
  1553                                 if (thrown.message != shouldError){
       
  1554                                     error = new YUITest.UnexpectedError(thrown);
       
  1555                                     failed = true;
       
  1556                                 }
       
  1557                             } else if (typeof shouldError == "function"){
       
  1558 
       
  1559                                 //if it's a function, see if the error is an instance of it
       
  1560                                 if (!(thrown instanceof shouldError)){
       
  1561                                     error = new YUITest.UnexpectedError(thrown);
       
  1562                                     failed = true;
       
  1563                                 }
       
  1564 
       
  1565                             } else if (typeof shouldError == "object" && shouldError !== null){
       
  1566 
       
  1567                                 //if it's an object, check the instance and message
       
  1568                                 if (!(thrown instanceof shouldError.constructor) ||
       
  1569                                         thrown.message != shouldError.message){
       
  1570                                     error = new YUITest.UnexpectedError(thrown);
       
  1571                                     failed = true;
       
  1572                                 }
       
  1573 
       
  1574                             }
       
  1575 
       
  1576                         }
       
  1577                     }
       
  1578 
       
  1579                 }
       
  1580 
       
  1581                 //fire appropriate event
       
  1582                 if (failed) {
       
  1583                     this.fire({ type: this.TEST_FAIL_EVENT, testCase: testCase, testName: testName, error: error });
       
  1584                 } else {
       
  1585                     this.fire({ type: this.TEST_PASS_EVENT, testCase: testCase, testName: testName });
       
  1586                 }
       
  1587 
       
  1588                 //run the tear down
       
  1589                 this._execNonTestMethod(node.parent, "tearDown", false);
       
  1590 
       
  1591                 //reset the assert count
       
  1592                 YUITest.Assert._reset();
       
  1593 
       
  1594                 //calculate duration
       
  1595                 var duration = (new Date()) - node._start;
       
  1596 
       
  1597                 //update results
       
  1598                 node.parent.results[testName] = {
       
  1599                     result: failed ? "fail" : "pass",
       
  1600                     message: error ? error.getMessage() : "Test passed",
       
  1601                     type: "test",
       
  1602                     name: testName,
       
  1603                     duration: duration
       
  1604                 };
       
  1605 
       
  1606                 if (failed){
       
  1607                     node.parent.results.failed++;
       
  1608                 } else {
       
  1609                     node.parent.results.passed++;
       
  1610                 }
       
  1611                 node.parent.results.total++;
       
  1612 
       
  1613                 //set timeout not supported in all environments
       
  1614                 if (typeof setTimeout != "undefined"){
       
  1615                     setTimeout(function(){
       
  1616                         YUITest.TestRunner._run();
       
  1617                     }, 0);
       
  1618                 } else {
       
  1619                     this._run();
       
  1620                 }
       
  1621 
       
  1622             },
       
  1623 
       
  1624             /**
       
  1625              * Handles an error as if it occurred within the currently executing
       
  1626              * test. This is for mock methods that may be called asynchronously
       
  1627              * and therefore out of the scope of the TestRunner. Previously, this
       
  1628              * error would bubble up to the browser. Now, this method is used
       
  1629              * to tell TestRunner about the error. This should never be called
       
  1630              * by anyplace other than the Mock object.
       
  1631              * @param {Error} error The error object.
       
  1632              * @method _handleError
       
  1633              * @private
       
  1634              * @static
       
  1635              */
       
  1636             _handleError: function(error){
       
  1637 
       
  1638                 if (this._waiting){
       
  1639                     this._resumeTest(function(){
       
  1640                         throw error;
       
  1641                     });
       
  1642                 } else {
       
  1643                     throw error;
       
  1644                 }
       
  1645 
       
  1646             },
       
  1647 
       
  1648             /**
       
  1649              * Runs a single test based on the data provided in the node.
       
  1650              * @method _runTest
       
  1651              * @param {TestNode} node The TestNode representing the test to run.
       
  1652              * @static
       
  1653              * @private
       
  1654              */
       
  1655             _runTest : function (node) {
       
  1656 
       
  1657                 //get relevant information
       
  1658                 var testName = node.testObject,
       
  1659                     testCase = node.parent.testObject,
       
  1660                     test = testCase[testName],
       
  1661 
       
  1662                     //get the "should" test cases
       
  1663                     shouldIgnore = testName.indexOf("ignore:") === 0 ||
       
  1664                                     !inGroups(testCase.groups, this._groups) ||
       
  1665                                     (testCase._should.ignore || {})[testName];   //deprecated
       
  1666 
       
  1667                 //figure out if the test should be ignored or not
       
  1668                 if (shouldIgnore){
       
  1669 
       
  1670                     //update results
       
  1671                     node.parent.results[testName] = {
       
  1672                         result: "ignore",
       
  1673                         message: "Test ignored",
       
  1674                         type: "test",
       
  1675                         name: testName.indexOf("ignore:") === 0 ? testName.substring(7) : testName
       
  1676                     };
       
  1677 
       
  1678                     node.parent.results.ignored++;
       
  1679                     node.parent.results.total++;
       
  1680 
       
  1681                     this.fire({ type: this.TEST_IGNORE_EVENT,  testCase: testCase, testName: testName });
       
  1682 
       
  1683                     //some environments don't support setTimeout
       
  1684                     if (typeof setTimeout != "undefined"){
       
  1685                         setTimeout(function(){
       
  1686                             YUITest.TestRunner._run();
       
  1687                         }, 0);
       
  1688                     } else {
       
  1689                         this._run();
       
  1690                     }
       
  1691 
       
  1692                 } else {
       
  1693 
       
  1694                     //mark the start time
       
  1695                     node._start = new Date();
       
  1696 
       
  1697                     //run the setup
       
  1698                     this._execNonTestMethod(node.parent, "setUp", false);
       
  1699 
       
  1700                     //now call the body of the test
       
  1701                     this._resumeTest(test);
       
  1702                 }
       
  1703 
       
  1704             },
       
  1705 
       
  1706             //-------------------------------------------------------------------------
       
  1707             // Misc Methods
       
  1708             //-------------------------------------------------------------------------
       
  1709 
       
  1710             /**
       
  1711              * Retrieves the name of the current result set.
       
  1712              * @return {String} The name of the result set.
       
  1713              * @method getName
       
  1714              */
       
  1715             getName: function(){
       
  1716                 return this.masterSuite.name;
       
  1717             },
       
  1718 
       
  1719             /**
       
  1720              * The name assigned to the master suite of the TestRunner. This is the name
       
  1721              * that is output as the root's name when results are retrieved.
       
  1722              * @param {String} name The name of the result set.
       
  1723              * @method setName
       
  1724              */
       
  1725             setName: function(name){
       
  1726                 this.masterSuite.name = name;
       
  1727             },
       
  1728 
       
  1729             //-------------------------------------------------------------------------
       
  1730             // Public Methods
       
  1731             //-------------------------------------------------------------------------
       
  1732 
       
  1733             /**
       
  1734              * Adds a test suite or test case to the list of test objects to run.
       
  1735              * @param testObject Either a TestCase or a TestSuite that should be run.
       
  1736              * @method add
       
  1737              * @static
       
  1738              */
       
  1739             add : function (testObject) {
       
  1740                 this.masterSuite.add(testObject);
       
  1741                 return this;
       
  1742             },
       
  1743 
       
  1744             /**
       
  1745              * Removes all test objects from the runner.
       
  1746              * @method clear
       
  1747              * @static
       
  1748              */
       
  1749             clear : function () {
       
  1750                 this.masterSuite = new YUITest.TestSuite(YUITest.guid('testSuite_'));
       
  1751             },
       
  1752 
       
  1753             /**
       
  1754              * Indicates if the TestRunner is waiting for a test to resume
       
  1755              * @return {Boolean} True if the TestRunner is waiting, false if not.
       
  1756              * @method isWaiting
       
  1757              * @static
       
  1758              */
       
  1759             isWaiting: function() {
       
  1760                 return this._waiting;
       
  1761             },
       
  1762 
       
  1763             /**
       
  1764              * Indicates that the TestRunner is busy running tests and therefore can't
       
  1765              * be stopped and results cannot be gathered.
       
  1766              * @return {Boolean} True if the TestRunner is running, false if not.
       
  1767              * @method isRunning
       
  1768              */
       
  1769             isRunning: function(){
       
  1770                 return this._running;
       
  1771             },
       
  1772 
       
  1773             /**
       
  1774              * Returns the last complete results set from the TestRunner. Null is returned
       
  1775              * if the TestRunner is running or no tests have been run.
       
  1776              * @param {Function} format (Optional) A test format to return the results in.
       
  1777              * @return {Object|String} Either the results object or, if a test format is
       
  1778              *      passed as the argument, a string representing the results in a specific
       
  1779              *      format.
       
  1780              * @method getResults
       
  1781              */
       
  1782             getResults: function(format){
       
  1783                 if (!this._running && this._lastResults){
       
  1784                     if (typeof format == "function"){
       
  1785                         return format(this._lastResults);
       
  1786                     } else {
       
  1787                         return this._lastResults;
       
  1788                     }
       
  1789                 } else {
       
  1790                     return null;
       
  1791                 }
       
  1792             },
       
  1793 
       
  1794             /**
       
  1795              * Returns the coverage report for the files that have been executed.
       
  1796              * This returns only coverage information for files that have been
       
  1797              * instrumented using YUI Test Coverage and only those that were run
       
  1798              * in the same pass.
       
  1799              * @param {Function} format (Optional) A coverage format to return results in.
       
  1800              * @return {Object|String} Either the coverage object or, if a coverage
       
  1801              *      format is specified, a string representing the results in that format.
       
  1802              * @method getCoverage
       
  1803              */
       
  1804             getCoverage: function(format) {
       
  1805                 var covObject = null;
       
  1806                 if (typeof _yuitest_coverage === "object") {
       
  1807                     covObject = _yuitest_coverage;
       
  1808                 }
       
  1809                 if (typeof __coverage__ === "object") {
       
  1810                     covObject = __coverage__;
       
  1811                 }
       
  1812                 if (!this._running && typeof covObject == "object"){
       
  1813                     if (typeof format == "function") {
       
  1814                         return format(covObject);
       
  1815                     } else {
       
  1816                         return covObject;
       
  1817                     }
       
  1818                 } else {
       
  1819                     return null;
       
  1820                 }
       
  1821             },
       
  1822 
       
  1823             /**
       
  1824              * Used to continue processing when a method marked with
       
  1825              * "async:" is executed. This should not be used in test
       
  1826              * methods, only in init(). Each argument is a string, and
       
  1827              * when the returned function is executed, the arguments
       
  1828              * are assigned to the context data object using the string
       
  1829              * as the key name (value is the argument itself).
       
  1830              * @private
       
  1831              * @return {Function} A callback function.
       
  1832              * @method callback
       
  1833              */
       
  1834             callback: function(){
       
  1835                 var names   = arguments,
       
  1836                     data    = this._context,
       
  1837                     that    = this;
       
  1838 
       
  1839                 return function(){
       
  1840                     for (var i=0; i < arguments.length; i++){
       
  1841                         data[names[i]] = arguments[i];
       
  1842                     }
       
  1843                     that._run();
       
  1844                 };
       
  1845             },
       
  1846 
       
  1847             /**
       
  1848              * Resumes the TestRunner after wait() was called.
       
  1849              * @param {Function} segment The function to run as the rest
       
  1850              *      of the haulted test.
       
  1851              * @method resume
       
  1852              * @static
       
  1853              */
       
  1854             resume : function (segment) {
       
  1855                 if (this._waiting){
       
  1856                     this._resumeTest(segment || function(){});
       
  1857                 } else {
       
  1858                     throw new Error("resume() called without wait().");
       
  1859                 }
       
  1860             },
       
  1861 
       
  1862             /**
       
  1863              * Runs the test suite.
       
  1864              * @param {Object|Boolean} options (Optional) Options for the runner:
       
  1865              *      <code>oldMode</code> indicates the TestRunner should work in the YUI <= 2.8 way
       
  1866              *      of internally managing test suites. <code>groups</code> is an array
       
  1867              *      of test groups indicating which tests to run.
       
  1868              * @method run
       
  1869              * @static
       
  1870              */
       
  1871             run : function (options) {
       
  1872 
       
  1873                 options = options || {};
       
  1874 
       
  1875                 //pointer to runner to avoid scope issues
       
  1876                 var runner  = YUITest.TestRunner,
       
  1877                     oldMode = options.oldMode;
       
  1878 
       
  1879 
       
  1880                 //if there's only one suite on the masterSuite, move it up
       
  1881                 if (!oldMode && this.masterSuite.items.length == 1 && this.masterSuite.items[0] instanceof YUITest.TestSuite){
       
  1882                     this.masterSuite = this.masterSuite.items[0];
       
  1883                 }
       
  1884 
       
  1885                 //determine if there are any groups to filter on
       
  1886                 runner._groups = (options.groups instanceof Array) ? "," + options.groups.join(",") + "," : "";
       
  1887 
       
  1888                 //initialize the runner
       
  1889                 runner._buildTestTree();
       
  1890                 runner._context = {};
       
  1891                 runner._root._start = new Date();
       
  1892 
       
  1893                 //fire the begin event
       
  1894                 runner.fire(runner.BEGIN_EVENT);
       
  1895 
       
  1896                 //begin the testing
       
  1897                 runner._run();
       
  1898             }
       
  1899         });
       
  1900 
       
  1901         return new TestRunner();
       
  1902 
       
  1903     }();
       
  1904 
       
  1905 /**
       
  1906  * The ArrayAssert object provides functions to test JavaScript array objects
       
  1907  * for a variety of cases.
       
  1908  * @namespace Test
       
  1909  * @module test
       
  1910  * @class ArrayAssert
       
  1911  * @static
       
  1912  */
       
  1913 
       
  1914 YUITest.ArrayAssert = {
       
  1915 
       
  1916     //=========================================================================
       
  1917     // Private methods
       
  1918     //=========================================================================
       
  1919 
       
  1920     /**
       
  1921      * Simple indexOf() implementation for an array. Defers to native
       
  1922      * if available.
       
  1923      * @param {Array} haystack The array to search.
       
  1924      * @param {Any} needle The value to locate.
       
  1925      * @return {Number} The index of the needle if found or -1 if not.
       
  1926      * @method _indexOf
       
  1927      * @private
       
  1928      */
       
  1929     _indexOf: function(haystack, needle){
       
  1930         if (haystack.indexOf){
       
  1931             return haystack.indexOf(needle);
       
  1932         } else {
       
  1933             for (var i=0; i < haystack.length; i++){
       
  1934                 if (haystack[i] === needle){
       
  1935                     return i;
       
  1936                 }
       
  1937             }
       
  1938             return -1;
       
  1939         }
       
  1940     },
       
  1941 
       
  1942     /**
       
  1943      * Simple some() implementation for an array. Defers to native
       
  1944      * if available.
       
  1945      * @param {Array} haystack The array to search.
       
  1946      * @param {Function} matcher The function to run on each value.
       
  1947      * @return {Boolean} True if any value, when run through the matcher,
       
  1948      *      returns true.
       
  1949      * @method _some
       
  1950      * @private
       
  1951      */
       
  1952     _some: function(haystack, matcher){
       
  1953         if (haystack.some){
       
  1954             return haystack.some(matcher);
       
  1955         } else {
       
  1956             for (var i=0; i < haystack.length; i++){
       
  1957                 if (matcher(haystack[i])){
       
  1958                     return true;
       
  1959                 }
       
  1960             }
       
  1961             return false;
       
  1962         }
       
  1963     },
       
  1964 
       
  1965     /**
       
  1966      * Asserts that a value is present in an array. This uses the triple equals
       
  1967      * sign so no type coercion may occur.
       
  1968      * @param {Object} needle The value that is expected in the array.
       
  1969      * @param {Array} haystack An array of values.
       
  1970      * @param {String} message (Optional) The message to display if the assertion fails.
       
  1971      * @method contains
       
  1972      * @static
       
  1973      */
       
  1974     contains : function (needle, haystack,
       
  1975                            message) {
       
  1976 
       
  1977         YUITest.Assert._increment();
       
  1978 
       
  1979         if (this._indexOf(haystack, needle) == -1){
       
  1980             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value " + needle + " (" + (typeof needle) + ") not found in array [" + haystack + "]."));
       
  1981         }
       
  1982     },
       
  1983 
       
  1984     /**
       
  1985      * Asserts that a set of values are present in an array. This uses the triple equals
       
  1986      * sign so no type coercion may occur. For this assertion to pass, all values must
       
  1987      * be found.
       
  1988      * @param {Object[]} needles An array of values that are expected in the array.
       
  1989      * @param {Array} haystack An array of values to check.
       
  1990      * @param {String} message (Optional) The message to display if the assertion fails.
       
  1991      * @method containsItems
       
  1992      * @static
       
  1993      */
       
  1994     containsItems : function (needles, haystack,
       
  1995                            message) {
       
  1996         YUITest.Assert._increment();
       
  1997 
       
  1998         //begin checking values
       
  1999         for (var i=0; i < needles.length; i++){
       
  2000             if (this._indexOf(haystack, needles[i]) == -1){
       
  2001                 YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value " + needles[i] + " (" + (typeof needles[i]) + ") not found in array [" + haystack + "]."));
       
  2002             }
       
  2003         }
       
  2004     },
       
  2005 
       
  2006     /**
       
  2007      * Asserts that a value matching some condition is present in an array. This uses
       
  2008      * a function to determine a match.
       
  2009      * @param {Function} matcher A function that returns true if the items matches or false if not.
       
  2010      * @param {Array} haystack An array of values.
       
  2011      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2012      * @method containsMatch
       
  2013      * @static
       
  2014      */
       
  2015     containsMatch : function (matcher, haystack,
       
  2016                            message) {
       
  2017 
       
  2018         YUITest.Assert._increment();
       
  2019         //check for valid matcher
       
  2020         if (typeof matcher != "function"){
       
  2021             throw new TypeError("ArrayAssert.containsMatch(): First argument must be a function.");
       
  2022         }
       
  2023 
       
  2024         if (!this._some(haystack, matcher)){
       
  2025             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "No match found in array [" + haystack + "]."));
       
  2026         }
       
  2027     },
       
  2028 
       
  2029     /**
       
  2030      * Asserts that a value is not present in an array. This uses the triple equals
       
  2031      * Asserts that a value is not present in an array. This uses the triple equals
       
  2032      * sign so no type coercion may occur.
       
  2033      * @param {Object} needle The value that is expected in the array.
       
  2034      * @param {Array} haystack An array of values.
       
  2035      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2036      * @method doesNotContain
       
  2037      * @static
       
  2038      */
       
  2039     doesNotContain : function (needle, haystack,
       
  2040                            message) {
       
  2041 
       
  2042         YUITest.Assert._increment();
       
  2043 
       
  2044         if (this._indexOf(haystack, needle) > -1){
       
  2045             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value found in array [" + haystack + "]."));
       
  2046         }
       
  2047     },
       
  2048 
       
  2049     /**
       
  2050      * Asserts that a set of values are not present in an array. This uses the triple equals
       
  2051      * sign so no type coercion may occur. For this assertion to pass, all values must
       
  2052      * not be found.
       
  2053      * @param {Object[]} needles An array of values that are not expected in the array.
       
  2054      * @param {Array} haystack An array of values to check.
       
  2055      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2056      * @method doesNotContainItems
       
  2057      * @static
       
  2058      */
       
  2059     doesNotContainItems : function (needles, haystack,
       
  2060                            message) {
       
  2061 
       
  2062         YUITest.Assert._increment();
       
  2063 
       
  2064         for (var i=0; i < needles.length; i++){
       
  2065             if (this._indexOf(haystack, needles[i]) > -1){
       
  2066                 YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value found in array [" + haystack + "]."));
       
  2067             }
       
  2068         }
       
  2069 
       
  2070     },
       
  2071 
       
  2072     /**
       
  2073      * Asserts that no values matching a condition are present in an array. This uses
       
  2074      * a function to determine a match.
       
  2075      * @param {Function} matcher A function that returns true if the item matches or false if not.
       
  2076      * @param {Array} haystack An array of values.
       
  2077      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2078      * @method doesNotContainMatch
       
  2079      * @static
       
  2080      */
       
  2081     doesNotContainMatch : function (matcher, haystack,
       
  2082                            message) {
       
  2083 
       
  2084         YUITest.Assert._increment();
       
  2085 
       
  2086         //check for valid matcher
       
  2087         if (typeof matcher != "function"){
       
  2088             throw new TypeError("ArrayAssert.doesNotContainMatch(): First argument must be a function.");
       
  2089         }
       
  2090 
       
  2091         if (this._some(haystack, matcher)){
       
  2092             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value found in array [" + haystack + "]."));
       
  2093         }
       
  2094     },
       
  2095 
       
  2096     /**
       
  2097      * Asserts that the given value is contained in an array at the specified index.
       
  2098      * This uses the triple equals sign so no type coercion will occur.
       
  2099      * @param {Object} needle The value to look for.
       
  2100      * @param {Array} haystack The array to search in.
       
  2101      * @param {Number} index The index at which the value should exist.
       
  2102      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2103      * @method indexOf
       
  2104      * @static
       
  2105      */
       
  2106     indexOf : function (needle, haystack, index, message) {
       
  2107 
       
  2108         YUITest.Assert._increment();
       
  2109 
       
  2110         //try to find the value in the array
       
  2111         for (var i=0; i < haystack.length; i++){
       
  2112             if (haystack[i] === needle){
       
  2113                 if (index != i){
       
  2114                     YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value exists at index " + i + " but should be at index " + index + "."));
       
  2115                 }
       
  2116                 return;
       
  2117             }
       
  2118         }
       
  2119 
       
  2120         //if it makes it here, it wasn't found at all
       
  2121         YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value doesn't exist in array [" + haystack + "]."));
       
  2122     },
       
  2123 
       
  2124     /**
       
  2125      * Asserts that the values in an array are equal, and in the same position,
       
  2126      * as values in another array. This uses the double equals sign
       
  2127      * so type coercion may occur. Note that the array objects themselves
       
  2128      * need not be the same for this test to pass.
       
  2129      * @param {Array} expected An array of the expected values.
       
  2130      * @param {Array} actual Any array of the actual values.
       
  2131      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2132      * @method itemsAreEqual
       
  2133      * @static
       
  2134      */
       
  2135     itemsAreEqual : function (expected, actual,
       
  2136                            message) {
       
  2137 
       
  2138         YUITest.Assert._increment();
       
  2139 
       
  2140         //first make sure they're array-like (this can probably be improved)
       
  2141         if (typeof expected != "object" || typeof actual != "object"){
       
  2142             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value should be an array."));
       
  2143         }
       
  2144 
       
  2145         //next check array length
       
  2146         if (expected.length != actual.length){
       
  2147             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Array should have a length of " + expected.length + " but has a length of " + actual.length + "."));
       
  2148         }
       
  2149 
       
  2150         //begin checking values
       
  2151         for (var i=0; i < expected.length; i++){
       
  2152             if (expected[i] != actual[i]){
       
  2153                 throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values in position " + i + " are not equal."), expected[i], actual[i]);
       
  2154             }
       
  2155         }
       
  2156     },
       
  2157 
       
  2158     /**
       
  2159      * Asserts that the values in an array are equivalent, and in the same position,
       
  2160      * as values in another array. This uses a function to determine if the values
       
  2161      * are equivalent. Note that the array objects themselves
       
  2162      * need not be the same for this test to pass.
       
  2163      * @param {Array} expected An array of the expected values.
       
  2164      * @param {Array} actual Any array of the actual values.
       
  2165      * @param {Function} comparator A function that returns true if the values are equivalent
       
  2166      *      or false if not.
       
  2167      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2168      * @method itemsAreEquivalent
       
  2169      * @static
       
  2170      */
       
  2171     itemsAreEquivalent : function (expected, actual,
       
  2172                            comparator, message) {
       
  2173 
       
  2174         YUITest.Assert._increment();
       
  2175 
       
  2176         //make sure the comparator is valid
       
  2177         if (typeof comparator != "function"){
       
  2178             throw new TypeError("ArrayAssert.itemsAreEquivalent(): Third argument must be a function.");
       
  2179         }
       
  2180 
       
  2181         //first check array length
       
  2182         if (expected.length != actual.length){
       
  2183             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Array should have a length of " + expected.length + " but has a length of " + actual.length));
       
  2184         }
       
  2185 
       
  2186         //begin checking values
       
  2187         for (var i=0; i < expected.length; i++){
       
  2188             if (!comparator(expected[i], actual[i])){
       
  2189                 throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values in position " + i + " are not equivalent."), expected[i], actual[i]);
       
  2190             }
       
  2191         }
       
  2192     },
       
  2193 
       
  2194     /**
       
  2195      * Asserts that an array is empty.
       
  2196      * @param {Array} actual The array to test.
       
  2197      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2198      * @method isEmpty
       
  2199      * @static
       
  2200      */
       
  2201     isEmpty : function (actual, message) {
       
  2202         YUITest.Assert._increment();
       
  2203         if (actual.length > 0){
       
  2204             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Array should be empty."));
       
  2205         }
       
  2206     },
       
  2207 
       
  2208     /**
       
  2209      * Asserts that an array is not empty.
       
  2210      * @param {Array} actual The array to test.
       
  2211      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2212      * @method isNotEmpty
       
  2213      * @static
       
  2214      */
       
  2215     isNotEmpty : function (actual, message) {
       
  2216         YUITest.Assert._increment();
       
  2217         if (actual.length === 0){
       
  2218             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Array should not be empty."));
       
  2219         }
       
  2220     },
       
  2221 
       
  2222     /**
       
  2223      * Asserts that the values in an array are the same, and in the same position,
       
  2224      * as values in another array. This uses the triple equals sign
       
  2225      * so no type coercion will occur. Note that the array objects themselves
       
  2226      * need not be the same for this test to pass.
       
  2227      * @param {Array} expected An array of the expected values.
       
  2228      * @param {Array} actual Any array of the actual values.
       
  2229      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2230      * @method itemsAreSame
       
  2231      * @static
       
  2232      */
       
  2233     itemsAreSame : function (expected, actual,
       
  2234                           message) {
       
  2235 
       
  2236         YUITest.Assert._increment();
       
  2237 
       
  2238         //first check array length
       
  2239         if (expected.length != actual.length){
       
  2240             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Array should have a length of " + expected.length + " but has a length of " + actual.length));
       
  2241         }
       
  2242 
       
  2243         //begin checking values
       
  2244         for (var i=0; i < expected.length; i++){
       
  2245             if (expected[i] !== actual[i]){
       
  2246                 throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values in position " + i + " are not the same."), expected[i], actual[i]);
       
  2247             }
       
  2248         }
       
  2249     },
       
  2250 
       
  2251     /**
       
  2252      * Asserts that the given value is contained in an array at the specified index,
       
  2253      * starting from the back of the array.
       
  2254      * This uses the triple equals sign so no type coercion will occur.
       
  2255      * @param {Object} needle The value to look for.
       
  2256      * @param {Array} haystack The array to search in.
       
  2257      * @param {Number} index The index at which the value should exist.
       
  2258      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2259      * @method lastIndexOf
       
  2260      * @static
       
  2261      */
       
  2262     lastIndexOf : function (needle, haystack, index, message) {
       
  2263 
       
  2264         //try to find the value in the array
       
  2265         for (var i=haystack.length; i >= 0; i--){
       
  2266             if (haystack[i] === needle){
       
  2267                 if (index != i){
       
  2268                     YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value exists at index " + i + " but should be at index " + index + "."));
       
  2269                 }
       
  2270                 return;
       
  2271             }
       
  2272         }
       
  2273 
       
  2274         //if it makes it here, it wasn't found at all
       
  2275         YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Value doesn't exist in array."));
       
  2276     },
       
  2277 
       
  2278     /**
       
  2279      * Asserts that given array doesn't contain duplicate items.
       
  2280      * @param {Array} array The array to check.
       
  2281      * @param {Function} [comparator=null] A custom function to use to test the equality of two values.
       
  2282      *      This function is similar to the one given to {{#crossLink "Array/unique:method"}}Y.Array.unique{{/crossLink}}.
       
  2283      * @param {String} [message] The message to display if the assertion fails.
       
  2284      * @method isUnique
       
  2285      * @static
       
  2286      */
       
  2287     isUnique: function (array, comparator, message) {
       
  2288 
       
  2289         YUITest.Assert._increment();
       
  2290 
       
  2291         if (!Y.Lang.isArray(array)){
       
  2292             throw new TypeError("ArrayAssert.isUnique(): First argument must be an array");
       
  2293         }
       
  2294 
       
  2295         if (Y.Lang.isValue(comparator) && !Y.Lang.isFunction(comparator)){
       
  2296             throw new TypeError("ArrayAssert.isUnique(): Second argument must be a function");
       
  2297         }
       
  2298 
       
  2299         if (Y.Array.unique(array, comparator).length < array.length){
       
  2300             message = YUITest.Assert._formatMessage(message, "Array contains duplicate(s)");
       
  2301             YUITest.Assert.fail(message);
       
  2302         }
       
  2303     }
       
  2304 
       
  2305 };
       
  2306 
       
  2307 /**
       
  2308  * The Assert object provides functions to test JavaScript values against
       
  2309  * known and expected results. Whenever a comparison (assertion) fails,
       
  2310  * an error is thrown.
       
  2311  * @namespace Test
       
  2312  * @module test
       
  2313  * @class Assert
       
  2314  * @static
       
  2315  */
       
  2316 YUITest.Assert = {
       
  2317 
       
  2318     /**
       
  2319      * The number of assertions performed.
       
  2320      * @property _asserts
       
  2321      * @type int
       
  2322      * @private
       
  2323      */
       
  2324     _asserts: 0,
       
  2325 
       
  2326     //-------------------------------------------------------------------------
       
  2327     // Helper Methods
       
  2328     //-------------------------------------------------------------------------
       
  2329 
       
  2330     /**
       
  2331      * Formats a message so that it can contain the original assertion message
       
  2332      * in addition to the custom message.
       
  2333      * @param {String} customMessage The message passed in by the developer.
       
  2334      * @param {String} defaultMessage The message created by the error by default.
       
  2335      * @return {String} The final error message, containing either or both.
       
  2336      * @protected
       
  2337      * @static
       
  2338      * @method _formatMessage
       
  2339      */
       
  2340     _formatMessage : function (customMessage, defaultMessage) {
       
  2341         if (typeof customMessage == "string" && customMessage.length > 0){
       
  2342             return customMessage.replace("{message}", defaultMessage);
       
  2343         } else {
       
  2344             return defaultMessage;
       
  2345         }
       
  2346     },
       
  2347 
       
  2348     /**
       
  2349      * Returns the number of assertions that have been performed.
       
  2350      * @method _getCount
       
  2351      * @protected
       
  2352      * @static
       
  2353      */
       
  2354     _getCount: function(){
       
  2355         return this._asserts;
       
  2356     },
       
  2357 
       
  2358     /**
       
  2359      * Increments the number of assertions that have been performed.
       
  2360      * @method _increment
       
  2361      * @protected
       
  2362      * @static
       
  2363      */
       
  2364     _increment: function(){
       
  2365         this._asserts++;
       
  2366     },
       
  2367 
       
  2368     /**
       
  2369      * Resets the number of assertions that have been performed to 0.
       
  2370      * @method _reset
       
  2371      * @protected
       
  2372      * @static
       
  2373      */
       
  2374     _reset: function(){
       
  2375         this._asserts = 0;
       
  2376     },
       
  2377 
       
  2378     //-------------------------------------------------------------------------
       
  2379     // Generic Assertion Methods
       
  2380     //-------------------------------------------------------------------------
       
  2381 
       
  2382     /**
       
  2383      * Forces an assertion error to occur.
       
  2384      * @param {String} message (Optional) The message to display with the failure.
       
  2385      * @method fail
       
  2386      * @static
       
  2387      */
       
  2388     fail : function (message) {
       
  2389         throw new YUITest.AssertionError(YUITest.Assert._formatMessage(message, "Test force-failed."));
       
  2390     },
       
  2391 
       
  2392     /**
       
  2393      * A marker that the test should pass.
       
  2394      * @method pass
       
  2395      * @static
       
  2396      */
       
  2397     pass : function (message) {
       
  2398         YUITest.Assert._increment();
       
  2399     },
       
  2400 
       
  2401     //-------------------------------------------------------------------------
       
  2402     // Equality Assertion Methods
       
  2403     //-------------------------------------------------------------------------
       
  2404 
       
  2405     /**
       
  2406      * Asserts that a value is equal to another. This uses the double equals sign
       
  2407      * so type coercion may occur.
       
  2408      * @param {Object} expected The expected value.
       
  2409      * @param {Object} actual The actual value to test.
       
  2410      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2411      * @method areEqual
       
  2412      * @static
       
  2413      */
       
  2414     areEqual : function (expected, actual, message) {
       
  2415         YUITest.Assert._increment();
       
  2416         if (expected != actual) {
       
  2417             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values should be equal."), expected, actual);
       
  2418         }
       
  2419     },
       
  2420 
       
  2421     /**
       
  2422      * Asserts that a value is not equal to another. This uses the double equals sign
       
  2423      * so type coercion may occur.
       
  2424      * @param {Object} unexpected The unexpected value.
       
  2425      * @param {Object} actual The actual value to test.
       
  2426      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2427      * @method areNotEqual
       
  2428      * @static
       
  2429      */
       
  2430     areNotEqual : function (unexpected, actual,
       
  2431                          message) {
       
  2432         YUITest.Assert._increment();
       
  2433         if (unexpected == actual) {
       
  2434             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Values should not be equal."), unexpected);
       
  2435         }
       
  2436     },
       
  2437 
       
  2438     /**
       
  2439      * Asserts that a value is not the same as another. This uses the triple equals sign
       
  2440      * so no type coercion may occur.
       
  2441      * @param {Object} unexpected The unexpected value.
       
  2442      * @param {Object} actual The actual value to test.
       
  2443      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2444      * @method areNotSame
       
  2445      * @static
       
  2446      */
       
  2447     areNotSame : function (unexpected, actual, message) {
       
  2448         YUITest.Assert._increment();
       
  2449         if (unexpected === actual) {
       
  2450             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Values should not be the same."), unexpected);
       
  2451         }
       
  2452     },
       
  2453 
       
  2454     /**
       
  2455      * Asserts that a value is the same as another. This uses the triple equals sign
       
  2456      * so no type coercion may occur.
       
  2457      * @param {Object} expected The expected value.
       
  2458      * @param {Object} actual The actual value to test.
       
  2459      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2460      * @method areSame
       
  2461      * @static
       
  2462      */
       
  2463     areSame : function (expected, actual, message) {
       
  2464         YUITest.Assert._increment();
       
  2465         if (expected !== actual) {
       
  2466             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values should be the same."), expected, actual);
       
  2467         }
       
  2468     },
       
  2469 
       
  2470     //-------------------------------------------------------------------------
       
  2471     // Boolean Assertion Methods
       
  2472     //-------------------------------------------------------------------------
       
  2473 
       
  2474     /**
       
  2475      * Asserts that a value is false. This uses the triple equals sign
       
  2476      * so no type coercion may occur.
       
  2477      * @param {Object} actual The actual value to test.
       
  2478      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2479      * @method isFalse
       
  2480      * @static
       
  2481      */
       
  2482     isFalse : function (actual, message) {
       
  2483         YUITest.Assert._increment();
       
  2484         if (false !== actual) {
       
  2485             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be false."), false, actual);
       
  2486         }
       
  2487     },
       
  2488 
       
  2489     /**
       
  2490      * Asserts that a value is true. This uses the triple equals sign
       
  2491      * so no type coercion may occur.
       
  2492      * @param {Object} actual The actual value to test.
       
  2493      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2494      * @method isTrue
       
  2495      * @static
       
  2496      */
       
  2497     isTrue : function (actual, message) {
       
  2498         YUITest.Assert._increment();
       
  2499         if (true !== actual) {
       
  2500             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be true."), true, actual);
       
  2501         }
       
  2502 
       
  2503     },
       
  2504 
       
  2505     //-------------------------------------------------------------------------
       
  2506     // Special Value Assertion Methods
       
  2507     //-------------------------------------------------------------------------
       
  2508 
       
  2509     /**
       
  2510      * Asserts that a value is not a number.
       
  2511      * @param {Object} actual The value to test.
       
  2512      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2513      * @method isNaN
       
  2514      * @static
       
  2515      */
       
  2516     isNaN : function (actual, message){
       
  2517         YUITest.Assert._increment();
       
  2518         if (!isNaN(actual)){
       
  2519             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be NaN."), NaN, actual);
       
  2520         }
       
  2521     },
       
  2522 
       
  2523     /**
       
  2524      * Asserts that a value is not the special NaN value.
       
  2525      * @param {Object} actual The value to test.
       
  2526      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2527      * @method isNotNaN
       
  2528      * @static
       
  2529      */
       
  2530     isNotNaN : function (actual, message){
       
  2531         YUITest.Assert._increment();
       
  2532         if (isNaN(actual)){
       
  2533             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Values should not be NaN."), NaN);
       
  2534         }
       
  2535     },
       
  2536 
       
  2537     /**
       
  2538      * Asserts that a value is not null. This uses the triple equals sign
       
  2539      * so no type coercion may occur.
       
  2540      * @param {Object} actual The actual value to test.
       
  2541      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2542      * @method isNotNull
       
  2543      * @static
       
  2544      */
       
  2545     isNotNull : function (actual, message) {
       
  2546         YUITest.Assert._increment();
       
  2547         if (actual === null) {
       
  2548             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Values should not be null."), null);
       
  2549         }
       
  2550     },
       
  2551 
       
  2552     /**
       
  2553      * Asserts that a value is not undefined. This uses the triple equals sign
       
  2554      * so no type coercion may occur.
       
  2555      * @param {Object} actual The actual value to test.
       
  2556      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2557      * @method isNotUndefined
       
  2558      * @static
       
  2559      */
       
  2560     isNotUndefined : function (actual, message) {
       
  2561         YUITest.Assert._increment();
       
  2562         if (typeof actual == "undefined") {
       
  2563             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should not be undefined."), undefined);
       
  2564         }
       
  2565     },
       
  2566 
       
  2567     /**
       
  2568      * Asserts that a value is null. This uses the triple equals sign
       
  2569      * so no type coercion may occur.
       
  2570      * @param {Object} actual The actual value to test.
       
  2571      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2572      * @method isNull
       
  2573      * @static
       
  2574      */
       
  2575     isNull : function (actual, message) {
       
  2576         YUITest.Assert._increment();
       
  2577         if (actual !== null) {
       
  2578             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be null."), null, actual);
       
  2579         }
       
  2580     },
       
  2581 
       
  2582     /**
       
  2583      * Asserts that a value is undefined. This uses the triple equals sign
       
  2584      * so no type coercion may occur.
       
  2585      * @param {Object} actual The actual value to test.
       
  2586      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2587      * @method isUndefined
       
  2588      * @static
       
  2589      */
       
  2590     isUndefined : function (actual, message) {
       
  2591         YUITest.Assert._increment();
       
  2592         if (typeof actual != "undefined") {
       
  2593             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be undefined."), undefined, actual);
       
  2594         }
       
  2595     },
       
  2596 
       
  2597     //--------------------------------------------------------------------------
       
  2598     // Instance Assertion Methods
       
  2599     //--------------------------------------------------------------------------
       
  2600 
       
  2601     /**
       
  2602      * Asserts that a value is an array.
       
  2603      * @param {Object} actual The value to test.
       
  2604      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2605      * @method isArray
       
  2606      * @static
       
  2607      */
       
  2608     isArray : function (actual, message) {
       
  2609         YUITest.Assert._increment();
       
  2610         var shouldFail = false;
       
  2611         if (Array.isArray){
       
  2612             shouldFail = !Array.isArray(actual);
       
  2613         } else {
       
  2614             shouldFail = Object.prototype.toString.call(actual) != "[object Array]";
       
  2615         }
       
  2616         if (shouldFail){
       
  2617             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be an array."), actual);
       
  2618         }
       
  2619     },
       
  2620 
       
  2621     /**
       
  2622      * Asserts that a value is a Boolean.
       
  2623      * @param {Object} actual The value to test.
       
  2624      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2625      * @method isBoolean
       
  2626      * @static
       
  2627      */
       
  2628     isBoolean : function (actual, message) {
       
  2629         YUITest.Assert._increment();
       
  2630         if (typeof actual != "boolean"){
       
  2631             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be a Boolean."), actual);
       
  2632         }
       
  2633     },
       
  2634 
       
  2635     /**
       
  2636      * Asserts that a value is a function.
       
  2637      * @param {Object} actual The value to test.
       
  2638      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2639      * @method isFunction
       
  2640      * @static
       
  2641      */
       
  2642     isFunction : function (actual, message) {
       
  2643         YUITest.Assert._increment();
       
  2644         if (!(actual instanceof Function)){
       
  2645             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be a function."), actual);
       
  2646         }
       
  2647     },
       
  2648 
       
  2649     /**
       
  2650      * Asserts that a value is an instance of a particular object. This may return
       
  2651      * incorrect results when comparing objects from one frame to constructors in
       
  2652      * another frame. For best results, don't use in a cross-frame manner.
       
  2653      * @param {Function} expected The function that the object should be an instance of.
       
  2654      * @param {Object} actual The object to test.
       
  2655      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2656      * @method isInstanceOf
       
  2657      * @static
       
  2658      */
       
  2659     isInstanceOf : function (expected, actual, message) {
       
  2660         YUITest.Assert._increment();
       
  2661         if (!(actual instanceof expected)){
       
  2662             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value isn't an instance of expected type."), expected, actual);
       
  2663         }
       
  2664     },
       
  2665 
       
  2666     /**
       
  2667      * Asserts that a value is a number.
       
  2668      * @param {Object} actual The value to test.
       
  2669      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2670      * @method isNumber
       
  2671      * @static
       
  2672      */
       
  2673     isNumber : function (actual, message) {
       
  2674         YUITest.Assert._increment();
       
  2675         if (typeof actual != "number"){
       
  2676             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be a number."), actual);
       
  2677         }
       
  2678     },
       
  2679 
       
  2680     /**
       
  2681      * Asserts that a value is an object.
       
  2682      * @param {Object} actual The value to test.
       
  2683      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2684      * @method isObject
       
  2685      * @static
       
  2686      */
       
  2687     isObject : function (actual, message) {
       
  2688         YUITest.Assert._increment();
       
  2689         if (!actual || (typeof actual != "object" && typeof actual != "function")){
       
  2690             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be an object."), actual);
       
  2691         }
       
  2692     },
       
  2693 
       
  2694     /**
       
  2695      * Asserts that a value is a string.
       
  2696      * @param {Object} actual The value to test.
       
  2697      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2698      * @method isString
       
  2699      * @static
       
  2700      */
       
  2701     isString : function (actual, message) {
       
  2702         YUITest.Assert._increment();
       
  2703         if (typeof actual != "string"){
       
  2704             throw new YUITest.UnexpectedValue(YUITest.Assert._formatMessage(message, "Value should be a string."), actual);
       
  2705         }
       
  2706     },
       
  2707 
       
  2708     /**
       
  2709      * Asserts that a value is of a particular type.
       
  2710      * @param {String} expectedType The expected type of the variable.
       
  2711      * @param {Object} actualValue The actual value to test.
       
  2712      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2713      * @method isTypeOf
       
  2714      * @static
       
  2715      */
       
  2716     isTypeOf : function (expectedType, actualValue, message){
       
  2717         YUITest.Assert._increment();
       
  2718         if (typeof actualValue != expectedType){
       
  2719             throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Value should be of type " + expectedType + "."), expectedType, typeof actualValue);
       
  2720         }
       
  2721     },
       
  2722 
       
  2723     //--------------------------------------------------------------------------
       
  2724     // Error Detection Methods
       
  2725     //--------------------------------------------------------------------------
       
  2726 
       
  2727     /**
       
  2728      * Asserts that executing a particular method should throw an error of
       
  2729      * a specific type. This is a replacement for _should.error.
       
  2730      * @param {String|Function|Object} expectedError If a string, this
       
  2731      *      is the error message that the error must have; if a function, this
       
  2732      *      is the constructor that should have been used to create the thrown
       
  2733      *      error; if an object, this is an instance of a particular error type
       
  2734      *      with a specific error message (both must match).
       
  2735      * @param {Function} method The method to execute that should throw the error.
       
  2736      * @param {String} message (Optional) The message to display if the assertion
       
  2737      *      fails.
       
  2738      * @method throwsError
       
  2739      * @static
       
  2740      */
       
  2741     throwsError: function(expectedError, method, message){
       
  2742         YUITest.Assert._increment();
       
  2743         var error = false;
       
  2744 
       
  2745         try {
       
  2746             method();
       
  2747         } catch (thrown) {
       
  2748 
       
  2749             //check to see what type of data we have
       
  2750             if (typeof expectedError == "string"){
       
  2751 
       
  2752                 //if it's a string, check the error message
       
  2753                 if (thrown.message != expectedError){
       
  2754                     error = true;
       
  2755                 }
       
  2756             } else if (typeof expectedError == "function"){
       
  2757 
       
  2758                 //if it's a function, see if the error is an instance of it
       
  2759                 if (!(thrown instanceof expectedError)){
       
  2760                     error = true;
       
  2761                 }
       
  2762 
       
  2763             } else if (typeof expectedError == "object" && expectedError !== null){
       
  2764 
       
  2765                 //if it's an object, check the instance and message
       
  2766                 if (!(thrown instanceof expectedError.constructor) ||
       
  2767                         thrown.message != expectedError.message){
       
  2768                     error = true;
       
  2769                 }
       
  2770 
       
  2771             } else { //if it gets here, the argument could be wrong
       
  2772                 error = true;
       
  2773             }
       
  2774 
       
  2775             if (error){
       
  2776                 throw new YUITest.UnexpectedError(thrown);
       
  2777             } else {
       
  2778                 return;
       
  2779             }
       
  2780         }
       
  2781 
       
  2782         //if it reaches here, the error wasn't thrown, which is a bad thing
       
  2783         throw new YUITest.AssertionError(YUITest.Assert._formatMessage(message, "Error should have been thrown."));
       
  2784     }
       
  2785 
       
  2786 };
       
  2787 /**
       
  2788  * Error is thrown whenever an assertion fails. It provides methods
       
  2789  * to more easily get at error information and also provides a base class
       
  2790  * from which more specific assertion errors can be derived.
       
  2791  *
       
  2792  * @param {String} message The message to display when the error occurs.
       
  2793  * @namespace Test
       
  2794  * @module test
       
  2795  * @class AssertionError
       
  2796  * @constructor
       
  2797  */
       
  2798 YUITest.AssertionError = function (message){
       
  2799 
       
  2800     /**
       
  2801      * Error message. Must be duplicated to ensure browser receives it.
       
  2802      * @type String
       
  2803      * @property message
       
  2804      */
       
  2805     this.message = message;
       
  2806 
       
  2807     /**
       
  2808      * The name of the error that occurred.
       
  2809      * @type String
       
  2810      * @property name
       
  2811      */
       
  2812     this.name = "Assert Error";
       
  2813 };
       
  2814 
       
  2815 YUITest.AssertionError.prototype = {
       
  2816 
       
  2817     //restore constructor
       
  2818     constructor: YUITest.AssertionError,
       
  2819 
       
  2820     /**
       
  2821      * Returns a fully formatted error for an assertion failure. This should
       
  2822      * be overridden by all subclasses to provide specific information.
       
  2823      * @method getMessage
       
  2824      * @return {String} A string describing the error.
       
  2825      */
       
  2826     getMessage : function () {
       
  2827         return this.message;
       
  2828     },
       
  2829 
       
  2830     /**
       
  2831      * Returns a string representation of the error.
       
  2832      * @method toString
       
  2833      * @return {String} A string representation of the error.
       
  2834      */
       
  2835     toString : function () {
       
  2836         return this.name + ": " + this.getMessage();
       
  2837     }
       
  2838 
       
  2839 };
       
  2840 /**
       
  2841  * ComparisonFailure is subclass of Error that is thrown whenever
       
  2842  * a comparison between two values fails. It provides mechanisms to retrieve
       
  2843  * both the expected and actual value.
       
  2844  *
       
  2845  * @param {String} message The message to display when the error occurs.
       
  2846  * @param {Object} expected The expected value.
       
  2847  * @param {Object} actual The actual value that caused the assertion to fail.
       
  2848  * @namespace Test
       
  2849  * @extends AssertionError
       
  2850  * @module test
       
  2851  * @class ComparisonFailure
       
  2852  * @constructor
       
  2853  */
       
  2854 YUITest.ComparisonFailure = function (message, expected, actual){
       
  2855 
       
  2856     //call superclass
       
  2857     YUITest.AssertionError.call(this, message);
       
  2858 
       
  2859     /**
       
  2860      * The expected value.
       
  2861      * @type Object
       
  2862      * @property expected
       
  2863      */
       
  2864     this.expected = expected;
       
  2865 
       
  2866     /**
       
  2867      * The actual value.
       
  2868      * @type Object
       
  2869      * @property actual
       
  2870      */
       
  2871     this.actual = actual;
       
  2872 
       
  2873     /**
       
  2874      * The name of the error that occurred.
       
  2875      * @type String
       
  2876      * @property name
       
  2877      */
       
  2878     this.name = "ComparisonFailure";
       
  2879 
       
  2880 };
       
  2881 
       
  2882 //inherit from YUITest.AssertionError
       
  2883 YUITest.ComparisonFailure.prototype = new YUITest.AssertionError;
       
  2884 
       
  2885 //restore constructor
       
  2886 YUITest.ComparisonFailure.prototype.constructor = YUITest.ComparisonFailure;
       
  2887 
       
  2888 /**
       
  2889  * Returns a fully formatted error for an assertion failure. This message
       
  2890  * provides information about the expected and actual values.
       
  2891  * @method getMessage
       
  2892  * @return {String} A string describing the error.
       
  2893  */
       
  2894 YUITest.ComparisonFailure.prototype.getMessage = function(){
       
  2895     return this.message + "\nExpected: " + this.expected + " (" + (typeof this.expected) + ")"  +
       
  2896             "\nActual: " + this.actual + " (" + (typeof this.actual) + ")";
       
  2897 };
       
  2898 /**
       
  2899  * An object object containing coverage result formatting methods.
       
  2900  * @namespace Test
       
  2901  * @module test
       
  2902  * @class CoverageFormat
       
  2903  * @static
       
  2904  */
       
  2905 YUITest.CoverageFormat = {
       
  2906 
       
  2907     /**
       
  2908      * Returns the coverage report in JSON format. This is the straight
       
  2909      * JSON representation of the native coverage report.
       
  2910      * @param {Object} coverage The coverage report object.
       
  2911      * @return {String} A JSON-formatted string of coverage data.
       
  2912      * @method JSON
       
  2913      * @namespace Test.CoverageFormat
       
  2914      */
       
  2915     JSON: function(coverage){
       
  2916         return YUITest.Util.JSON.stringify(coverage);
       
  2917     },
       
  2918 
       
  2919     /**
       
  2920      * Returns the coverage report in a JSON format compatible with
       
  2921      * Xdebug. See <a href="http://www.xdebug.com/docs/code_coverage">Xdebug Documentation</a>
       
  2922      * for more information. Note: function coverage is not available
       
  2923      * in this format.
       
  2924      * @param {Object} coverage The coverage report object.
       
  2925      * @return {String} A JSON-formatted string of coverage data.
       
  2926      * @method XdebugJSON
       
  2927      * @namespace Test.CoverageFormat
       
  2928      */
       
  2929     XdebugJSON: function(coverage){
       
  2930 
       
  2931         var report = {};
       
  2932         for (var prop in coverage){
       
  2933             if (coverage.hasOwnProperty(prop)){
       
  2934                 report[prop] = coverage[prop].lines;
       
  2935             }
       
  2936         }
       
  2937 
       
  2938         return YUITest.Util.JSON.stringify(coverage);
       
  2939     }
       
  2940 
       
  2941 };
       
  2942 
       
  2943 
       
  2944 /**
       
  2945  * The DateAssert object provides functions to test JavaScript Date objects
       
  2946  * for a variety of cases.
       
  2947  * @namespace Test
       
  2948  * @module test
       
  2949  * @class DateAssert
       
  2950  * @static
       
  2951  */
       
  2952 
       
  2953 YUITest.DateAssert = {
       
  2954 
       
  2955     /**
       
  2956      * Asserts that a date's month, day, and year are equal to another date's.
       
  2957      * @param {Date} expected The expected date.
       
  2958      * @param {Date} actual The actual date to test.
       
  2959      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2960      * @method datesAreEqual
       
  2961      * @static
       
  2962      */
       
  2963     datesAreEqual : function (expected, actual, message){
       
  2964         YUITest.Assert._increment();
       
  2965         if (expected instanceof Date && actual instanceof Date){
       
  2966             var msg = "";
       
  2967 
       
  2968             //check years first
       
  2969             if (expected.getFullYear() != actual.getFullYear()){
       
  2970                 msg = "Years should be equal.";
       
  2971             }
       
  2972 
       
  2973             //now check months
       
  2974             if (expected.getMonth() != actual.getMonth()){
       
  2975                 msg = "Months should be equal.";
       
  2976             }
       
  2977 
       
  2978             //last, check the day of the month
       
  2979             if (expected.getDate() != actual.getDate()){
       
  2980                 msg = "Days of month should be equal.";
       
  2981             }
       
  2982 
       
  2983             if (msg.length){
       
  2984                 throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, msg), expected, actual);
       
  2985             }
       
  2986         } else {
       
  2987             throw new TypeError("YUITest.DateAssert.datesAreEqual(): Expected and actual values must be Date objects.");
       
  2988         }
       
  2989     },
       
  2990 
       
  2991     /**
       
  2992      * Asserts that a date's hour, minutes, and seconds are equal to another date's.
       
  2993      * @param {Date} expected The expected date.
       
  2994      * @param {Date} actual The actual date to test.
       
  2995      * @param {String} message (Optional) The message to display if the assertion fails.
       
  2996      * @method timesAreEqual
       
  2997      * @static
       
  2998      */
       
  2999     timesAreEqual : function (expected, actual, message){
       
  3000         YUITest.Assert._increment();
       
  3001         if (expected instanceof Date && actual instanceof Date){
       
  3002             var msg = "";
       
  3003 
       
  3004             //check hours first
       
  3005             if (expected.getHours() != actual.getHours()){
       
  3006                 msg = "Hours should be equal.";
       
  3007             }
       
  3008 
       
  3009             //now check minutes
       
  3010             if (expected.getMinutes() != actual.getMinutes()){
       
  3011                 msg = "Minutes should be equal.";
       
  3012             }
       
  3013 
       
  3014             //last, check the seconds
       
  3015             if (expected.getSeconds() != actual.getSeconds()){
       
  3016                 msg = "Seconds should be equal.";
       
  3017             }
       
  3018 
       
  3019             if (msg.length){
       
  3020                 throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, msg), expected, actual);
       
  3021             }
       
  3022         } else {
       
  3023             throw new TypeError("YUITest.DateAssert.timesAreEqual(): Expected and actual values must be Date objects.");
       
  3024         }
       
  3025     }
       
  3026 
       
  3027 };
       
  3028 /**
       
  3029  * Creates a new mock object.
       
  3030  * @namespace Test
       
  3031  * @module test
       
  3032  * @class Mock
       
  3033  * @constructor
       
  3034  * @param {Object} template (Optional) An object whose methods
       
  3035  *      should be stubbed out on the mock object.
       
  3036  */
       
  3037 YUITest.Mock = function(template){
       
  3038 
       
  3039     //use blank object is nothing is passed in
       
  3040     template = template || {};
       
  3041 
       
  3042     var mock,
       
  3043         name;
       
  3044 
       
  3045     //try to create mock that keeps prototype chain intact
       
  3046     //fails in the case of ActiveX objects
       
  3047     try {
       
  3048         function f(){}
       
  3049         f.prototype = template;
       
  3050         mock = new f();
       
  3051     } catch (ex) {
       
  3052         mock = {};
       
  3053     }
       
  3054 
       
  3055     //create stubs for all methods
       
  3056     for (name in template){
       
  3057         if (template.hasOwnProperty(name)){
       
  3058             if (typeof template[name] == "function"){
       
  3059                 mock[name] = function(name){
       
  3060                     return function(){
       
  3061                         YUITest.Assert.fail("Method " + name + "() was called but was not expected to be.");
       
  3062                     };
       
  3063                 }(name);
       
  3064             }
       
  3065         }
       
  3066     }
       
  3067 
       
  3068     //return it
       
  3069     return mock;
       
  3070 };
       
  3071 
       
  3072 /**
       
  3073  * Assigns an expectation to a mock object. This is used to create
       
  3074  * methods and properties on the mock object that are monitored for
       
  3075  * calls and changes, respectively.
       
  3076  * @param {Object} mock The object to add the expectation to.
       
  3077  * @param {Object} expectation An object defining the expectation. For
       
  3078  *      properties, the keys "property" and "value" are required. For a
       
  3079  *      method the "method" key defines the method's name, the optional "args"
       
  3080  *      key provides an array of argument types. The "returns" key provides
       
  3081  *      an optional return value. An optional "run" key provides a function
       
  3082  *      to be used as the method body. The return value of a mocked method is
       
  3083  *      determined first by the "returns" key, then the "run" function's return
       
  3084  *      value. If neither "returns" nor "run" is provided undefined is returned.
       
  3085  *      An optional 'error' key defines an error type to be thrown in all cases.
       
  3086  *      The "callCount" key provides an optional number of times the method is
       
  3087  *      expected to be called (the default is 1).
       
  3088  * @method expect
       
  3089  * @static
       
  3090  */
       
  3091 YUITest.Mock.expect = function(mock /*:Object*/, expectation /*:Object*/){
       
  3092 
       
  3093     //make sure there's a place to store the expectations
       
  3094     if (!mock.__expectations) {
       
  3095         mock.__expectations = {};
       
  3096     }
       
  3097 
       
  3098     //method expectation
       
  3099     if (expectation.method){
       
  3100         var name = expectation.method,
       
  3101             args = expectation.args || [],
       
  3102             result = expectation.returns,
       
  3103             callCount = (typeof expectation.callCount == "number") ? expectation.callCount : 1,
       
  3104             error = expectation.error,
       
  3105             run = expectation.run || function(){},
       
  3106             runResult,
       
  3107             i;
       
  3108 
       
  3109         //save expectations
       
  3110         mock.__expectations[name] = expectation;
       
  3111         expectation.callCount = callCount;
       
  3112         expectation.actualCallCount = 0;
       
  3113 
       
  3114         //process arguments
       
  3115         for (i=0; i < args.length; i++){
       
  3116              if (!(args[i] instanceof YUITest.Mock.Value)){
       
  3117                 args[i] = YUITest.Mock.Value(YUITest.Assert.areSame, [args[i]], "Argument " + i + " of " + name + "() is incorrect.");
       
  3118             }
       
  3119         }
       
  3120 
       
  3121         //if the method is expected to be called
       
  3122         if (callCount > 0){
       
  3123             mock[name] = function(){
       
  3124                 try {
       
  3125                     expectation.actualCallCount++;
       
  3126                     YUITest.Assert.areEqual(args.length, arguments.length, "Method " + name + "() passed incorrect number of arguments.");
       
  3127                     for (var i=0, len=args.length; i < len; i++){
       
  3128                         args[i].verify(arguments[i]);
       
  3129                     }
       
  3130 
       
  3131                     runResult = run.apply(this, arguments);
       
  3132 
       
  3133                     if (error){
       
  3134                         throw error;
       
  3135                     }
       
  3136                 } catch (ex){
       
  3137                     //route through TestRunner for proper handling
       
  3138                     YUITest.TestRunner._handleError(ex);
       
  3139                 }
       
  3140 
       
  3141                 // Any value provided for 'returns' overrides any value returned
       
  3142                 // by our 'run' function.
       
  3143                 return expectation.hasOwnProperty('returns') ? result : runResult;
       
  3144             };
       
  3145         } else {
       
  3146 
       
  3147             //method should fail if called when not expected
       
  3148             mock[name] = function(){
       
  3149                 try {
       
  3150                     YUITest.Assert.fail("Method " + name + "() should not have been called.");
       
  3151                 } catch (ex){
       
  3152                     //route through TestRunner for proper handling
       
  3153                     YUITest.TestRunner._handleError(ex);
       
  3154                 }
       
  3155             };
       
  3156         }
       
  3157     } else if (expectation.property){
       
  3158         //save expectations
       
  3159         mock.__expectations[expectation.property] = expectation;
       
  3160     }
       
  3161 };
       
  3162 
       
  3163 /**
       
  3164  * Verifies that all expectations of a mock object have been met and
       
  3165  * throws an assertion error if not.
       
  3166  * @param {Object} mock The object to verify..
       
  3167  * @method verify
       
  3168  * @static
       
  3169  */
       
  3170 YUITest.Mock.verify = function(mock){
       
  3171     try {
       
  3172 
       
  3173         for (var name in mock.__expectations){
       
  3174             if (mock.__expectations.hasOwnProperty(name)){
       
  3175                 var expectation = mock.__expectations[name];
       
  3176                 if (expectation.method) {
       
  3177                     YUITest.Assert.areEqual(expectation.callCount, expectation.actualCallCount, "Method " + expectation.method + "() wasn't called the expected number of times.");
       
  3178                 } else if (expectation.property){
       
  3179                     YUITest.Assert.areEqual(expectation.value, mock[expectation.property], "Property " + expectation.property + " wasn't set to the correct value.");
       
  3180                 }
       
  3181             }
       
  3182         }
       
  3183 
       
  3184     } catch (ex){
       
  3185         //route through TestRunner for proper handling
       
  3186         YUITest.TestRunner._handleError(ex);
       
  3187     }
       
  3188 };
       
  3189 
       
  3190 /**
       
  3191  * Creates a new value matcher.
       
  3192  * @param {Function} method The function to call on the value.
       
  3193  * @param {Array} originalArgs (Optional) Array of arguments to pass to the method.
       
  3194  * @param {String} message (Optional) Message to display in case of failure.
       
  3195  * @namespace Test.Mock
       
  3196  * @module test
       
  3197  * @class Value
       
  3198  * @constructor
       
  3199  */
       
  3200 YUITest.Mock.Value = function(method, originalArgs, message){
       
  3201     if (this instanceof YUITest.Mock.Value){
       
  3202         this.verify = function(value){
       
  3203             var args = [].concat(originalArgs || []);
       
  3204             args.push(value);
       
  3205             args.push(message);
       
  3206             method.apply(null, args);
       
  3207         };
       
  3208     } else {
       
  3209         return new YUITest.Mock.Value(method, originalArgs, message);
       
  3210     }
       
  3211 };
       
  3212 
       
  3213 /**
       
  3214  * Predefined matcher to match any value.
       
  3215  * @property Any
       
  3216  * @static
       
  3217  * @type Function
       
  3218  */
       
  3219 YUITest.Mock.Value.Any        = YUITest.Mock.Value(function(){});
       
  3220 
       
  3221 /**
       
  3222  * Predefined matcher to match boolean values.
       
  3223  * @property Boolean
       
  3224  * @static
       
  3225  * @type Function
       
  3226  */
       
  3227 YUITest.Mock.Value.Boolean    = YUITest.Mock.Value(YUITest.Assert.isBoolean);
       
  3228 
       
  3229 /**
       
  3230  * Predefined matcher to match number values.
       
  3231  * @property Number
       
  3232  * @static
       
  3233  * @type Function
       
  3234  */
       
  3235 YUITest.Mock.Value.Number     = YUITest.Mock.Value(YUITest.Assert.isNumber);
       
  3236 
       
  3237 /**
       
  3238  * Predefined matcher to match string values.
       
  3239  * @property String
       
  3240  * @static
       
  3241  * @type Function
       
  3242  */
       
  3243 YUITest.Mock.Value.String     = YUITest.Mock.Value(YUITest.Assert.isString);
       
  3244 
       
  3245 /**
       
  3246  * Predefined matcher to match object values.
       
  3247  * @property Object
       
  3248  * @static
       
  3249  * @type Function
       
  3250  */
       
  3251 YUITest.Mock.Value.Object     = YUITest.Mock.Value(YUITest.Assert.isObject);
       
  3252 
       
  3253 /**
       
  3254  * Predefined matcher to match function values.
       
  3255  * @property Function
       
  3256  * @static
       
  3257  * @type Function
       
  3258  */
       
  3259 YUITest.Mock.Value.Function   = YUITest.Mock.Value(YUITest.Assert.isFunction);
       
  3260 
       
  3261 /**
       
  3262  * The ObjectAssert object provides functions to test JavaScript objects
       
  3263  * for a variety of cases.
       
  3264  * @namespace Test
       
  3265  * @module test
       
  3266  * @class ObjectAssert
       
  3267  * @static
       
  3268  */
       
  3269 YUITest.ObjectAssert = {
       
  3270 
       
  3271     /**
       
  3272      * Asserts that an object has all of the same properties
       
  3273      * and property values as the other.
       
  3274      * @param {Object} expected The object with all expected properties and values.
       
  3275      * @param {Object} actual The object to inspect.
       
  3276      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3277      * @method areEqual
       
  3278      * @static
       
  3279      * @deprecated
       
  3280      */
       
  3281     areEqual: function(expected, actual, message) {
       
  3282         YUITest.Assert._increment();
       
  3283 
       
  3284         var expectedKeys = YUITest.Object.keys(expected),
       
  3285             actualKeys = YUITest.Object.keys(actual);
       
  3286 
       
  3287         //first check keys array length
       
  3288         if (expectedKeys.length != actualKeys.length){
       
  3289             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Object should have " + expectedKeys.length + " keys but has " + actualKeys.length));
       
  3290         }
       
  3291 
       
  3292         //then check values
       
  3293         for (var name in expected){
       
  3294             if (expected.hasOwnProperty(name)){
       
  3295                 if (expected[name] != actual[name]){
       
  3296                     throw new YUITest.ComparisonFailure(YUITest.Assert._formatMessage(message, "Values should be equal for property " + name), expected[name], actual[name]);
       
  3297                 }
       
  3298             }
       
  3299         }
       
  3300     },
       
  3301 
       
  3302     /**
       
  3303      * Asserts that an object has a property with the given name.
       
  3304      * @param {String} propertyName The name of the property to test.
       
  3305      * @param {Object} object The object to search.
       
  3306      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3307      * @method hasKey
       
  3308      * @static
       
  3309      * @deprecated Use ownsOrInheritsKey() instead
       
  3310      */
       
  3311     hasKey: function (propertyName, object, message) {
       
  3312         YUITest.ObjectAssert.ownsOrInheritsKey(propertyName, object, message);
       
  3313     },
       
  3314 
       
  3315     /**
       
  3316      * Asserts that an object has all properties of a reference object.
       
  3317      * @param {Array} properties An array of property names that should be on the object.
       
  3318      * @param {Object} object The object to search.
       
  3319      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3320      * @method hasKeys
       
  3321      * @static
       
  3322      * @deprecated Use ownsOrInheritsKeys() instead
       
  3323      */
       
  3324     hasKeys: function (properties, object, message) {
       
  3325         YUITest.ObjectAssert.ownsOrInheritsKeys(properties, object, message);
       
  3326     },
       
  3327 
       
  3328     /**
       
  3329      * Asserts that a property with the given name exists on an object's prototype.
       
  3330      * @param {String} propertyName The name of the property to test.
       
  3331      * @param {Object} object The object to search.
       
  3332      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3333      * @method inheritsKey
       
  3334      * @static
       
  3335      */
       
  3336     inheritsKey: function (propertyName, object, message) {
       
  3337         YUITest.Assert._increment();
       
  3338         if (!(propertyName in object && !object.hasOwnProperty(propertyName))){
       
  3339             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + propertyName + "' not found on object instance."));
       
  3340         }
       
  3341     },
       
  3342 
       
  3343     /**
       
  3344      * Asserts that all properties exist on an object prototype.
       
  3345      * @param {Array} properties An array of property names that should be on the object.
       
  3346      * @param {Object} object The object to search.
       
  3347      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3348      * @method inheritsKeys
       
  3349      * @static
       
  3350      */
       
  3351     inheritsKeys: function (properties, object, message) {
       
  3352         YUITest.Assert._increment();
       
  3353         for (var i=0; i < properties.length; i++){
       
  3354             if (!(propertyName in object && !object.hasOwnProperty(properties[i]))){
       
  3355                 YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + properties[i] + "' not found on object instance."));
       
  3356             }
       
  3357         }
       
  3358     },
       
  3359 
       
  3360     /**
       
  3361      * Asserts that a property with the given name exists on an object instance (not on its prototype).
       
  3362      * @param {String} propertyName The name of the property to test.
       
  3363      * @param {Object} object The object to search.
       
  3364      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3365      * @method ownsKey
       
  3366      * @static
       
  3367      */
       
  3368     ownsKey: function (propertyName, object, message) {
       
  3369         YUITest.Assert._increment();
       
  3370         if (!object.hasOwnProperty(propertyName)){
       
  3371             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + propertyName + "' not found on object instance."));
       
  3372         }
       
  3373     },
       
  3374 
       
  3375     /**
       
  3376      * Asserts that all properties exist on an object instance (not on its prototype).
       
  3377      * @param {Array} properties An array of property names that should be on the object.
       
  3378      * @param {Object} object The object to search.
       
  3379      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3380      * @method ownsKeys
       
  3381      * @static
       
  3382      */
       
  3383     ownsKeys: function (properties, object, message) {
       
  3384         YUITest.Assert._increment();
       
  3385         for (var i=0; i < properties.length; i++){
       
  3386             if (!object.hasOwnProperty(properties[i])){
       
  3387                 YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + properties[i] + "' not found on object instance."));
       
  3388             }
       
  3389         }
       
  3390     },
       
  3391 
       
  3392     /**
       
  3393      * Asserts that an object owns no properties.
       
  3394      * @param {Object} object The object to check.
       
  3395      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3396      * @method ownsNoKeys
       
  3397      * @static
       
  3398      */
       
  3399     ownsNoKeys : function (object, message) {
       
  3400         YUITest.Assert._increment();
       
  3401         var count = YUITest.Object.keys(object).length;
       
  3402 
       
  3403         if (count !== 0){
       
  3404             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Object owns " + count + " properties but should own none."));
       
  3405         }
       
  3406 
       
  3407     },
       
  3408 
       
  3409     /**
       
  3410      * Asserts that an object has a property with the given name.
       
  3411      * @param {String} propertyName The name of the property to test.
       
  3412      * @param {Object} object The object to search.
       
  3413      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3414      * @method ownsOrInheritsKey
       
  3415      * @static
       
  3416      */
       
  3417     ownsOrInheritsKey: function (propertyName, object, message) {
       
  3418         YUITest.Assert._increment();
       
  3419         if (!(propertyName in object)){
       
  3420             YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + propertyName + "' not found on object."));
       
  3421         }
       
  3422     },
       
  3423 
       
  3424     /**
       
  3425      * Asserts that an object has all properties of a reference object.
       
  3426      * @param {Array} properties An array of property names that should be on the object.
       
  3427      * @param {Object} object The object to search.
       
  3428      * @param {String} message (Optional) The message to display if the assertion fails.
       
  3429      * @method ownsOrInheritsKeys
       
  3430      * @static
       
  3431      */
       
  3432     ownsOrInheritsKeys: function (properties, object, message) {
       
  3433         YUITest.Assert._increment();
       
  3434         for (var i=0; i < properties.length; i++){
       
  3435             if (!(properties[i] in object)){
       
  3436                 YUITest.Assert.fail(YUITest.Assert._formatMessage(message, "Property '" + properties[i] + "' not found on object."));
       
  3437             }
       
  3438         }
       
  3439     }
       
  3440 };
       
  3441 /**
       
  3442  * Convenience type for storing and aggregating
       
  3443  * test result information.
       
  3444  * @private
       
  3445  * @namespace Test
       
  3446  * @module test
       
  3447  * @class Results
       
  3448  * @constructor
       
  3449  * @param {String} name The name of the test.
       
  3450  */
       
  3451 YUITest.Results = function(name){
       
  3452 
       
  3453     /**
       
  3454      * Name of the test, test case, or test suite.
       
  3455      * @type String
       
  3456      * @property name
       
  3457      */
       
  3458     this.name = name;
       
  3459 
       
  3460     /**
       
  3461      * Number of passed tests.
       
  3462      * @type int
       
  3463      * @property passed
       
  3464      */
       
  3465     this.passed = 0;
       
  3466 
       
  3467     /**
       
  3468      * Number of failed tests.
       
  3469      * @type int
       
  3470      * @property failed
       
  3471      */
       
  3472     this.failed = 0;
       
  3473 
       
  3474     /**
       
  3475      * Number of errors that occur in non-test methods.
       
  3476      * @type int
       
  3477      * @property errors
       
  3478      */
       
  3479     this.errors = 0;
       
  3480 
       
  3481     /**
       
  3482      * Number of ignored tests.
       
  3483      * @type int
       
  3484      * @property ignored
       
  3485      */
       
  3486     this.ignored = 0;
       
  3487 
       
  3488     /**
       
  3489      * Number of total tests.
       
  3490      * @type int
       
  3491      * @property total
       
  3492      */
       
  3493     this.total = 0;
       
  3494 
       
  3495     /**
       
  3496      * Amount of time (ms) it took to complete testing.
       
  3497      * @type int
       
  3498      * @property duration
       
  3499      */
       
  3500     this.duration = 0;
       
  3501 };
       
  3502 
       
  3503 /**
       
  3504  * Includes results from another results object into this one.
       
  3505  * @param {Test.Results} result The results object to include.
       
  3506  * @method include
       
  3507  */
       
  3508 YUITest.Results.prototype.include = function(results){
       
  3509     this.passed += results.passed;
       
  3510     this.failed += results.failed;
       
  3511     this.ignored += results.ignored;
       
  3512     this.total += results.total;
       
  3513     this.errors += results.errors;
       
  3514 };
       
  3515 /**
       
  3516  * ShouldError is subclass of Error that is thrown whenever
       
  3517  * a test is expected to throw an error but doesn't.
       
  3518  *
       
  3519  * @param {String} message The message to display when the error occurs.
       
  3520  * @namespace Test
       
  3521  * @extends AssertionError
       
  3522  * @module test
       
  3523  * @class ShouldError
       
  3524  * @constructor
       
  3525  */
       
  3526 YUITest.ShouldError = function (message){
       
  3527 
       
  3528     //call superclass
       
  3529     YUITest.AssertionError.call(this, message || "This test should have thrown an error but didn't.");
       
  3530 
       
  3531     /**
       
  3532      * The name of the error that occurred.
       
  3533      * @type String
       
  3534      * @property name
       
  3535      */
       
  3536     this.name = "ShouldError";
       
  3537 
       
  3538 };
       
  3539 
       
  3540 //inherit from YUITest.AssertionError
       
  3541 YUITest.ShouldError.prototype = new YUITest.AssertionError();
       
  3542 
       
  3543 //restore constructor
       
  3544 YUITest.ShouldError.prototype.constructor = YUITest.ShouldError;
       
  3545 /**
       
  3546  * ShouldFail is subclass of AssertionError that is thrown whenever
       
  3547  * a test was expected to fail but did not.
       
  3548  *
       
  3549  * @param {String} message The message to display when the error occurs.
       
  3550  * @namespace Test
       
  3551  * @extends YUITest.AssertionError
       
  3552  * @module test
       
  3553  * @class ShouldFail
       
  3554  * @constructor
       
  3555  */
       
  3556 YUITest.ShouldFail = function (message){
       
  3557 
       
  3558     //call superclass
       
  3559     YUITest.AssertionError.call(this, message || "This test should fail but didn't.");
       
  3560 
       
  3561     /**
       
  3562      * The name of the error that occurred.
       
  3563      * @type String
       
  3564      * @property name
       
  3565      */
       
  3566     this.name = "ShouldFail";
       
  3567 
       
  3568 };
       
  3569 
       
  3570 //inherit from YUITest.AssertionError
       
  3571 YUITest.ShouldFail.prototype = new YUITest.AssertionError();
       
  3572 
       
  3573 //restore constructor
       
  3574 YUITest.ShouldFail.prototype.constructor = YUITest.ShouldFail;
       
  3575 /**
       
  3576  * UnexpectedError is subclass of AssertionError that is thrown whenever
       
  3577  * an error occurs within the course of a test and the test was not expected
       
  3578  * to throw an error.
       
  3579  *
       
  3580  * @param {Error} cause The unexpected error that caused this error to be
       
  3581  *                      thrown.
       
  3582  * @namespace Test
       
  3583  * @extends YUITest.AssertionError
       
  3584  * @module test
       
  3585  * @class UnexpectedError
       
  3586  * @constructor
       
  3587  */
       
  3588 YUITest.UnexpectedError = function (cause){
       
  3589 
       
  3590     //call superclass
       
  3591     YUITest.AssertionError.call(this, "Unexpected error: " + cause.message);
       
  3592 
       
  3593     /**
       
  3594      * The unexpected error that occurred.
       
  3595      * @type Error
       
  3596      * @property cause
       
  3597      */
       
  3598     this.cause = cause;
       
  3599 
       
  3600     /**
       
  3601      * The name of the error that occurred.
       
  3602      * @type String
       
  3603      * @property name
       
  3604      */
       
  3605     this.name = "UnexpectedError";
       
  3606 
       
  3607     /**
       
  3608      * Stack information for the error (if provided).
       
  3609      * @type String
       
  3610      * @property stack
       
  3611      */
       
  3612     this.stack = cause.stack;
       
  3613 
       
  3614 };
       
  3615 
       
  3616 //inherit from YUITest.AssertionError
       
  3617 YUITest.UnexpectedError.prototype = new YUITest.AssertionError();
       
  3618 
       
  3619 //restore constructor
       
  3620 YUITest.UnexpectedError.prototype.constructor = YUITest.UnexpectedError;
       
  3621 /**
       
  3622  * UnexpectedValue is subclass of Error that is thrown whenever
       
  3623  * a value was unexpected in its scope. This typically means that a test
       
  3624  * was performed to determine that a value was *not* equal to a certain
       
  3625  * value.
       
  3626  *
       
  3627  * @param {String} message The message to display when the error occurs.
       
  3628  * @param {Object} unexpected The unexpected value.
       
  3629  * @namespace Test
       
  3630  * @extends AssertionError
       
  3631  * @module test
       
  3632  * @class UnexpectedValue
       
  3633  * @constructor
       
  3634  */
       
  3635 YUITest.UnexpectedValue = function (message, unexpected){
       
  3636 
       
  3637     //call superclass
       
  3638     YUITest.AssertionError.call(this, message);
       
  3639 
       
  3640     /**
       
  3641      * The unexpected value.
       
  3642      * @type Object
       
  3643      * @property unexpected
       
  3644      */
       
  3645     this.unexpected = unexpected;
       
  3646 
       
  3647     /**
       
  3648      * The name of the error that occurred.
       
  3649      * @type String
       
  3650      * @property name
       
  3651      */
       
  3652     this.name = "UnexpectedValue";
       
  3653 
       
  3654 };
       
  3655 
       
  3656 //inherit from YUITest.AssertionError
       
  3657 YUITest.UnexpectedValue.prototype = new YUITest.AssertionError();
       
  3658 
       
  3659 //restore constructor
       
  3660 YUITest.UnexpectedValue.prototype.constructor = YUITest.UnexpectedValue;
       
  3661 
       
  3662 /**
       
  3663  * Returns a fully formatted error for an assertion failure. This message
       
  3664  * provides information about the expected and actual values.
       
  3665  * @method getMessage
       
  3666  * @return {String} A string describing the error.
       
  3667  */
       
  3668 YUITest.UnexpectedValue.prototype.getMessage = function(){
       
  3669     return this.message + "\nUnexpected: " + this.unexpected + " (" + (typeof this.unexpected) + ") ";
       
  3670 };
       
  3671 
       
  3672 /**
       
  3673  * Represents a stoppage in test execution to wait for an amount of time before
       
  3674  * continuing.
       
  3675  * @param {Function} segment A function to run when the wait is over.
       
  3676  * @param {Number} delay The number of milliseconds to wait before running the code.
       
  3677  * @module test
       
  3678  * @class Wait
       
  3679  * @namespace Test
       
  3680  * @constructor
       
  3681  *
       
  3682  */
       
  3683 YUITest.Wait = function (segment, delay) {
       
  3684 
       
  3685     /**
       
  3686      * The segment of code to run when the wait is over.
       
  3687      * @type Function
       
  3688      * @property segment
       
  3689      */
       
  3690     this.segment = (typeof segment == "function" ? segment : null);
       
  3691 
       
  3692     /**
       
  3693      * The delay before running the segment of code.
       
  3694      * @type int
       
  3695      * @property delay
       
  3696      */
       
  3697     this.delay = (typeof delay == "number" ? delay : 0);
       
  3698 };
       
  3699 
       
  3700 
       
  3701 //Setting up our aliases..
       
  3702 Y.Test = YUITest;
       
  3703 Y.Object.each(YUITest, function(item, name) {
       
  3704     var name = name.replace('Test', '');
       
  3705     Y.Test[name] = item;
       
  3706 });
       
  3707 
       
  3708 } //End of else in top wrapper
       
  3709 
       
  3710 Y.Assert = YUITest.Assert;
       
  3711 Y.Assert.Error = Y.Test.AssertionError;
       
  3712 Y.Assert.ComparisonFailure = Y.Test.ComparisonFailure;
       
  3713 Y.Assert.UnexpectedValue = Y.Test.UnexpectedValue;
       
  3714 Y.Mock = Y.Test.Mock;
       
  3715 Y.ObjectAssert = Y.Test.ObjectAssert;
       
  3716 Y.ArrayAssert = Y.Test.ArrayAssert;
       
  3717 Y.DateAssert = Y.Test.DateAssert;
       
  3718 Y.Test.ResultsFormat = Y.Test.TestFormat;
       
  3719 
       
  3720 var itemsAreEqual = Y.Test.ArrayAssert.itemsAreEqual;
       
  3721 
       
  3722 Y.Test.ArrayAssert.itemsAreEqual = function(expected, actual, message) {
       
  3723     return itemsAreEqual.call(this, Y.Array(expected), Y.Array(actual), message);
       
  3724 };
       
  3725 
       
  3726 
       
  3727 /**
       
  3728  * Asserts that a given condition is true. If not, then a Y.Assert.Error object is thrown
       
  3729  * and the test fails.
       
  3730  * @method assert
       
  3731  * @param {Boolean} condition The condition to test.
       
  3732  * @param {String} message The message to display if the assertion fails.
       
  3733  * @for YUI
       
  3734  * @static
       
  3735  */
       
  3736 Y.assert = function(condition, message){
       
  3737     Y.Assert._increment();
       
  3738     if (!condition){
       
  3739         throw new Y.Assert.Error(Y.Assert._formatMessage(message, "Assertion failed."));
       
  3740     }
       
  3741 };
       
  3742 
       
  3743 /**
       
  3744  * Forces an assertion error to occur. Shortcut for Y.Assert.fail().
       
  3745  * @method fail
       
  3746  * @param {String} message (Optional) The message to display with the failure.
       
  3747  * @for YUI
       
  3748  * @static
       
  3749  */
       
  3750 Y.fail = Y.Assert.fail;
       
  3751 
       
  3752 Y.Test.Runner.once = Y.Test.Runner.subscribe;
       
  3753 
       
  3754 Y.Test.Runner.disableLogging = function() {
       
  3755     Y.Test.Runner._log = false;
       
  3756 };
       
  3757 
       
  3758 Y.Test.Runner.enableLogging = function() {
       
  3759     Y.Test.Runner._log = true;
       
  3760 };
       
  3761 
       
  3762 Y.Test.Runner._ignoreEmpty = true;
       
  3763 Y.Test.Runner._log = true;
       
  3764 
       
  3765 Y.Test.Runner.on = Y.Test.Runner.attach;
       
  3766 
       
  3767 //Only allow one instance of YUITest
       
  3768 if (!YUI.YUITest) {
       
  3769 
       
  3770     if (Y.config.win) {
       
  3771         Y.config.win.YUITest = YUITest;
       
  3772     }
       
  3773 
       
  3774     YUI.YUITest = Y.Test;
       
  3775 
       
  3776 
       
  3777     //Only setup the listeners once.
       
  3778     var logEvent = function(event) {
       
  3779 
       
  3780         //data variables
       
  3781         var message = "";
       
  3782         var messageType = "";
       
  3783 
       
  3784         switch(event.type){
       
  3785             case this.BEGIN_EVENT:
       
  3786                 message = "Testing began at " + (new Date()).toString() + ".";
       
  3787                 messageType = "info";
       
  3788                 break;
       
  3789 
       
  3790             case this.COMPLETE_EVENT:
       
  3791                 message = Y.Lang.sub("Testing completed at " +
       
  3792                     (new Date()).toString() + ".\n" +
       
  3793                     "Passed:{passed} Failed:{failed} " +
       
  3794                     "Total:{total} ({ignored} ignored)",
       
  3795                     event.results);
       
  3796                 messageType = "info";
       
  3797                 break;
       
  3798 
       
  3799             case this.TEST_FAIL_EVENT:
       
  3800                 message = event.testName + ": failed.\n" + event.error.getMessage();
       
  3801                 messageType = "fail";
       
  3802                 break;
       
  3803 
       
  3804             case this.TEST_IGNORE_EVENT:
       
  3805                 message = event.testName + ": ignored.";
       
  3806                 messageType = "ignore";
       
  3807                 break;
       
  3808 
       
  3809             case this.TEST_PASS_EVENT:
       
  3810                 message = event.testName + ": passed.";
       
  3811                 messageType = "pass";
       
  3812                 break;
       
  3813 
       
  3814             case this.TEST_SUITE_BEGIN_EVENT:
       
  3815                 message = "Test suite \"" + event.testSuite.name + "\" started.";
       
  3816                 messageType = "info";
       
  3817                 break;
       
  3818 
       
  3819             case this.TEST_SUITE_COMPLETE_EVENT:
       
  3820                 message = Y.Lang.sub("Test suite \"" +
       
  3821                     event.testSuite.name + "\" completed" + ".\n" +
       
  3822                     "Passed:{passed} Failed:{failed} " +
       
  3823                     "Total:{total} ({ignored} ignored)",
       
  3824                     event.results);
       
  3825                 messageType = "info";
       
  3826                 break;
       
  3827 
       
  3828             case this.TEST_CASE_BEGIN_EVENT:
       
  3829                 message = "Test case \"" + event.testCase.name + "\" started.";
       
  3830                 messageType = "info";
       
  3831                 break;
       
  3832 
       
  3833             case this.TEST_CASE_COMPLETE_EVENT:
       
  3834                 message = Y.Lang.sub("Test case \"" +
       
  3835                     event.testCase.name + "\" completed.\n" +
       
  3836                     "Passed:{passed} Failed:{failed} " +
       
  3837                     "Total:{total} ({ignored} ignored)",
       
  3838                     event.results);
       
  3839                 messageType = "info";
       
  3840                 break;
       
  3841             default:
       
  3842                 message = "Unexpected event " + event.type;
       
  3843                 messageType = "info";
       
  3844         }
       
  3845 
       
  3846         if (Y.Test.Runner._log) {
       
  3847             Y.log(message, messageType, "TestRunner");
       
  3848         }
       
  3849     };
       
  3850 
       
  3851     var i, name;
       
  3852 
       
  3853     for (i in Y.Test.Runner) {
       
  3854         name = Y.Test.Runner[i];
       
  3855         if (i.indexOf('_EVENT') > -1) {
       
  3856             Y.Test.Runner.subscribe(name, logEvent);
       
  3857         }
       
  3858     };
       
  3859 
       
  3860 } //End if for YUI.YUITest
       
  3861 
       
  3862 
       
  3863 }, '@VERSION@', {"requires": ["event-simulate", "event-custom", "json-stringify"]});