[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-yuitest/ -> yui2-yuitest-debug.js (source)

   1  YUI.add('yui2-yuitest', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  YAHOO.namespace("tool");
  10  
  11  //-----------------------------------------------------------------------------
  12  // TestCase object
  13  //-----------------------------------------------------------------------------
  14  (function(){
  15      
  16      //used for autogenerating test case names
  17      var tempId = 0;
  18      
  19      /**
  20       * Test case containing various tests to run.
  21       * @param template An object containing any number of test methods, other methods,
  22       *                 an optional name, and anything else the test case needs.
  23       * @class TestCase
  24       * @namespace YAHOO.tool
  25       * @constructor
  26       */
  27      YAHOO.tool.TestCase = function (template /*:Object*/) {
  28          
  29          /**
  30           * Special rules for the test case. Possible subobjects
  31           * are fail, for tests that should fail, and error, for
  32           * tests that should throw an error.
  33           */
  34          this._should /*:Object*/ = {};
  35          
  36          //copy over all properties from the template to this object
  37          for (var prop in template) {
  38              this[prop] = template[prop];
  39          }    
  40          
  41          //check for a valid name
  42          if (!YAHOO.lang.isString(this.name)){
  43              /**
  44               * Name for the test case.
  45               */
  46              this.name /*:String*/ = "testCase" + (tempId++);
  47          }
  48      
  49      };
  50      
  51      
  52      YAHOO.tool.TestCase.prototype = {  
  53      
  54          /**
  55           * Resumes a paused test and runs the given function.
  56           * @param {Function} segment (Optional) The function to run.
  57           *      If omitted, the test automatically passes.
  58           * @return {Void}
  59           * @method resume
  60           */
  61          resume : function (segment /*:Function*/) /*:Void*/ {
  62              YAHOO.tool.TestRunner.resume(segment);
  63          },
  64      
  65          /**
  66           * Causes the test case to wait a specified amount of time and then
  67           * continue executing the given code.
  68           * @param {Function} segment (Optional) The function to run after the delay.
  69           *      If omitted, the TestRunner will wait until resume() is called.
  70           * @param {int} delay (Optional) The number of milliseconds to wait before running
  71           *      the function. If omitted, defaults to zero.
  72           * @return {Void}
  73           * @method wait
  74           */
  75          wait : function (segment /*:Function*/, delay /*:int*/) /*:Void*/{
  76              var args = arguments;
  77              if (YAHOO.lang.isFunction(args[0])){
  78                  throw new YAHOO.tool.TestCase.Wait(args[0], args[1]);
  79              } else {
  80                  throw new YAHOO.tool.TestCase.Wait(function(){
  81                      YAHOO.util.Assert.fail("Timeout: wait() called but resume() never called.");
  82                  }, (YAHOO.lang.isNumber(args[0]) ? args[0] : 10000));
  83              }            
  84          },
  85      
  86          //-------------------------------------------------------------------------
  87          // Stub Methods
  88          //-------------------------------------------------------------------------
  89      
  90          /**
  91           * Function to run before each test is executed.
  92           * @return {Void}
  93           * @method setUp
  94           */
  95          setUp : function () /*:Void*/ {
  96          },
  97          
  98          /**
  99           * Function to run after each test is executed.
 100           * @return {Void}
 101           * @method tearDown
 102           */
 103          tearDown: function () /*:Void*/ {    
 104          }
 105      };
 106      
 107      /**
 108       * Represents a stoppage in test execution to wait for an amount of time before
 109       * continuing.
 110       * @param {Function} segment A function to run when the wait is over.
 111       * @param {int} delay The number of milliseconds to wait before running the code.
 112       * @class Wait
 113       * @namespace YAHOO.tool.TestCase
 114       * @constructor
 115       *
 116       */
 117      YAHOO.tool.TestCase.Wait = function (segment /*:Function*/, delay /*:int*/) {
 118          
 119          /**
 120           * The segment of code to run when the wait is over.
 121           * @type Function
 122           * @property segment
 123           */
 124          this.segment /*:Function*/ = (YAHOO.lang.isFunction(segment) ? segment : null);
 125      
 126          /**
 127           * The delay before running the segment of code.
 128           * @type int
 129           * @property delay
 130           */
 131          this.delay /*:int*/ = (YAHOO.lang.isNumber(delay) ? delay : 0);
 132      
 133      };
 134  
 135  })();
 136  YAHOO.namespace("tool");
 137  
 138  
 139  //-----------------------------------------------------------------------------
 140  // TestSuite object
 141  //-----------------------------------------------------------------------------
 142  
 143  /**
 144   * A test suite that can contain a collection of TestCase and TestSuite objects.
 145   * @param {String||Object} data The name of the test suite or an object containing
 146   *      a name property as well as setUp and tearDown methods.
 147   * @namespace YAHOO.tool
 148   * @class TestSuite
 149   * @constructor
 150   */
 151  YAHOO.tool.TestSuite = function (data /*:String||Object*/) {
 152  
 153      /**
 154       * The name of the test suite.
 155       * @type String
 156       * @property name
 157       */
 158      this.name /*:String*/ = "";
 159  
 160      /**
 161       * Array of test suites and
 162       * @private
 163       */
 164      this.items /*:Array*/ = [];
 165  
 166      //initialize the properties
 167      if (YAHOO.lang.isString(data)){
 168          this.name = data;
 169      } else if (YAHOO.lang.isObject(data)){
 170          YAHOO.lang.augmentObject(this, data, true);
 171      }
 172  
 173      //double-check name
 174      if (this.name === ""){
 175          this.name = YAHOO.util.Dom.generateId(null, "testSuite");
 176      }
 177  
 178  };
 179  
 180  YAHOO.tool.TestSuite.prototype = {
 181      
 182      /**
 183       * Adds a test suite or test case to the test suite.
 184       * @param {YAHOO.tool.TestSuite||YAHOO.tool.TestCase} testObject The test suite or test case to add.
 185       * @return {Void}
 186       * @method add
 187       */
 188      add : function (testObject /*:YAHOO.tool.TestSuite*/) /*:Void*/ {
 189          if (testObject instanceof YAHOO.tool.TestSuite || testObject instanceof YAHOO.tool.TestCase) {
 190              this.items.push(testObject);
 191          }
 192      },
 193      
 194      //-------------------------------------------------------------------------
 195      // Stub Methods
 196      //-------------------------------------------------------------------------
 197  
 198      /**
 199       * Function to run before each test is executed.
 200       * @return {Void}
 201       * @method setUp
 202       */
 203      setUp : function () /*:Void*/ {
 204      },
 205      
 206      /**
 207       * Function to run after each test is executed.
 208       * @return {Void}
 209       * @method tearDown
 210       */
 211      tearDown: function () /*:Void*/ {
 212      }
 213      
 214  };
 215  YAHOO.namespace("tool");
 216  
 217  /**
 218   * The YUI test tool
 219   * @module yuitest
 220   * @namespace YAHOO.tool
 221   * @requires yahoo,dom,event,logger
 222   * @optional event-simulate
 223   */
 224  
 225  
 226  //-----------------------------------------------------------------------------
 227  // TestRunner object
 228  //-----------------------------------------------------------------------------
 229  
 230  
 231  YAHOO.tool.TestRunner = (function(){
 232  
 233      /**
 234       * A node in the test tree structure. May represent a TestSuite, TestCase, or
 235       * test function.
 236       * @param {Variant} testObject A TestSuite, TestCase, or the name of a test function.
 237       * @class TestNode
 238       * @constructor
 239       * @private
 240       */
 241      function TestNode(testObject /*:Variant*/){
 242      
 243          /**
 244           * The TestSuite, TestCase, or test function represented by this node.
 245           * @type Variant
 246           * @property testObject
 247           */
 248          this.testObject = testObject;
 249          
 250          /**
 251           * Pointer to this node's first child.
 252           * @type TestNode
 253           * @property firstChild
 254           */        
 255          this.firstChild /*:TestNode*/ = null;
 256          
 257          /**
 258           * Pointer to this node's last child.
 259           * @type TestNode
 260           * @property lastChild
 261           */        
 262          this.lastChild = null;
 263          
 264          /**
 265           * Pointer to this node's parent.
 266           * @type TestNode
 267           * @property parent
 268           */        
 269          this.parent = null; 
 270     
 271          /**
 272           * Pointer to this node's next sibling.
 273           * @type TestNode
 274           * @property next
 275           */        
 276          this.next = null;
 277          
 278          /**
 279           * Test results for this test object.
 280           * @type object
 281           * @property results
 282           */                
 283          this.results /*:Object*/ = {
 284              passed : 0,
 285              failed : 0,
 286              total : 0,
 287              ignored : 0,
 288              duration: 0
 289          };
 290          
 291          //initialize results
 292          if (testObject instanceof YAHOO.tool.TestSuite){
 293              this.results.type = "testsuite";
 294              this.results.name = testObject.name;
 295          } else if (testObject instanceof YAHOO.tool.TestCase){
 296              this.results.type = "testcase";
 297              this.results.name = testObject.name;
 298          }
 299         
 300      }
 301      
 302      TestNode.prototype = {
 303      
 304          /**
 305           * Appends a new test object (TestSuite, TestCase, or test function name) as a child
 306           * of this node.
 307           * @param {Variant} testObject A TestSuite, TestCase, or the name of a test function.
 308           * @return {Void}
 309           */
 310          appendChild : function (testObject /*:Variant*/) /*:Void*/{
 311              var node = new TestNode(testObject);
 312              if (this.firstChild === null){
 313                  this.firstChild = this.lastChild = node;
 314              } else {
 315                  this.lastChild.next = node;
 316                  this.lastChild = node;
 317              }
 318              node.parent = this;
 319              return node;
 320          }       
 321      };
 322  
 323      /**
 324       * Runs test suites and test cases, providing events to allowing for the
 325       * interpretation of test results.
 326       * @namespace YAHOO.tool
 327       * @class TestRunner
 328       * @static
 329       */
 330      function TestRunner(){
 331      
 332          //inherit from EventProvider
 333          TestRunner.superclass.constructor.apply(this,arguments);
 334          
 335          /**
 336           * Suite on which to attach all TestSuites and TestCases to be run.
 337           * @type YAHOO.tool.TestSuite
 338           * @property masterSuite
 339           * @private
 340           * @static
 341           */
 342          this.masterSuite = new YAHOO.tool.TestSuite("yuitests" + (new Date()).getTime());        
 343  
 344          /**
 345           * Pointer to the current node in the test tree.
 346           * @type TestNode
 347           * @private
 348           * @property _cur
 349           * @static
 350           */
 351          this._cur = null;                
 352          
 353          /**
 354           * Pointer to the root node in the test tree.
 355           * @type TestNode
 356           * @private
 357           * @property _root
 358           * @static
 359           */
 360          this._root = null;
 361          
 362          /**
 363           * Indicates if the TestRunner is currently running tests.
 364           * @type Boolean
 365           * @private
 366           * @property _running
 367           * @static
 368           */
 369          this._running = false;
 370          
 371          /**
 372           * Holds copy of the results object generated when all tests are
 373           * complete.
 374           * @type Object
 375           * @private
 376           * @property _lastResults
 377           * @static
 378           */
 379          this._lastResults = null;
 380          
 381          //create events
 382          var events /*:Array*/ = [
 383              this.TEST_CASE_BEGIN_EVENT,
 384              this.TEST_CASE_COMPLETE_EVENT,
 385              this.TEST_SUITE_BEGIN_EVENT,
 386              this.TEST_SUITE_COMPLETE_EVENT,
 387              this.TEST_PASS_EVENT,
 388              this.TEST_FAIL_EVENT,
 389              this.TEST_IGNORE_EVENT,
 390              this.COMPLETE_EVENT,
 391              this.BEGIN_EVENT
 392          ];
 393          for (var i=0; i < events.length; i++){
 394              this.createEvent(events[i], { scope: this });
 395          }       
 396     
 397      }
 398      
 399      YAHOO.lang.extend(TestRunner, YAHOO.util.EventProvider, {
 400      
 401          //-------------------------------------------------------------------------
 402          // Constants
 403          //-------------------------------------------------------------------------
 404           
 405          /**
 406           * Fires when a test case is opened but before the first 
 407           * test is executed.
 408           * @event testcasebegin
 409           */         
 410          TEST_CASE_BEGIN_EVENT /*:String*/ : "testcasebegin",
 411          
 412          /**
 413           * Fires when all tests in a test case have been executed.
 414           * @event testcasecomplete
 415           */        
 416          TEST_CASE_COMPLETE_EVENT /*:String*/ : "testcasecomplete",
 417          
 418          /**
 419           * Fires when a test suite is opened but before the first 
 420           * test is executed.
 421           * @event testsuitebegin
 422           */        
 423          TEST_SUITE_BEGIN_EVENT /*:String*/ : "testsuitebegin",
 424          
 425          /**
 426           * Fires when all test cases in a test suite have been
 427           * completed.
 428           * @event testsuitecomplete
 429           */        
 430          TEST_SUITE_COMPLETE_EVENT /*:String*/ : "testsuitecomplete",
 431          
 432          /**
 433           * Fires when a test has passed.
 434           * @event pass
 435           */        
 436          TEST_PASS_EVENT /*:String*/ : "pass",
 437          
 438          /**
 439           * Fires when a test has failed.
 440           * @event fail
 441           */        
 442          TEST_FAIL_EVENT /*:String*/ : "fail",
 443          
 444          /**
 445           * Fires when a test has been ignored.
 446           * @event ignore
 447           */        
 448          TEST_IGNORE_EVENT /*:String*/ : "ignore",
 449          
 450          /**
 451           * Fires when all test suites and test cases have been completed.
 452           * @event complete
 453           */        
 454          COMPLETE_EVENT /*:String*/ : "complete",
 455          
 456          /**
 457           * Fires when the run() method is called.
 458           * @event begin
 459           */        
 460          BEGIN_EVENT /*:String*/ : "begin",                
 461          
 462          //-------------------------------------------------------------------------
 463          // Misc Methods
 464          //-------------------------------------------------------------------------   
 465  
 466          /**
 467           * Retrieves the name of the current result set.
 468           * @return {String} The name of the result set.
 469           * @method getName
 470           */
 471          getName: function(){
 472              return this.masterSuite.name;
 473          },         
 474  
 475          /**
 476           * The name assigned to the master suite of the TestRunner. This is the name
 477           * that is output as the root's name when results are retrieved.
 478           * @param {String} name The name of the result set.
 479           * @return {Void}
 480           * @method setName
 481           */
 482          setName: function(name){
 483              this.masterSuite.name = name;
 484          },        
 485          
 486          
 487          //-------------------------------------------------------------------------
 488          // State-Related Methods
 489          //-------------------------------------------------------------------------
 490  
 491          /**
 492           * Indicates that the TestRunner is busy running tests and therefore can't
 493           * be stopped and results cannot be gathered.
 494           * @return {Boolean} True if the TestRunner is running, false if not.
 495           * @method isRunning
 496           */
 497          isRunning: function(){
 498              return this._running;
 499          },
 500          
 501          /**
 502           * Returns the last complete results set from the TestRunner. Null is returned
 503           * if the TestRunner is running or no tests have been run.
 504           * @param {Function} format (Optional) A test format to return the results in.
 505           * @return {Object|String} Either the results object or, if a test format is 
 506           *      passed as the argument, a string representing the results in a specific
 507           *      format.
 508           * @method getResults
 509           */
 510          getResults: function(format){
 511              if (!this._running && this._lastResults){
 512                  if (YAHOO.lang.isFunction(format)){
 513                      return format(this._lastResults);                    
 514                  } else {
 515                      return this._lastResults;
 516                  }
 517              } else {
 518                  return null;
 519              }
 520          },
 521  
 522          /**
 523           * Returns the coverage report for the files that have been executed.
 524           * This returns only coverage information for files that have been
 525           * instrumented using YUI Test Coverage and only those that were run
 526           * in the same pass.
 527           * @param {Function} format (Optional) A coverage format to return results in.
 528           * @return {Object|String} Either the coverage object or, if a coverage
 529           *      format is specified, a string representing the results in that format.
 530           * @method getCoverage
 531           */
 532          getCoverage: function(format){
 533              if (!this._running && typeof _yuitest_coverage == "object"){
 534                  if (YAHOO.lang.isFunction(format)){
 535                      return format(_yuitest_coverage);                    
 536                  } else {
 537                      return _yuitest_coverage;
 538                  }
 539              } else {
 540                  return null;
 541              }            
 542          },
 543          
 544          //-------------------------------------------------------------------------
 545          // Misc Methods
 546          //-------------------------------------------------------------------------
 547  
 548          /**
 549           * Retrieves the name of the current result set.
 550           * @return {String} The name of the result set.
 551           * @method getName
 552           */
 553          getName: function(){
 554              return this.masterSuite.name;
 555          },         
 556  
 557          /**
 558           * The name assigned to the master suite of the TestRunner. This is the name
 559           * that is output as the root's name when results are retrieved.
 560           * @param {String} name The name of the result set.
 561           * @return {Void}
 562           * @method setName
 563           */
 564          setName: function(name){
 565              this.masterSuite.name = name;
 566          },
 567  
 568          //-------------------------------------------------------------------------
 569          // Test Tree-Related Methods
 570          //-------------------------------------------------------------------------
 571  
 572          /**
 573           * Adds a test case to the test tree as a child of the specified node.
 574           * @param {TestNode} parentNode The node to add the test case to as a child.
 575           * @param {YAHOO.tool.TestCase} testCase The test case to add.
 576           * @return {Void}
 577           * @static
 578           * @private
 579           * @method _addTestCaseToTestTree
 580           */
 581         _addTestCaseToTestTree : function (parentNode /*:TestNode*/, testCase /*:YAHOO.tool.TestCase*/) /*:Void*/{
 582              
 583              //add the test suite
 584              var node = parentNode.appendChild(testCase);
 585              
 586              //iterate over the items in the test case
 587              for (var prop in testCase){
 588                  if (prop.indexOf("test") === 0 && YAHOO.lang.isFunction(testCase[prop])){
 589                      node.appendChild(prop);
 590                  }
 591              }
 592           
 593          },
 594          
 595          /**
 596           * Adds a test suite to the test tree as a child of the specified node.
 597           * @param {TestNode} parentNode The node to add the test suite to as a child.
 598           * @param {YAHOO.tool.TestSuite} testSuite The test suite to add.
 599           * @return {Void}
 600           * @static
 601           * @private
 602           * @method _addTestSuiteToTestTree
 603           */
 604          _addTestSuiteToTestTree : function (parentNode /*:TestNode*/, testSuite /*:YAHOO.tool.TestSuite*/) /*:Void*/ {
 605              
 606              //add the test suite
 607              var node = parentNode.appendChild(testSuite);
 608              
 609              //iterate over the items in the master suite
 610              for (var i=0; i < testSuite.items.length; i++){
 611                  if (testSuite.items[i] instanceof YAHOO.tool.TestSuite) {
 612                      this._addTestSuiteToTestTree(node, testSuite.items[i]);
 613                  } else if (testSuite.items[i] instanceof YAHOO.tool.TestCase) {
 614                      this._addTestCaseToTestTree(node, testSuite.items[i]);
 615                  }                   
 616              }            
 617          },
 618          
 619          /**
 620           * Builds the test tree based on items in the master suite. The tree is a hierarchical
 621           * representation of the test suites, test cases, and test functions. The resulting tree
 622           * is stored in _root and the pointer _cur is set to the root initially.
 623           * @return {Void}
 624           * @static
 625           * @private
 626           * @method _buildTestTree
 627           */
 628          _buildTestTree : function () /*:Void*/ {
 629          
 630              this._root = new TestNode(this.masterSuite);
 631              //this._cur = this._root;
 632              
 633              //iterate over the items in the master suite
 634              for (var i=0; i < this.masterSuite.items.length; i++){
 635                  if (this.masterSuite.items[i] instanceof YAHOO.tool.TestSuite) {
 636                      this._addTestSuiteToTestTree(this._root, this.masterSuite.items[i]);
 637                  } else if (this.masterSuite.items[i] instanceof YAHOO.tool.TestCase) {
 638                      this._addTestCaseToTestTree(this._root, this.masterSuite.items[i]);
 639                  }                   
 640              }            
 641          
 642          }, 
 643      
 644          //-------------------------------------------------------------------------
 645          // Private Methods
 646          //-------------------------------------------------------------------------
 647          
 648          /**
 649           * Handles the completion of a test object's tests. Tallies test results 
 650           * from one level up to the next.
 651           * @param {TestNode} node The TestNode representing the test object.
 652           * @return {Void}
 653           * @method _handleTestObjectComplete
 654           * @private
 655           * @static
 656           */
 657          _handleTestObjectComplete : function (node /*:TestNode*/) /*:Void*/ {
 658              if (YAHOO.lang.isObject(node.testObject)){
 659                  node.parent.results.passed += node.results.passed;
 660                  node.parent.results.failed += node.results.failed;
 661                  node.parent.results.total += node.results.total;                
 662                  node.parent.results.ignored += node.results.ignored;                
 663                  node.parent.results[node.testObject.name] = node.results;
 664              
 665                  if (node.testObject instanceof YAHOO.tool.TestSuite){
 666                      node.testObject.tearDown();
 667                      node.results.duration = (new Date()) - node._start;
 668                      this.fireEvent(this.TEST_SUITE_COMPLETE_EVENT, { testSuite: node.testObject, results: node.results});
 669                  } else if (node.testObject instanceof YAHOO.tool.TestCase){
 670                      node.results.duration = (new Date()) - node._start;
 671                      this.fireEvent(this.TEST_CASE_COMPLETE_EVENT, { testCase: node.testObject, results: node.results});
 672                  }      
 673              } 
 674          },                
 675          
 676          //-------------------------------------------------------------------------
 677          // Navigation Methods
 678          //-------------------------------------------------------------------------
 679          
 680          /**
 681           * Retrieves the next node in the test tree.
 682           * @return {TestNode} The next node in the test tree or null if the end is reached.
 683           * @private
 684           * @static
 685           * @method _next
 686           */
 687          _next : function () /*:TestNode*/ {
 688                  
 689              if (this._cur === null){
 690                  this._cur = this._root;
 691              } else if (this._cur.firstChild) {
 692                  this._cur = this._cur.firstChild;
 693              } else if (this._cur.next) {
 694                  this._cur = this._cur.next;            
 695              } else {
 696                  while (this._cur && !this._cur.next && this._cur !== this._root){
 697                      this._handleTestObjectComplete(this._cur);
 698                      this._cur = this._cur.parent;
 699                  }
 700                  
 701                  if (this._cur == this._root){
 702                      this._cur.results.type = "report";
 703                      this._cur.results.timestamp = (new Date()).toLocaleString();
 704                      this._cur.results.duration = (new Date()) - this._cur._start;                       
 705                      this._lastResults = this._cur.results;
 706                      this._running = false;
 707                      this.fireEvent(this.COMPLETE_EVENT, { results: this._lastResults});
 708                      this._cur = null;
 709                  } else {
 710                      this._handleTestObjectComplete(this._cur);               
 711                      this._cur = this._cur.next;                
 712                  }
 713              }
 714          
 715              return this._cur;
 716          },
 717          
 718          /**
 719           * Runs a test case or test suite, returning the results.
 720           * @param {YAHOO.tool.TestCase|YAHOO.tool.TestSuite} testObject The test case or test suite to run.
 721           * @return {Object} Results of the execution with properties passed, failed, and total.
 722           * @private
 723           * @method _run
 724           * @static
 725           */
 726          _run : function () /*:Void*/ {
 727                                  
 728              //flag to indicate if the TestRunner should wait before continuing
 729              var shouldWait = false;
 730              
 731              //get the next test node
 732              var node = this._next();
 733  
 734              
 735              if (node !== null) {
 736              
 737                  //set flag to say the testrunner is running
 738                  this._running = true;
 739                  
 740                  //eliminate last results
 741                  this._lastResult = null;            
 742              
 743                  var testObject = node.testObject;
 744                  
 745                  //figure out what to do
 746                  if (YAHOO.lang.isObject(testObject)){
 747                      if (testObject instanceof YAHOO.tool.TestSuite){
 748                          this.fireEvent(this.TEST_SUITE_BEGIN_EVENT, { testSuite: testObject });
 749                          node._start = new Date();
 750                          testObject.setUp();
 751                      } else if (testObject instanceof YAHOO.tool.TestCase){
 752                          this.fireEvent(this.TEST_CASE_BEGIN_EVENT, { testCase: testObject });
 753                          node._start = new Date();
 754                      }
 755                      
 756                      //some environments don't support setTimeout
 757                      if (typeof setTimeout != "undefined"){                    
 758                          setTimeout(function(){
 759                              YAHOO.tool.TestRunner._run();
 760                          }, 0);
 761                      } else {
 762                          this._run();
 763                      }
 764                  } else {
 765                      this._runTest(node);
 766                  }
 767  
 768              }
 769          },
 770          
 771          _resumeTest : function (segment /*:Function*/) /*:Void*/ {
 772          
 773              //get relevant information
 774              var node /*:TestNode*/ = this._cur;
 775              var testName /*:String*/ = node.testObject;
 776              var testCase /*:YAHOO.tool.TestCase*/ = node.parent.testObject;
 777              
 778              //cancel other waits if available
 779              if (testCase.__yui_wait){
 780                  clearTimeout(testCase.__yui_wait);
 781                  delete testCase.__yui_wait;
 782              }            
 783              
 784              //get the "should" test cases
 785              var shouldFail /*:Object*/ = (testCase._should.fail || {})[testName];
 786              var shouldError /*:Object*/ = (testCase._should.error || {})[testName];
 787              
 788              //variable to hold whether or not the test failed
 789              var failed /*:Boolean*/ = false;
 790              var error /*:Error*/ = null;
 791                  
 792              //try the test
 793              try {
 794              
 795                  //run the test
 796                  segment.apply(testCase);
 797                  
 798                  //if it should fail, and it got here, then it's a fail because it didn't
 799                  if (shouldFail){
 800                      error = new YAHOO.util.ShouldFail();
 801                      failed = true;
 802                  } else if (shouldError){
 803                      error = new YAHOO.util.ShouldError();
 804                      failed = true;
 805                  }
 806                             
 807              } catch (thrown /*:Error*/){
 808                  if (thrown instanceof YAHOO.util.AssertionError) {
 809                      if (!shouldFail){
 810                          error = thrown;
 811                          failed = true;
 812                      }
 813                  } else if (thrown instanceof YAHOO.tool.TestCase.Wait){
 814                  
 815                      if (YAHOO.lang.isFunction(thrown.segment)){
 816                          if (YAHOO.lang.isNumber(thrown.delay)){
 817                          
 818                              //some environments don't support setTimeout
 819                              if (typeof setTimeout != "undefined"){
 820                                  testCase.__yui_wait = setTimeout(function(){
 821                                      YAHOO.tool.TestRunner._resumeTest(thrown.segment);
 822                                  }, thrown.delay);                             
 823                              } else {
 824                                  throw new Error("Asynchronous tests not supported in this environment.");
 825                              }
 826                          }
 827                      }
 828                      
 829                      return;
 830                  
 831                  } else {
 832                      //first check to see if it should error
 833                      if (!shouldError) {                        
 834                          error = new YAHOO.util.UnexpectedError(thrown);
 835                          failed = true;
 836                      } else {
 837                          //check to see what type of data we have
 838                          if (YAHOO.lang.isString(shouldError)){
 839                              
 840                              //if it's a string, check the error message
 841                              if (thrown.message != shouldError){
 842                                  error = new YAHOO.util.UnexpectedError(thrown);
 843                                  failed = true;                                    
 844                              }
 845                          } else if (YAHOO.lang.isFunction(shouldError)){
 846                          
 847                              //if it's a function, see if the error is an instance of it
 848                              if (!(thrown instanceof shouldError)){
 849                                  error = new YAHOO.util.UnexpectedError(thrown);
 850                                  failed = true;
 851                              }
 852                          
 853                          } else if (YAHOO.lang.isObject(shouldError)){
 854                          
 855                              //if it's an object, check the instance and message
 856                              if (!(thrown instanceof shouldError.constructor) || 
 857                                      thrown.message != shouldError.message){
 858                                  error = new YAHOO.util.UnexpectedError(thrown);
 859                                  failed = true;                                    
 860                              }
 861                          
 862                          }
 863                      
 864                      }
 865                  }
 866                  
 867              }
 868              
 869              //fireEvent appropriate event
 870              if (failed) {
 871                  this.fireEvent(this.TEST_FAIL_EVENT, { testCase: testCase, testName: testName, error: error });
 872              } else {
 873                  this.fireEvent(this.TEST_PASS_EVENT, { testCase: testCase, testName: testName });
 874              }
 875              
 876              //run the tear down
 877              testCase.tearDown();
 878          
 879              //calculate duration
 880              var duration = (new Date()) - node._start;            
 881              
 882              //update results
 883              node.parent.results[testName] = { 
 884                  result: failed ? "fail" : "pass",
 885                  message: error ? error.getMessage() : "Test passed",
 886                  type: "test",
 887                  name: testName,
 888                  duration: duration
 889              };
 890              
 891              if (failed){
 892                  node.parent.results.failed++;
 893              } else {
 894                  node.parent.results.passed++;
 895              }
 896              node.parent.results.total++;
 897  
 898              //set timeout not supported in all environments
 899              if (typeof setTimeout != "undefined"){
 900                  setTimeout(function(){
 901                      YAHOO.tool.TestRunner._run();
 902                  }, 0);
 903              } else {
 904                  this._run();
 905              }
 906          
 907          },
 908                  
 909          /**
 910           * Runs a single test based on the data provided in the node.
 911           * @param {TestNode} node The TestNode representing the test to run.
 912           * @return {Void}
 913           * @static
 914           * @private
 915           * @name _runTest
 916           */
 917          _runTest : function (node /*:TestNode*/) /*:Void*/ {
 918          
 919              //get relevant information
 920              var testName /*:String*/ = node.testObject;
 921              var testCase /*:YAHOO.tool.TestCase*/ = node.parent.testObject;
 922              var test /*:Function*/ = testCase[testName];
 923              
 924              //get the "should" test cases
 925              var shouldIgnore /*:Object*/ = (testCase._should.ignore || {})[testName];
 926              
 927              //figure out if the test should be ignored or not
 928              if (shouldIgnore){
 929              
 930                  //update results
 931                  node.parent.results[testName] = { 
 932                      result: "ignore",
 933                      message: "Test ignored",
 934                      type: "test",
 935                      name: testName
 936                  };
 937                  
 938                  node.parent.results.ignored++;
 939                  node.parent.results.total++;
 940              
 941                  this.fireEvent(this.TEST_IGNORE_EVENT, { testCase: testCase, testName: testName });
 942                  
 943                  //some environments don't support setTimeout
 944                  if (typeof setTimeout != "undefined"){                    
 945                      setTimeout(function(){
 946                          YAHOO.tool.TestRunner._run();
 947                      }, 0);              
 948                  } else {
 949                      this._run();
 950                  }
 951  
 952              } else {
 953              
 954                  //mark the start time
 955                  node._start = new Date();
 956              
 957                  //run the setup
 958                  testCase.setUp();
 959                  
 960                  //now call the body of the test
 961                  this._resumeTest(test);                
 962              }
 963  
 964          },        
 965          
 966          //-------------------------------------------------------------------------
 967          // Protected Methods
 968          //-------------------------------------------------------------------------   
 969      
 970          /**
 971           * Fires events for the TestRunner. This overrides the default fireEvent()
 972           * method from EventProvider to add the type property to the data that is
 973           * passed through on each event call.
 974           * @param {String} type The type of event to fire.
 975           * @param {Object} data (Optional) Data for the event.
 976           * @method fireEvent
 977           * @static
 978           * @protected
 979           */
 980          fireEvent : function (type /*:String*/, data /*:Object*/) /*:Void*/ {
 981              data = data || {};
 982              data.type = type;
 983              TestRunner.superclass.fireEvent.call(this, type, data);
 984          },
 985  
 986          //-------------------------------------------------------------------------
 987          // Public Methods
 988          //-------------------------------------------------------------------------   
 989      
 990          /**
 991           * Adds a test suite or test case to the list of test objects to run.
 992           * @param testObject Either a TestCase or a TestSuite that should be run.
 993           * @return {Void}
 994           * @method add
 995           * @static
 996           */
 997          add : function (testObject /*:Object*/) /*:Void*/ {
 998              this.masterSuite.add(testObject);
 999          },
1000          
1001          /**
1002           * Removes all test objects from the runner.
1003           * @return {Void}
1004           * @method clear
1005           * @static
1006           */
1007          clear : function () /*:Void*/ {
1008              this.masterSuite = new YAHOO.tool.TestSuite("yuitests" + (new Date()).getTime());
1009          },
1010          
1011          /**
1012           * Resumes the TestRunner after wait() was called.
1013           * @param {Function} segment The function to run as the rest
1014           *      of the haulted test.
1015           * @return {Void}
1016           * @method resume
1017           * @static
1018           */
1019          resume : function (segment /*:Function*/) /*:Void*/ {
1020              this._resumeTest(segment || function(){});
1021          },
1022      
1023          /**
1024           * Runs the test suite.
1025           * @param {Boolean} oldMode (Optional) Specifies that the <= 2.8 way of
1026           *      internally managing test suites should be used.
1027           * @return {Void}
1028           * @method run
1029           * @static
1030           */
1031          run : function (oldMode) {
1032              
1033              //pointer to runner to avoid scope issues 
1034              var runner = YAHOO.tool.TestRunner;
1035              
1036              //if there's only one suite on the masterSuite, move it up
1037              if (!oldMode && this.masterSuite.items.length == 1 && this.masterSuite.items[0] instanceof YAHOO.tool.TestSuite){
1038                  this.masterSuite = this.masterSuite.items[0];
1039              }
1040  
1041              //build the test tree
1042              runner._buildTestTree();
1043              
1044              //set when the test started
1045              runner._root._start = new Date();
1046                              
1047              //fire the begin event
1048              runner.fireEvent(runner.BEGIN_EVENT);
1049         
1050              //begin the testing
1051              runner._run();
1052          }    
1053      });
1054      
1055      return new TestRunner();
1056      
1057  })();
1058  YAHOO.namespace("util");
1059  
1060  //-----------------------------------------------------------------------------
1061  // Assert object
1062  //-----------------------------------------------------------------------------
1063  
1064  /**
1065   * The Assert object provides functions to test JavaScript values against
1066   * known and expected results. Whenever a comparison (assertion) fails,
1067   * an error is thrown.
1068   *
1069   * @namespace YAHOO.util
1070   * @class Assert
1071   * @static
1072   */
1073  YAHOO.util.Assert = {
1074  
1075      //-------------------------------------------------------------------------
1076      // Helper Methods
1077      //-------------------------------------------------------------------------
1078      
1079      /**
1080       * Formats a message so that it can contain the original assertion message
1081       * in addition to the custom message.
1082       * @param {String} customMessage The message passed in by the developer.
1083       * @param {String} defaultMessage The message created by the error by default.
1084       * @return {String} The final error message, containing either or both.
1085       * @protected
1086       * @static
1087       * @method _formatMessage
1088       */
1089      _formatMessage : function (customMessage /*:String*/, defaultMessage /*:String*/) /*:String*/ {
1090          var message = customMessage;
1091          if (YAHOO.lang.isString(customMessage) && customMessage.length > 0){
1092              return YAHOO.lang.substitute(customMessage, { message: defaultMessage });
1093          } else {
1094              return defaultMessage;
1095          }        
1096      },
1097      
1098      //-------------------------------------------------------------------------
1099      // Generic Assertion Methods
1100      //-------------------------------------------------------------------------
1101      
1102      /** 
1103       * Forces an assertion error to occur.
1104       * @param {String} message (Optional) The message to display with the failure.
1105       * @method fail
1106       * @static
1107       */
1108      fail : function (message /*:String*/) /*:Void*/ {
1109          throw new YAHOO.util.AssertionError(this._formatMessage(message, "Test force-failed."));
1110      },       
1111      
1112      //-------------------------------------------------------------------------
1113      // Equality Assertion Methods
1114      //-------------------------------------------------------------------------    
1115      
1116      /**
1117       * Asserts that a value is equal to another. This uses the double equals sign
1118       * so type coercion may occur.
1119       * @param {Object} expected The expected value.
1120       * @param {Object} actual The actual value to test.
1121       * @param {String} message (Optional) The message to display if the assertion fails.
1122       * @method areEqual
1123       * @static
1124       */
1125      areEqual : function (expected /*:Object*/, actual /*:Object*/, message /*:String*/) /*:Void*/ {
1126          if (expected != actual) {
1127              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Values should be equal."), expected, actual);
1128          }
1129      },
1130      
1131      /**
1132       * Asserts that a value is not equal to another. This uses the double equals sign
1133       * so type coercion may occur.
1134       * @param {Object} unexpected The unexpected value.
1135       * @param {Object} actual The actual value to test.
1136       * @param {String} message (Optional) The message to display if the assertion fails.
1137       * @method areNotEqual
1138       * @static
1139       */
1140      areNotEqual : function (unexpected /*:Object*/, actual /*:Object*/, 
1141                           message /*:String*/) /*:Void*/ {
1142          if (unexpected == actual) {
1143              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Values should not be equal."), unexpected);
1144          }
1145      },
1146      
1147      /**
1148       * Asserts that a value is not the same as another. This uses the triple equals sign
1149       * so no type coercion may occur.
1150       * @param {Object} unexpected The unexpected value.
1151       * @param {Object} actual The actual value to test.
1152       * @param {String} message (Optional) The message to display if the assertion fails.
1153       * @method areNotSame
1154       * @static
1155       */
1156      areNotSame : function (unexpected /*:Object*/, actual /*:Object*/, message /*:String*/) /*:Void*/ {
1157          if (unexpected === actual) {
1158              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Values should not be the same."), unexpected);
1159          }
1160      },
1161  
1162      /**
1163       * Asserts that a value is the same as another. This uses the triple equals sign
1164       * so no type coercion may occur.
1165       * @param {Object} expected The expected value.
1166       * @param {Object} actual The actual value to test.
1167       * @param {String} message (Optional) The message to display if the assertion fails.
1168       * @method areSame
1169       * @static
1170       */
1171      areSame : function (expected /*:Object*/, actual /*:Object*/, message /*:String*/) /*:Void*/ {
1172          if (expected !== actual) {
1173              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Values should be the same."), expected, actual);
1174          }
1175      },    
1176      
1177      //-------------------------------------------------------------------------
1178      // Boolean Assertion Methods
1179      //-------------------------------------------------------------------------    
1180      
1181      /**
1182       * Asserts that a value is false. This uses the triple equals sign
1183       * so no type coercion may occur.
1184       * @param {Object} actual The actual value to test.
1185       * @param {String} message (Optional) The message to display if the assertion fails.
1186       * @method isFalse
1187       * @static
1188       */
1189      isFalse : function (actual /*:Boolean*/, message /*:String*/) {
1190          if (false !== actual) {
1191              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be false."), false, actual);
1192          }
1193      },
1194      
1195      /**
1196       * Asserts that a value is true. This uses the triple equals sign
1197       * so no type coercion may occur.
1198       * @param {Object} actual The actual value to test.
1199       * @param {String} message (Optional) The message to display if the assertion fails.
1200       * @method isTrue
1201       * @static
1202       */
1203      isTrue : function (actual /*:Boolean*/, message /*:String*/) /*:Void*/ {
1204          if (true !== actual) {
1205              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be true."), true, actual);
1206          }
1207  
1208      },
1209      
1210      //-------------------------------------------------------------------------
1211      // Special Value Assertion Methods
1212      //-------------------------------------------------------------------------    
1213      
1214      /**
1215       * Asserts that a value is not a number.
1216       * @param {Object} actual The value to test.
1217       * @param {String} message (Optional) The message to display if the assertion fails.
1218       * @method isNaN
1219       * @static
1220       */
1221      isNaN : function (actual /*:Object*/, message /*:String*/) /*:Void*/{
1222          if (!isNaN(actual)){
1223              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be NaN."), NaN, actual);
1224          }    
1225      },
1226      
1227      /**
1228       * Asserts that a value is not the special NaN value.
1229       * @param {Object} actual The value to test.
1230       * @param {String} message (Optional) The message to display if the assertion fails.
1231       * @method isNotNaN
1232       * @static
1233       */
1234      isNotNaN : function (actual /*:Object*/, message /*:String*/) /*:Void*/{
1235          if (isNaN(actual)){
1236              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Values should not be NaN."), NaN);
1237          }    
1238      },
1239      
1240      /**
1241       * Asserts that a value is not null. This uses the triple equals sign
1242       * so no type coercion may occur.
1243       * @param {Object} actual The actual value to test.
1244       * @param {String} message (Optional) The message to display if the assertion fails.
1245       * @method isNotNull
1246       * @static
1247       */
1248      isNotNull : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1249          if (YAHOO.lang.isNull(actual)) {
1250              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Values should not be null."), null);
1251          }
1252      },
1253  
1254      /**
1255       * Asserts that a value is not undefined. This uses the triple equals sign
1256       * so no type coercion may occur.
1257       * @param {Object} actual The actual value to test.
1258       * @param {String} message (Optional) The message to display if the assertion fails.
1259       * @method isNotUndefined
1260       * @static
1261       */
1262      isNotUndefined : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1263          if (YAHOO.lang.isUndefined(actual)) {
1264              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should not be undefined."), undefined);
1265          }
1266      },
1267  
1268      /**
1269       * Asserts that a value is null. This uses the triple equals sign
1270       * so no type coercion may occur.
1271       * @param {Object} actual The actual value to test.
1272       * @param {String} message (Optional) The message to display if the assertion fails.
1273       * @method isNull
1274       * @static
1275       */
1276      isNull : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1277          if (!YAHOO.lang.isNull(actual)) {
1278              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be null."), null, actual);
1279          }
1280      },
1281          
1282      /**
1283       * Asserts that a value is undefined. This uses the triple equals sign
1284       * so no type coercion may occur.
1285       * @param {Object} actual The actual value to test.
1286       * @param {String} message (Optional) The message to display if the assertion fails.
1287       * @method isUndefined
1288       * @static
1289       */
1290      isUndefined : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1291          if (!YAHOO.lang.isUndefined(actual)) {
1292              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be undefined."), undefined, actual);
1293          }
1294      },    
1295      
1296      //--------------------------------------------------------------------------
1297      // Instance Assertion Methods
1298      //--------------------------------------------------------------------------    
1299     
1300      /**
1301       * Asserts that a value is an array.
1302       * @param {Object} actual The value to test.
1303       * @param {String} message (Optional) The message to display if the assertion fails.
1304       * @method isArray
1305       * @static
1306       */
1307      isArray : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1308          if (!YAHOO.lang.isArray(actual)){
1309              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be an array."), actual);
1310          }    
1311      },
1312     
1313      /**
1314       * Asserts that a value is a Boolean.
1315       * @param {Object} actual The value to test.
1316       * @param {String} message (Optional) The message to display if the assertion fails.
1317       * @method isBoolean
1318       * @static
1319       */
1320      isBoolean : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1321          if (!YAHOO.lang.isBoolean(actual)){
1322              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be a Boolean."), actual);
1323          }    
1324      },
1325     
1326      /**
1327       * Asserts that a value is a function.
1328       * @param {Object} actual The value to test.
1329       * @param {String} message (Optional) The message to display if the assertion fails.
1330       * @method isFunction
1331       * @static
1332       */
1333      isFunction : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1334          if (!YAHOO.lang.isFunction(actual)){
1335              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be a function."), actual);
1336          }    
1337      },
1338     
1339      /**
1340       * Asserts that a value is an instance of a particular object. This may return
1341       * incorrect results when comparing objects from one frame to constructors in
1342       * another frame. For best results, don't use in a cross-frame manner.
1343       * @param {Function} expected The function that the object should be an instance of.
1344       * @param {Object} actual The object to test.
1345       * @param {String} message (Optional) The message to display if the assertion fails.
1346       * @method isInstanceOf
1347       * @static
1348       */
1349      isInstanceOf : function (expected /*:Function*/, actual /*:Object*/, message /*:String*/) /*:Void*/ {
1350          if (!(actual instanceof expected)){
1351              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value isn't an instance of expected type."), expected, actual);
1352          }
1353      },
1354      
1355      /**
1356       * Asserts that a value is a number.
1357       * @param {Object} actual The value to test.
1358       * @param {String} message (Optional) The message to display if the assertion fails.
1359       * @method isNumber
1360       * @static
1361       */
1362      isNumber : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1363          if (!YAHOO.lang.isNumber(actual)){
1364              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be a number."), actual);
1365          }    
1366      },    
1367      
1368      /**
1369       * Asserts that a value is an object.
1370       * @param {Object} actual The value to test.
1371       * @param {String} message (Optional) The message to display if the assertion fails.
1372       * @method isObject
1373       * @static
1374       */
1375      isObject : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1376          if (!YAHOO.lang.isObject(actual)){
1377              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be an object."), actual);
1378          }
1379      },
1380      
1381      /**
1382       * Asserts that a value is a string.
1383       * @param {Object} actual The value to test.
1384       * @param {String} message (Optional) The message to display if the assertion fails.
1385       * @method isString
1386       * @static
1387       */
1388      isString : function (actual /*:Object*/, message /*:String*/) /*:Void*/ {
1389          if (!YAHOO.lang.isString(actual)){
1390              throw new YAHOO.util.UnexpectedValue(this._formatMessage(message, "Value should be a string."), actual);
1391          }
1392      },
1393      
1394      /**
1395       * Asserts that a value is of a particular type. 
1396       * @param {String} expectedType The expected type of the variable.
1397       * @param {Object} actualValue The actual value to test.
1398       * @param {String} message (Optional) The message to display if the assertion fails.
1399       * @method isTypeOf
1400       * @static
1401       */
1402      isTypeOf : function (expected /*:String*/, actual /*:Object*/, message /*:String*/) /*:Void*/{
1403          if (typeof actual != expected){
1404              throw new YAHOO.util.ComparisonFailure(this._formatMessage(message, "Value should be of type " + expected + "."), expected, typeof actual);
1405          }
1406      }
1407  };
1408  
1409  //-----------------------------------------------------------------------------
1410  // Assertion errors
1411  //-----------------------------------------------------------------------------
1412  
1413  /**
1414   * AssertionError is thrown whenever an assertion fails. It provides methods
1415   * to more easily get at error information and also provides a base class
1416   * from which more specific assertion errors can be derived.
1417   *
1418   * @param {String} message The message to display when the error occurs.
1419   * @namespace YAHOO.util
1420   * @class AssertionError
1421   * @extends Error
1422   * @constructor
1423   */ 
1424  YAHOO.util.AssertionError = function (message /*:String*/){
1425  
1426      //call superclass
1427      //arguments.callee.superclass.constructor.call(this, message);
1428      
1429      /*
1430       * Error message. Must be duplicated to ensure browser receives it.
1431       * @type String
1432       * @property message
1433       */
1434      this.message /*:String*/ = message;
1435      
1436      /**
1437       * The name of the error that occurred.
1438       * @type String
1439       * @property name
1440       */
1441      this.name /*:String*/ = "AssertionError";
1442  };
1443  
1444  //inherit methods
1445  YAHOO.lang.extend(YAHOO.util.AssertionError, Object, {
1446  
1447      /**
1448       * Returns a fully formatted error for an assertion failure. This should
1449       * be overridden by all subclasses to provide specific information.
1450       * @method getMessage
1451       * @return {String} A string describing the error.
1452       */
1453      getMessage : function () /*:String*/ {
1454          return this.message;
1455      },
1456      
1457      /**
1458       * Returns a string representation of the error.
1459       * @method toString
1460       * @return {String} A string representation of the error.
1461       */
1462      toString : function () /*:String*/ {
1463          return this.name + ": " + this.getMessage();
1464      }
1465      
1466  });
1467  
1468  /**
1469   * ComparisonFailure is subclass of AssertionError that is thrown whenever
1470   * a comparison between two values fails. It provides mechanisms to retrieve
1471   * both the expected and actual value.
1472   *
1473   * @param {String} message The message to display when the error occurs.
1474   * @param {Object} expected The expected value.
1475   * @param {Object} actual The actual value that caused the assertion to fail.
1476   * @namespace YAHOO.util
1477   * @extends YAHOO.util.AssertionError
1478   * @class ComparisonFailure
1479   * @constructor
1480   */ 
1481  YAHOO.util.ComparisonFailure = function (message /*:String*/, expected /*:Object*/, actual /*:Object*/){
1482  
1483      //call superclass
1484      YAHOO.util.AssertionError.call(this, message);
1485      
1486      /**
1487       * The expected value.
1488       * @type Object
1489       * @property expected
1490       */
1491      this.expected /*:Object*/ = expected;
1492      
1493      /**
1494       * The actual value.
1495       * @type Object
1496       * @property actual
1497       */
1498      this.actual /*:Object*/ = actual;
1499      
1500      /**
1501       * The name of the error that occurred.
1502       * @type String
1503       * @property name
1504       */
1505      this.name /*:String*/ = "ComparisonFailure";
1506      
1507  };
1508  
1509  //inherit methods
1510  YAHOO.lang.extend(YAHOO.util.ComparisonFailure, YAHOO.util.AssertionError, {
1511  
1512      /**
1513       * Returns a fully formatted error for an assertion failure. This message
1514       * provides information about the expected and actual values.
1515       * @method toString
1516       * @return {String} A string describing the error.
1517       */
1518      getMessage : function () /*:String*/ {
1519          return this.message + "\nExpected: " + this.expected + " (" + (typeof this.expected) + ")"  +
1520              "\nActual:" + this.actual + " (" + (typeof this.actual) + ")";
1521      }
1522  
1523  });
1524  
1525  /**
1526   * UnexpectedValue is subclass of AssertionError that is thrown whenever
1527   * a value was unexpected in its scope. This typically means that a test
1528   * was performed to determine that a value was *not* equal to a certain
1529   * value.
1530   *
1531   * @param {String} message The message to display when the error occurs.
1532   * @param {Object} unexpected The unexpected value.
1533   * @namespace YAHOO.util
1534   * @extends YAHOO.util.AssertionError
1535   * @class UnexpectedValue
1536   * @constructor
1537   */ 
1538  YAHOO.util.UnexpectedValue = function (message /*:String*/, unexpected /*:Object*/){
1539  
1540      //call superclass
1541      YAHOO.util.AssertionError.call(this, message);
1542      
1543      /**
1544       * The unexpected value.
1545       * @type Object
1546       * @property unexpected
1547       */
1548      this.unexpected /*:Object*/ = unexpected;
1549      
1550      /**
1551       * The name of the error that occurred.
1552       * @type String
1553       * @property name
1554       */
1555      this.name /*:String*/ = "UnexpectedValue";
1556      
1557  };
1558  
1559  //inherit methods
1560  YAHOO.lang.extend(YAHOO.util.UnexpectedValue, YAHOO.util.AssertionError, {
1561  
1562      /**
1563       * Returns a fully formatted error for an assertion failure. The message
1564       * contains information about the unexpected value that was encountered.
1565       * @method getMessage
1566       * @return {String} A string describing the error.
1567       */
1568      getMessage : function () /*:String*/ {
1569          return this.message + "\nUnexpected: " + this.unexpected + " (" + (typeof this.unexpected) + ") ";
1570      }
1571  
1572  });
1573  
1574  /**
1575   * ShouldFail is subclass of AssertionError that is thrown whenever
1576   * a test was expected to fail but did not.
1577   *
1578   * @param {String} message The message to display when the error occurs.
1579   * @namespace YAHOO.util
1580   * @extends YAHOO.util.AssertionError
1581   * @class ShouldFail
1582   * @constructor
1583   */  
1584  YAHOO.util.ShouldFail = function (message /*:String*/){
1585  
1586      //call superclass
1587      YAHOO.util.AssertionError.call(this, message || "This test should fail but didn't.");
1588      
1589      /**
1590       * The name of the error that occurred.
1591       * @type String
1592       * @property name
1593       */
1594      this.name /*:String*/ = "ShouldFail";
1595      
1596  };
1597  
1598  //inherit methods
1599  YAHOO.lang.extend(YAHOO.util.ShouldFail, YAHOO.util.AssertionError);
1600  
1601  /**
1602   * ShouldError is subclass of AssertionError that is thrown whenever
1603   * a test is expected to throw an error but doesn't.
1604   *
1605   * @param {String} message The message to display when the error occurs.
1606   * @namespace YAHOO.util
1607   * @extends YAHOO.util.AssertionError
1608   * @class ShouldError
1609   * @constructor
1610   */  
1611  YAHOO.util.ShouldError = function (message /*:String*/){
1612  
1613      //call superclass
1614      YAHOO.util.AssertionError.call(this, message || "This test should have thrown an error but didn't.");
1615      
1616      /**
1617       * The name of the error that occurred.
1618       * @type String
1619       * @property name
1620       */
1621      this.name /*:String*/ = "ShouldError";
1622      
1623  };
1624  
1625  //inherit methods
1626  YAHOO.lang.extend(YAHOO.util.ShouldError, YAHOO.util.AssertionError);
1627  
1628  /**
1629   * UnexpectedError is subclass of AssertionError that is thrown whenever
1630   * an error occurs within the course of a test and the test was not expected
1631   * to throw an error.
1632   *
1633   * @param {Error} cause The unexpected error that caused this error to be 
1634   *                      thrown.
1635   * @namespace YAHOO.util
1636   * @extends YAHOO.util.AssertionError
1637   * @class UnexpectedError
1638   * @constructor
1639   */  
1640  YAHOO.util.UnexpectedError = function (cause /*:Object*/){
1641  
1642      //call superclass
1643      YAHOO.util.AssertionError.call(this, "Unexpected error: " + cause.message);
1644      
1645      /**
1646       * The unexpected error that occurred.
1647       * @type Error
1648       * @property cause
1649       */
1650      this.cause /*:Error*/ = cause;
1651      
1652      /**
1653       * The name of the error that occurred.
1654       * @type String
1655       * @property name
1656       */
1657      this.name /*:String*/ = "UnexpectedError";
1658      
1659      /**
1660       * Stack information for the error (if provided).
1661       * @type String
1662       * @property stack
1663       */
1664      this.stack /*:String*/ = cause.stack;
1665      
1666  };
1667  
1668  //inherit methods
1669  YAHOO.lang.extend(YAHOO.util.UnexpectedError, YAHOO.util.AssertionError);
1670  //-----------------------------------------------------------------------------
1671  // ArrayAssert object
1672  //-----------------------------------------------------------------------------
1673  
1674  /**
1675   * The ArrayAssert object provides functions to test JavaScript array objects
1676   * for a variety of cases.
1677   *
1678   * @namespace YAHOO.util
1679   * @class ArrayAssert
1680   * @static
1681   */
1682   
1683  YAHOO.util.ArrayAssert = {
1684  
1685      /**
1686       * Asserts that a value is present in an array. This uses the triple equals 
1687       * sign so no type coercion may occur.
1688       * @param {Object} needle The value that is expected in the array.
1689       * @param {Array} haystack An array of values.
1690       * @param {String} message (Optional) The message to display if the assertion fails.
1691       * @method contains
1692       * @static
1693       */
1694      contains : function (needle /*:Object*/, haystack /*:Array*/, 
1695                             message /*:String*/) /*:Void*/ {
1696          
1697          var found /*:Boolean*/ = false;
1698          var Assert = YAHOO.util.Assert;
1699          
1700          //begin checking values
1701          for (var i=0; i < haystack.length && !found; i++){
1702              if (haystack[i] === needle) {
1703                  found = true;
1704              }
1705          }
1706          
1707          if (!found){
1708              Assert.fail(Assert._formatMessage(message, "Value " + needle + " (" + (typeof needle) + ") not found in array [" + haystack + "]."));
1709          }
1710      },
1711  
1712      /**
1713       * Asserts that a set of values are present in an array. This uses the triple equals 
1714       * sign so no type coercion may occur. For this assertion to pass, all values must
1715       * be found.
1716       * @param {Object[]} needles An array of values that are expected in the array.
1717       * @param {Array} haystack An array of values to check.
1718       * @param {String} message (Optional) The message to display if the assertion fails.
1719       * @method containsItems
1720       * @static
1721       */
1722      containsItems : function (needles /*:Object[]*/, haystack /*:Array*/, 
1723                             message /*:String*/) /*:Void*/ {
1724  
1725          //begin checking values
1726          for (var i=0; i < needles.length; i++){
1727              this.contains(needles[i], haystack, message);
1728          }
1729      },
1730  
1731      /**
1732       * Asserts that a value matching some condition is present in an array. This uses
1733       * a function to determine a match.
1734       * @param {Function} matcher A function that returns true if the items matches or false if not.
1735       * @param {Array} haystack An array of values.
1736       * @param {String} message (Optional) The message to display if the assertion fails.
1737       * @method containsMatch
1738       * @static
1739       */
1740      containsMatch : function (matcher /*:Function*/, haystack /*:Array*/, 
1741                             message /*:String*/) /*:Void*/ {
1742          
1743          //check for valid matcher
1744          if (typeof matcher != "function"){
1745              throw new TypeError("ArrayAssert.containsMatch(): First argument must be a function.");
1746          }
1747          
1748          var found /*:Boolean*/ = false;
1749          var Assert = YAHOO.util.Assert;
1750          
1751          //begin checking values
1752          for (var i=0; i < haystack.length && !found; i++){
1753              if (matcher(haystack[i])) {
1754                  found = true;
1755              }
1756          }
1757          
1758          if (!found){
1759              Assert.fail(Assert._formatMessage(message, "No match found in array [" + haystack + "]."));
1760          }
1761      },
1762  
1763      /**
1764       * Asserts that a value is not present in an array. This uses the triple equals 
1765       * sign so no type coercion may occur.
1766       * @param {Object} needle The value that is expected in the array.
1767       * @param {Array} haystack An array of values.
1768       * @param {String} message (Optional) The message to display if the assertion fails.
1769       * @method doesNotContain
1770       * @static
1771       */
1772      doesNotContain : function (needle /*:Object*/, haystack /*:Array*/, 
1773                             message /*:String*/) /*:Void*/ {
1774          
1775          var found /*:Boolean*/ = false;
1776          var Assert = YAHOO.util.Assert;
1777          
1778          //begin checking values
1779          for (var i=0; i < haystack.length && !found; i++){
1780              if (haystack[i] === needle) {
1781                  found = true;
1782              }
1783          }
1784          
1785          if (found){
1786              Assert.fail(Assert._formatMessage(message, "Value found in array [" + haystack + "]."));
1787          }
1788      },
1789  
1790      /**
1791       * Asserts that a set of values are not present in an array. This uses the triple equals 
1792       * sign so no type coercion may occur. For this assertion to pass, all values must
1793       * not be found.
1794       * @param {Object[]} needles An array of values that are not expected in the array.
1795       * @param {Array} haystack An array of values to check.
1796       * @param {String} message (Optional) The message to display if the assertion fails.
1797       * @method doesNotContainItems
1798       * @static
1799       */
1800      doesNotContainItems : function (needles /*:Object[]*/, haystack /*:Array*/, 
1801                             message /*:String*/) /*:Void*/ {
1802  
1803          for (var i=0; i < needles.length; i++){
1804              this.doesNotContain(needles[i], haystack, message);
1805          }
1806  
1807      },
1808          
1809      /**
1810       * Asserts that no values matching a condition are present in an array. This uses
1811       * a function to determine a match.
1812       * @param {Function} matcher A function that returns true if the items matches or false if not.
1813       * @param {Array} haystack An array of values.
1814       * @param {String} message (Optional) The message to display if the assertion fails.
1815       * @method doesNotContainMatch
1816       * @static
1817       */
1818      doesNotContainMatch : function (matcher /*:Function*/, haystack /*:Array*/, 
1819                             message /*:String*/) /*:Void*/ {
1820          
1821          //check for valid matcher
1822          if (typeof matcher != "function"){
1823              throw new TypeError("ArrayAssert.doesNotContainMatch(): First argument must be a function.");
1824          }
1825  
1826          var found /*:Boolean*/ = false;
1827          var Assert = YAHOO.util.Assert;
1828          
1829          //begin checking values
1830          for (var i=0; i < haystack.length && !found; i++){
1831              if (matcher(haystack[i])) {
1832                  found = true;
1833              }
1834          }
1835          
1836          if (found){
1837              Assert.fail(Assert._formatMessage(message, "Value found in array [" + haystack + "]."));
1838          }
1839      },
1840          
1841      /**
1842       * Asserts that the given value is contained in an array at the specified index.
1843       * This uses the triple equals sign so no type coercion will occur.
1844       * @param {Object} needle The value to look for.
1845       * @param {Array} haystack The array to search in.
1846       * @param {int} index The index at which the value should exist.
1847       * @param {String} message (Optional) The message to display if the assertion fails.
1848       * @method indexOf
1849       * @static
1850       */
1851      indexOf : function (needle /*:Object*/, haystack /*:Array*/, index /*:int*/, message /*:String*/) /*:Void*/ {
1852      
1853          //try to find the value in the array
1854          for (var i=0; i < haystack.length; i++){
1855              if (haystack[i] === needle){
1856                  YAHOO.util.Assert.areEqual(index, i, message || "Value exists at index " + i + " but should be at index " + index + ".");
1857                  return;
1858              }
1859          }
1860          
1861          var Assert = YAHOO.util.Assert;
1862          
1863          //if it makes it here, it wasn't found at all
1864          Assert.fail(Assert._formatMessage(message, "Value doesn't exist in array [" + haystack + "]."));
1865      },
1866          
1867      /**
1868       * Asserts that the values in an array are equal, and in the same position,
1869       * as values in another array. This uses the double equals sign
1870       * so type coercion may occur. Note that the array objects themselves
1871       * need not be the same for this test to pass.
1872       * @param {Array} expected An array of the expected values.
1873       * @param {Array} actual Any array of the actual values.
1874       * @param {String} message (Optional) The message to display if the assertion fails.
1875       * @method itemsAreEqual
1876       * @static
1877       */
1878      itemsAreEqual : function (expected /*:Array*/, actual /*:Array*/, 
1879                             message /*:String*/) /*:Void*/ {
1880          
1881          //one may be longer than the other, so get the maximum length
1882          var len /*:int*/ = Math.max(expected.length, actual.length || 0);
1883          var Assert = YAHOO.util.Assert;
1884         
1885          //begin checking values
1886          for (var i=0; i < len; i++){
1887              Assert.areEqual(expected[i], actual[i], 
1888                  Assert._formatMessage(message, "Values in position " + i + " are not equal."));
1889          }
1890      },
1891      
1892      /**
1893       * Asserts that the values in an array are equivalent, and in the same position,
1894       * as values in another array. This uses a function to determine if the values
1895       * are equivalent. Note that the array objects themselves
1896       * need not be the same for this test to pass.
1897       * @param {Array} expected An array of the expected values.
1898       * @param {Array} actual Any array of the actual values.
1899       * @param {Function} comparator A function that returns true if the values are equivalent
1900       *      or false if not.
1901       * @param {String} message (Optional) The message to display if the assertion fails.
1902       * @return {Void}
1903       * @method itemsAreEquivalent
1904       * @static
1905       */
1906      itemsAreEquivalent : function (expected /*:Array*/, actual /*:Array*/, 
1907                             comparator /*:Function*/, message /*:String*/) /*:Void*/ {
1908          
1909          //make sure the comparator is valid
1910          if (typeof comparator != "function"){
1911              throw new TypeError("ArrayAssert.itemsAreEquivalent(): Third argument must be a function.");
1912          }
1913          
1914          //one may be longer than the other, so get the maximum length
1915          var len /*:int*/ = Math.max(expected.length, actual.length || 0);
1916          
1917          //begin checking values
1918          for (var i=0; i < len; i++){
1919              if (!comparator(expected[i], actual[i])){
1920                  throw new YAHOO.util.ComparisonFailure(YAHOO.util.Assert._formatMessage(message, "Values in position " + i + " are not equivalent."), expected[i], actual[i]);
1921              }
1922          }
1923      },
1924      
1925      /**
1926       * Asserts that an array is empty.
1927       * @param {Array} actual The array to test.
1928       * @param {String} message (Optional) The message to display if the assertion fails.
1929       * @method isEmpty
1930       * @static
1931       */
1932      isEmpty : function (actual /*:Array*/, message /*:String*/) /*:Void*/ {        
1933          if (actual.length > 0){
1934              var Assert = YAHOO.util.Assert;
1935              Assert.fail(Assert._formatMessage(message, "Array should be empty."));
1936          }
1937      },    
1938      
1939      /**
1940       * Asserts that an array is not empty.
1941       * @param {Array} actual The array to test.
1942       * @param {String} message (Optional) The message to display if the assertion fails.
1943       * @method isNotEmpty
1944       * @static
1945       */
1946      isNotEmpty : function (actual /*:Array*/, message /*:String*/) /*:Void*/ {        
1947          if (actual.length === 0){
1948              var Assert = YAHOO.util.Assert;
1949              Assert.fail(Assert._formatMessage(message, "Array should not be empty."));
1950          }
1951      },    
1952      
1953      /**
1954       * Asserts that the values in an array are the same, and in the same position,
1955       * as values in another array. This uses the triple equals sign
1956       * so no type coercion will occur. Note that the array objects themselves
1957       * need not be the same for this test to pass.
1958       * @param {Array} expected An array of the expected values.
1959       * @param {Array} actual Any array of the actual values.
1960       * @param {String} message (Optional) The message to display if the assertion fails.
1961       * @method itemsAreSame
1962       * @static
1963       */
1964      itemsAreSame : function (expected /*:Array*/, actual /*:Array*/, 
1965                            message /*:String*/) /*:Void*/ {
1966          
1967          //one may be longer than the other, so get the maximum length
1968          var len /*:int*/ = Math.max(expected.length, actual.length || 0);
1969          var Assert = YAHOO.util.Assert;
1970          
1971          //begin checking values
1972          for (var i=0; i < len; i++){
1973              Assert.areSame(expected[i], actual[i], 
1974                  Assert._formatMessage(message, "Values in position " + i + " are not the same."));
1975          }
1976      },
1977      
1978      /**
1979       * Asserts that the given value is contained in an array at the specified index,
1980       * starting from the back of the array.
1981       * This uses the triple equals sign so no type coercion will occur.
1982       * @param {Object} needle The value to look for.
1983       * @param {Array} haystack The array to search in.
1984       * @param {int} index The index at which the value should exist.
1985       * @param {String} message (Optional) The message to display if the assertion fails.
1986       * @method lastIndexOf
1987       * @static
1988       */
1989      lastIndexOf : function (needle /*:Object*/, haystack /*:Array*/, index /*:int*/, message /*:String*/) /*:Void*/ {
1990      
1991          var Assert = YAHOO.util.Assert;
1992      
1993          //try to find the value in the array
1994          for (var i=haystack.length; i >= 0; i--){
1995              if (haystack[i] === needle){
1996                  Assert.areEqual(index, i, Assert._formatMessage(message, "Value exists at index " + i + " but should be at index " + index + "."));
1997                  return;
1998              }
1999          }
2000          
2001          //if it makes it here, it wasn't found at all
2002          Assert.fail(Assert._formatMessage(message, "Value doesn't exist in array."));        
2003      }
2004      
2005  };
2006  YAHOO.namespace("util");
2007  
2008  
2009  //-----------------------------------------------------------------------------
2010  // ObjectAssert object
2011  //-----------------------------------------------------------------------------
2012  
2013  /**
2014   * The ObjectAssert object provides functions to test JavaScript objects
2015   * for a variety of cases.
2016   *
2017   * @namespace YAHOO.util
2018   * @class ObjectAssert
2019   * @static
2020   */
2021  YAHOO.util.ObjectAssert = {
2022          
2023      /**
2024       * Asserts that all properties in the object exist in another object.
2025       * @param {Object} expected An object with the expected properties.
2026       * @param {Object} actual An object with the actual properties.
2027       * @param {String} message (Optional) The message to display if the assertion fails.
2028       * @method propertiesAreEqual
2029       * @static
2030       */
2031      propertiesAreEqual : function (expected /*:Object*/, actual /*:Object*/, 
2032                             message /*:String*/) /*:Void*/ {
2033          
2034          var Assert = YAHOO.util.Assert;
2035          
2036          //get all properties in the object
2037          var properties /*:Array*/ = [];        
2038          for (var property in expected){
2039              properties.push(property);
2040          }
2041          
2042          //see if the properties are in the expected object
2043          for (var i=0; i < properties.length; i++){
2044              Assert.isNotUndefined(actual[properties[i]], 
2045                  Assert._formatMessage(message, "Property '" + properties[i] + "' expected."));
2046          }
2047  
2048      },
2049      
2050      /**
2051       * Asserts that an object has a property with the given name.
2052       * @param {String} propertyName The name of the property to test.
2053       * @param {Object} object The object to search.
2054       * @param {String} message (Optional) The message to display if the assertion fails.
2055       * @method hasProperty
2056       * @static
2057       */    
2058      hasProperty : function (propertyName /*:String*/, object /*:Object*/, message /*:String*/) /*:Void*/ {
2059          if (!(propertyName in object)){
2060              var Assert = YAHOO.util.Assert;
2061              Assert.fail(Assert._formatMessage(message, "Property '" + propertyName + "' not found on object."));
2062          }    
2063      },
2064      
2065      /**
2066       * Asserts that a property with the given name exists on an object instance (not on its prototype).
2067       * @param {String} propertyName The name of the property to test.
2068       * @param {Object} object The object to search.
2069       * @param {String} message (Optional) The message to display if the assertion fails.
2070       * @method hasProperty
2071       * @static
2072       */    
2073      hasOwnProperty : function (propertyName /*:String*/, object /*:Object*/, message /*:String*/) /*:Void*/ {
2074          if (!YAHOO.lang.hasOwnProperty(object, propertyName)){
2075              var Assert = YAHOO.util.Assert;
2076              Assert.fail(Assert._formatMessage(message, "Property '" + propertyName + "' not found on object instance."));
2077          }     
2078      }
2079  };
2080  //-----------------------------------------------------------------------------
2081  // DateAssert object
2082  //-----------------------------------------------------------------------------
2083  
2084  /**
2085   * The DateAssert object provides functions to test JavaScript Date objects
2086   * for a variety of cases.
2087   *
2088   * @namespace YAHOO.util
2089   * @class DateAssert
2090   * @static
2091   */
2092   
2093  YAHOO.util.DateAssert = {
2094  
2095      /**
2096       * Asserts that a date's month, day, and year are equal to another date's.
2097       * @param {Date} expected The expected date.
2098       * @param {Date} actual The actual date to test.
2099       * @param {String} message (Optional) The message to display if the assertion fails.
2100       * @method datesAreEqual
2101       * @static
2102       */
2103      datesAreEqual : function (expected /*:Date*/, actual /*:Date*/, message /*:String*/){
2104          if (expected instanceof Date && actual instanceof Date){
2105              var Assert = YAHOO.util.Assert;
2106              Assert.areEqual(expected.getFullYear(), actual.getFullYear(), Assert._formatMessage(message, "Years should be equal."));
2107              Assert.areEqual(expected.getMonth(), actual.getMonth(), Assert._formatMessage(message, "Months should be equal."));
2108              Assert.areEqual(expected.getDate(), actual.getDate(), Assert._formatMessage(message, "Day of month should be equal."));
2109          } else {
2110              throw new TypeError("DateAssert.datesAreEqual(): Expected and actual values must be Date objects.");
2111          }
2112      },
2113  
2114      /**
2115       * Asserts that a date's hour, minutes, and seconds are equal to another date's.
2116       * @param {Date} expected The expected date.
2117       * @param {Date} actual The actual date to test.
2118       * @param {String} message (Optional) The message to display if the assertion fails.
2119       * @method timesAreEqual
2120       * @static
2121       */
2122      timesAreEqual : function (expected /*:Date*/, actual /*:Date*/, message /*:String*/){
2123          if (expected instanceof Date && actual instanceof Date){
2124              var Assert = YAHOO.util.Assert;
2125              Assert.areEqual(expected.getHours(), actual.getHours(), Assert._formatMessage(message, "Hours should be equal."));
2126              Assert.areEqual(expected.getMinutes(), actual.getMinutes(), Assert._formatMessage(message, "Minutes should be equal."));
2127              Assert.areEqual(expected.getSeconds(), actual.getSeconds(), Assert._formatMessage(message, "Seconds should be equal."));
2128          } else {
2129              throw new TypeError("DateAssert.timesAreEqual(): Expected and actual values must be Date objects.");
2130          }
2131      }
2132      
2133  };
2134  YAHOO.namespace("tool");
2135  
2136  //-----------------------------------------------------------------------------
2137  // TestManager object
2138  //-----------------------------------------------------------------------------
2139  
2140  /**
2141   * Runs pages containing test suite definitions.
2142   * @namespace YAHOO.tool
2143   * @class TestManager
2144   * @static
2145   */
2146  YAHOO.tool.TestManager = {
2147  
2148      /**
2149       * Constant for the testpagebegin custom event
2150       * @property TEST_PAGE_BEGIN_EVENT
2151       * @static
2152       * @type string
2153       * @final
2154       */
2155      TEST_PAGE_BEGIN_EVENT /*:String*/ : "testpagebegin",
2156  
2157      /**
2158       * Constant for the testpagecomplete custom event
2159       * @property TEST_PAGE_COMPLETE_EVENT
2160       * @static
2161       * @type string
2162       * @final
2163       */
2164      TEST_PAGE_COMPLETE_EVENT /*:String*/ : "testpagecomplete",
2165  
2166      /**
2167       * Constant for the testmanagerbegin custom event
2168       * @property TEST_MANAGER_BEGIN_EVENT
2169       * @static
2170       * @type string
2171       * @final
2172       */
2173      TEST_MANAGER_BEGIN_EVENT /*:String*/ : "testmanagerbegin",
2174  
2175      /**
2176       * Constant for the testmanagercomplete custom event
2177       * @property TEST_MANAGER_COMPLETE_EVENT
2178       * @static
2179       * @type string
2180       * @final
2181       */
2182      TEST_MANAGER_COMPLETE_EVENT /*:String*/ : "testmanagercomplete",
2183  
2184      //-------------------------------------------------------------------------
2185      // Private Properties
2186      //-------------------------------------------------------------------------
2187      
2188      
2189      /**
2190       * The URL of the page currently being executed.
2191       * @type String
2192       * @private
2193       * @property _curPage
2194       * @static
2195       */
2196      _curPage /*:String*/ : null,
2197      
2198      /**
2199       * The frame used to load and run tests.
2200       * @type Window
2201       * @private
2202       * @property _frame
2203       * @static
2204       */
2205      _frame /*:Window*/ : null,
2206      
2207      /**
2208       * The logger used to output results from the various tests.
2209       * @type YAHOO.tool.TestLogger
2210       * @private
2211       * @property _logger
2212       * @static
2213       */
2214      _logger : null,
2215      
2216      /**
2217       * The timeout ID for the next iteration through the tests.
2218       * @type int
2219       * @private
2220       * @property _timeoutId
2221       * @static
2222       */
2223      _timeoutId /*:int*/ : 0,
2224      
2225      /**
2226       * Array of pages to load.
2227       * @type String[]
2228       * @private
2229       * @property _pages
2230       * @static
2231       */
2232      _pages /*:String[]*/ : [],
2233      
2234      /**
2235       * Aggregated results
2236       * @type Object
2237       * @private
2238       * @property _results
2239       * @static
2240       */
2241      _results: null,
2242      
2243      //-------------------------------------------------------------------------
2244      // Private Methods
2245      //-------------------------------------------------------------------------
2246      
2247      /**
2248       * Handles TestRunner.COMPLETE_EVENT, storing the results and beginning
2249       * the loop again.
2250       * @param {Object} data Data about the event.
2251       * @return {Void}
2252       * @private
2253       * @static
2254       */
2255      _handleTestRunnerComplete : function (data /*:Object*/) /*:Void*/ {
2256  
2257          this.fireEvent(this.TEST_PAGE_COMPLETE_EVENT, {
2258                  page: this._curPage,
2259                  results: data.results
2260              });
2261      
2262          //save results
2263          //this._results[this.curPage] = data.results;
2264          
2265          //process 'em
2266          this._processResults(this._curPage, data.results);
2267          
2268          this._logger.clearTestRunner();
2269      
2270          //if there's more to do, set a timeout to begin again
2271          if (this._pages.length){
2272              this._timeoutId = setTimeout(function(){
2273                  YAHOO.tool.TestManager._run();
2274              }, 1000);
2275          } else {
2276              this.fireEvent(this.TEST_MANAGER_COMPLETE_EVENT, this._results);
2277          }
2278      },
2279      
2280      /**
2281       * Processes the results of a test page run, outputting log messages
2282       * for failed tests.
2283       * @return {Void}
2284       * @private
2285       * @static
2286       */
2287      _processResults : function (page /*:String*/, results /*:Object*/) /*:Void*/ {
2288  
2289          var r = this._results;
2290          
2291          r.passed += results.passed;
2292          r.failed += results.failed;
2293          r.ignored += results.ignored;
2294          r.total += results.total;
2295          r.duration += results.duration;
2296          
2297          if (results.failed){
2298              r.failedPages.push(page);
2299          } else {
2300              r.passedPages.push(page);
2301          }
2302          
2303          results.name = page;
2304          results.type = "page";
2305          
2306          r[page] = results;
2307      },
2308      
2309      /**
2310       * Loads the next test page into the iframe.
2311       * @return {Void}
2312       * @static
2313       * @private
2314       */
2315      _run : function () /*:Void*/ {
2316      
2317          //set the current page
2318          this._curPage = this._pages.shift();
2319  
2320          this.fireEvent(this.TEST_PAGE_BEGIN_EVENT, this._curPage);
2321          
2322          //load the frame - destroy history in case there are other iframes that
2323          //need testing
2324          this._frame.location.replace(this._curPage);
2325      
2326      },
2327          
2328      //-------------------------------------------------------------------------
2329      // Public Methods
2330      //-------------------------------------------------------------------------
2331      
2332      /**
2333       * Signals that a test page has been loaded. This should be called from
2334       * within the test page itself to notify the TestManager that it is ready.
2335       * @return {Void}
2336       * @static
2337       */
2338      load : function () /*:Void*/ {
2339          if (parent.YAHOO.tool.TestManager !== this){
2340              parent.YAHOO.tool.TestManager.load();
2341          } else {
2342              
2343              if (this._frame) {
2344                  //assign event handling
2345                  var TestRunner = this._frame.YAHOO.tool.TestRunner;
2346  
2347                  this._logger.setTestRunner(TestRunner);
2348                  TestRunner.subscribe(TestRunner.COMPLETE_EVENT, this._handleTestRunnerComplete, this, true);
2349                  
2350                  //run it
2351                  TestRunner.run();
2352              }
2353          }
2354      },
2355      
2356      /**
2357       * Sets the pages to be loaded.
2358       * @param {String[]} pages An array of URLs to load.
2359       * @return {Void}
2360       * @static
2361       */
2362      setPages : function (pages /*:String[]*/) /*:Void*/ {
2363          this._pages = pages;
2364      },
2365      
2366      /**
2367       * Begins the process of running the tests.
2368       * @return {Void}
2369       * @static
2370       */
2371      start : function () /*:Void*/ {
2372  
2373          if (!this._initialized) {
2374  
2375              /**
2376               * Fires when loading a test page
2377               * @event testpagebegin
2378               * @param curPage {string} the page being loaded
2379               * @static
2380               */
2381              this.createEvent(this.TEST_PAGE_BEGIN_EVENT);
2382  
2383              /**
2384               * Fires when a test page is complete
2385               * @event testpagecomplete
2386               * @param obj {page: string, results: object} the name of the
2387               * page that was loaded, and the test suite results
2388               * @static
2389               */
2390              this.createEvent(this.TEST_PAGE_COMPLETE_EVENT);
2391  
2392              /**
2393               * Fires when the test manager starts running all test pages
2394               * @event testmanagerbegin
2395               * @static
2396               */
2397              this.createEvent(this.TEST_MANAGER_BEGIN_EVENT);
2398  
2399              /**
2400               * Fires when the test manager finishes running all test pages.  External
2401               * test runners should subscribe to this event in order to get the
2402               * aggregated test results.
2403               * @event testmanagercomplete
2404               * @param obj { pages_passed: int, pages_failed: int, tests_passed: int
2405               *              tests_failed: int, passed: string[], failed: string[],
2406               *              page_results: {} }
2407               * @static
2408               */
2409              this.createEvent(this.TEST_MANAGER_COMPLETE_EVENT);
2410  
2411              //create iframe if not already available
2412              if (!this._frame){
2413                  var frame /*:HTMLElement*/ = document.createElement("iframe");
2414                  frame.style.visibility = "hidden";
2415                  frame.style.position = "absolute";
2416                  document.body.appendChild(frame);
2417                  this._frame = frame.contentWindow || frame.contentDocument.parentWindow;
2418              }
2419              
2420              //create test logger if not already available
2421              if (!this._logger){
2422                  this._logger = new YAHOO.tool.TestLogger();
2423              }
2424  
2425              this._initialized = true;
2426          }
2427  
2428  
2429          // reset the results cache
2430          this._results = {
2431          
2432              passed: 0,
2433              failed: 0,
2434              ignored: 0,
2435              total: 0,
2436              type: "report",
2437              name: "YUI Test Results",
2438              duration: 0,
2439              failedPages:[],
2440              passedPages:[]
2441              /*
2442              // number of pages that pass
2443              pages_passed: 0,
2444              // number of pages that fail
2445              pages_failed: 0,
2446              // total number of tests passed
2447              tests_passed: 0,
2448              // total number of tests failed
2449              tests_failed: 0,
2450              // array of pages that passed
2451              passed: [],
2452              // array of pages that failed
2453              failed: [],
2454              // map of full results for each page
2455              page_results: {}*/
2456          };
2457  
2458          this.fireEvent(this.TEST_MANAGER_BEGIN_EVENT, null);
2459          this._run();
2460      
2461      },
2462  
2463      /**
2464       * Stops the execution of tests.
2465       * @return {Void}
2466       * @static
2467       */
2468      stop : function () /*:Void*/ {
2469          clearTimeout(this._timeoutId);
2470      }
2471  
2472  };
2473  
2474  YAHOO.lang.augmentObject(YAHOO.tool.TestManager, YAHOO.util.EventProvider.prototype);
2475  
2476  YAHOO.namespace("tool");
2477  
2478  //-----------------------------------------------------------------------------
2479  // TestLogger object
2480  //-----------------------------------------------------------------------------
2481  
2482  /**
2483   * Displays test execution progress and results, providing filters based on
2484   * different key events.
2485   * @namespace YAHOO.tool
2486   * @class TestLogger
2487   * @constructor
2488   * @param {HTMLElement} element (Optional) The element to create the logger in.
2489   * @param {Object} config (Optional) Configuration options for the logger.
2490   */
2491  YAHOO.tool.TestLogger = function (element, config) {
2492      YAHOO.tool.TestLogger.superclass.constructor.call(this, element, config);
2493      this.init();
2494  };
2495  
2496  YAHOO.lang.extend(YAHOO.tool.TestLogger, YAHOO.widget.LogReader, {
2497  
2498      footerEnabled : true,
2499      newestOnTop : false,
2500  
2501      /**
2502       * Formats message string to HTML for output to console.
2503       * @private
2504       * @method formatMsg
2505       * @param oLogMsg {Object} Log message object.
2506       * @return {String} HTML-formatted message for output to console.
2507       */
2508      formatMsg : function(message /*:Object*/) {
2509      
2510          var category /*:String*/ = message.category;        
2511          var text /*:String*/ = this.html2Text(message.msg);
2512          
2513          return "<pre><p><span class=\"" + category + "\">" + category.toUpperCase() + "</span> " + text + "</p></pre>";
2514      
2515      },
2516      
2517      //-------------------------------------------------------------------------
2518      // Private Methods
2519      //-------------------------------------------------------------------------
2520      
2521      /*
2522       * Initializes the logger.
2523       * @private
2524       */
2525      init : function () {
2526      
2527          //attach to any available TestRunner
2528          if (YAHOO.tool.TestRunner){
2529              this.setTestRunner(YAHOO.tool.TestRunner);
2530          }
2531          
2532          //hide useless sources
2533          this.hideSource("global");
2534          this.hideSource("LogReader");
2535          
2536          //hide useless message categories
2537          this.hideCategory("warn");
2538          this.hideCategory("window");
2539          this.hideCategory("time");
2540          
2541          //reset the logger
2542          this.clearConsole();
2543      },
2544      
2545      /**
2546       * Clears the reference to the TestRunner from previous operations. This 
2547       * unsubscribes all events and removes the object reference.
2548       * @return {Void}
2549       * @static
2550       */
2551      clearTestRunner : function () /*:Void*/ {
2552          if (this._runner){
2553              this._runner.unsubscribeAll();
2554              this._runner = null;
2555          }
2556      },
2557      
2558      /**
2559       * Sets the source test runner that the logger should monitor.
2560       * @param {YAHOO.tool.TestRunner} testRunner The TestRunner to observe.
2561       * @return {Void}
2562       * @static
2563       */
2564      setTestRunner : function (testRunner /*:YAHOO.tool.TestRunner*/) /*:Void*/ {
2565      
2566          if (this._runner){
2567              this.clearTestRunner();
2568          }
2569          
2570          this._runner = testRunner;
2571          
2572          //setup event _handlers
2573          testRunner.subscribe(testRunner.TEST_PASS_EVENT, this._handleTestRunnerEvent, this, true);
2574          testRunner.subscribe(testRunner.TEST_FAIL_EVENT, this._handleTestRunnerEvent, this, true);
2575          testRunner.subscribe(testRunner.TEST_IGNORE_EVENT, this._handleTestRunnerEvent, this, true);
2576          testRunner.subscribe(testRunner.BEGIN_EVENT, this._handleTestRunnerEvent, this, true);
2577          testRunner.subscribe(testRunner.COMPLETE_EVENT, this._handleTestRunnerEvent, this, true);
2578          testRunner.subscribe(testRunner.TEST_SUITE_BEGIN_EVENT, this._handleTestRunnerEvent, this, true);
2579          testRunner.subscribe(testRunner.TEST_SUITE_COMPLETE_EVENT, this._handleTestRunnerEvent, this, true);
2580          testRunner.subscribe(testRunner.TEST_CASE_BEGIN_EVENT, this._handleTestRunnerEvent, this, true);
2581          testRunner.subscribe(testRunner.TEST_CASE_COMPLETE_EVENT, this._handleTestRunnerEvent, this, true);    
2582      },
2583      
2584      //-------------------------------------------------------------------------
2585      // Event Handlers
2586      //-------------------------------------------------------------------------
2587      
2588      /**
2589       * Handles all TestRunner events, outputting appropriate data into the console.
2590       * @param {Object} data The event data object.
2591       * @return {Void}
2592       * @private
2593       */
2594      _handleTestRunnerEvent : function (data /*:Object*/) /*:Void*/ {
2595      
2596          //shortcut variables
2597          var TestRunner /*:Object*/ = YAHOO.tool.TestRunner;
2598      
2599          //data variables
2600          var message /*:String*/ = "";
2601          var messageType /*:String*/ = "";
2602          
2603          switch(data.type){
2604              case TestRunner.BEGIN_EVENT:
2605                  message = "Testing began at " + (new Date()).toString() + ".";
2606                  messageType = "info";
2607                  break;
2608                  
2609              case TestRunner.COMPLETE_EVENT:
2610                  message = "Testing completed at " + (new Date()).toString() + ".\nPassed:" + 
2611                      data.results.passed + " Failed:" + data.results.failed + " Total:" + data.results.total;
2612                  messageType = "info";
2613                  break;
2614                  
2615              case TestRunner.TEST_FAIL_EVENT:
2616                  message = data.testName + ": " + data.error.getMessage();
2617                  messageType = "fail";
2618                  break;
2619                  
2620              case TestRunner.TEST_IGNORE_EVENT:
2621                  message = data.testName + ": ignored.";
2622                  messageType = "ignore";
2623                  break;
2624                  
2625              case TestRunner.TEST_PASS_EVENT:
2626                  message = data.testName + ": passed.";
2627                  messageType = "pass";
2628                  break;
2629                  
2630              case TestRunner.TEST_SUITE_BEGIN_EVENT:
2631                  message = "Test suite \"" + data.testSuite.name + "\" started.";
2632                  messageType = "info";
2633                  break;
2634                  
2635              case TestRunner.TEST_SUITE_COMPLETE_EVENT:
2636                  message = "Test suite \"" + data.testSuite.name + "\" completed.\nPassed:" + 
2637                      data.results.passed + " Failed:" + data.results.failed + " Total:" + data.results.total;
2638                  messageType = "info";
2639                  break;
2640                  
2641              case TestRunner.TEST_CASE_BEGIN_EVENT:
2642                  message = "Test case \"" + data.testCase.name + "\" started.";
2643                  messageType = "info";
2644                  break;
2645                  
2646              case TestRunner.TEST_CASE_COMPLETE_EVENT:
2647                  message = "Test case \"" + data.testCase.name + "\" completed.\nPassed:" + 
2648                      data.results.passed + " Failed:" + data.results.failed + " Total:" + data.results.total;
2649                  messageType = "info";
2650                  break;
2651              default:
2652                  message = "Unexpected event " + data.type;
2653                  message = "info";
2654          }
2655      
2656          YAHOO.log(message, messageType, "TestRunner");    
2657      }
2658      
2659  });
2660  YAHOO.namespace("tool.TestFormat");
2661  
2662  (function(){
2663  
2664      /**
2665       * Returns test results formatted as a JSON string. Requires JSON utility.
2666       * @param {Object} result The results object created by TestRunner.
2667       * @return {String} An XML-formatted string of results.
2668       * @namespace YAHOO.tool.TestFormat
2669       * @method JSON
2670       * @static
2671       */
2672      YAHOO.tool.TestFormat.JSON = function(results) {
2673          return YAHOO.lang.JSON.stringify(results);
2674      };
2675  
2676      /* (intentionally not documented)
2677       * Simple escape function for XML attribute values.
2678       * @param {String} text The text to escape.
2679       * @return {String} The escaped text.
2680       */
2681      function xmlEscape(text){
2682          return text.replace(/["'<>&]/g, function(c){
2683              switch(c){
2684                  case "<":   return "&lt;";
2685                  case ">":   return "&gt;";
2686                  case "\"":  return "&quot;";
2687                  case "'":   return "&apos;";
2688                  case "&":   return "&amp;";
2689              }
2690          });
2691      } 
2692  
2693      /**
2694       * Returns test results formatted as an XML string.
2695       * @param {Object} result The results object created by TestRunner.
2696       * @return {String} An XML-formatted string of results.
2697       * @namespace YAHOO.tool.TestFormat
2698       * @method XML
2699       * @static
2700       */
2701      YAHOO.tool.TestFormat.XML = function(results) {
2702  
2703          function serializeToXML(results){
2704              var l   = YAHOO.lang,
2705                  xml = "<" + results.type + " name=\"" + xmlEscape(results.name) + "\"";
2706              
2707              if (l.isNumber(results.duration)){
2708                  xml += " duration=\"" + results.duration + "\"";
2709              }
2710              
2711              if (results.type == "test"){
2712                  xml += " result=\"" + results.result + "\" message=\"" + xmlEscape(results.message) + "\">";
2713              } else {
2714                  xml += " passed=\"" + results.passed + "\" failed=\"" + results.failed + "\" ignored=\"" + results.ignored + "\" total=\"" + results.total + "\">";
2715                  for (var prop in results) {
2716                      if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2717                          xml += serializeToXML(results[prop]);
2718                      }
2719                  }        
2720              }
2721  
2722              xml += "</" + results.type + ">";
2723              
2724              return xml;    
2725          }
2726  
2727          return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToXML(results);
2728  
2729      };
2730  
2731  
2732      /**
2733       * Returns test results formatted in JUnit XML format.
2734       * @param {Object} result The results object created by TestRunner.
2735       * @return {String} An XML-formatted string of results.
2736       * @namespace YAHOO.tool.TestFormat
2737       * @method JUnitXML
2738       * @static
2739       */
2740      YAHOO.tool.TestFormat.JUnitXML = function(results) {
2741  
2742  
2743          function serializeToJUnitXML(results){
2744              var l   = YAHOO.lang,
2745                  xml = "",
2746                  prop;
2747                  
2748              switch (results.type){
2749                  //equivalent to testcase in JUnit
2750                  case "test":
2751                      if (results.result != "ignore"){
2752                          xml = "<testcase name=\"" + xmlEscape(results.name) + "\">";
2753                          if (results.result == "fail"){
2754                              xml += "<failure message=\"" + xmlEscape(results.message) + "\"><![CDATA[" + results.message + "]]></failure>";
2755                          }
2756                          xml+= "</testcase>";
2757                      }
2758                      break;
2759                      
2760                  //equivalent to testsuite in JUnit
2761                  case "testcase":
2762                  
2763                      xml = "<testsuite name=\"" + xmlEscape(results.name) + "\" tests=\"" + results.total + "\" failures=\"" + results.failed + "\">";
2764                  
2765                      for (prop in results) {
2766                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2767                              xml += serializeToJUnitXML(results[prop]);
2768                          }
2769                      }              
2770                      
2771                      xml += "</testsuite>";
2772                      break;
2773                  
2774                  case "testsuite":
2775                      for (prop in results) {
2776                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2777                              xml += serializeToJUnitXML(results[prop]);
2778                          }
2779                      } 
2780  
2781                      //skip output - no JUnit equivalent                    
2782                      break;
2783                      
2784                  case "report":
2785                  
2786                      xml = "<testsuites>";
2787                  
2788                      for (prop in results) {
2789                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2790                              xml += serializeToJUnitXML(results[prop]);
2791                          }
2792                      }              
2793                      
2794                      xml += "</testsuites>";            
2795                  
2796                  //no default
2797              }
2798              
2799              return xml;
2800       
2801          }
2802  
2803          return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToJUnitXML(results);
2804      };
2805      
2806      /**
2807       * Returns test results formatted in TAP format.
2808       * For more information, see <a href="http://testanything.org/">Test Anything Protocol</a>.
2809       * @param {Object} result The results object created by TestRunner.
2810       * @return {String} A TAP-formatted string of results.
2811       * @namespace YAHOO.tool.TestFormat
2812       * @method TAP
2813       * @static
2814       */
2815      YAHOO.tool.TestFormat.TAP = function(results) {
2816      
2817          var currentTestNum = 1;
2818  
2819          function serializeToTAP(results){
2820              var l   = YAHOO.lang,
2821                  text = "";
2822                  
2823              switch (results.type){
2824  
2825                  case "test":
2826                      if (results.result != "ignore"){
2827  
2828                          text = "ok " + (currentTestNum++) + " - " + results.name;
2829                          
2830                          if (results.result == "fail"){
2831                              text = "not " + text + " - " + results.message;
2832                          }
2833                          
2834                          text += "\n";
2835                      } else {
2836                          text = "#Ignored test " + results.name + "\n";
2837                      }
2838                      break;
2839                      
2840                  case "testcase":
2841                  
2842                      text = "#Begin testcase " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";
2843                                      
2844                                      
2845                      for (prop in results) {
2846                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2847                              text += serializeToTAP(results[prop]);
2848                          }
2849                      }              
2850                                                          
2851                      text += "#End testcase " + results.name + "\n";
2852                      
2853                      
2854                      break;
2855                  
2856                  case "testsuite":
2857  
2858                      text = "#Begin testsuite " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";                
2859                  
2860                      for (prop in results) {
2861                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2862                              text += serializeToTAP(results[prop]);
2863                          }
2864                      }   
2865  
2866                      text += "#End testsuite " + results.name + "\n";
2867                      break;
2868  
2869                  case "report":
2870                  
2871                      for (prop in results) {
2872                          if (l.hasOwnProperty(results, prop) && l.isObject(results[prop]) && !l.isArray(results[prop])){
2873                              text += serializeToTAP(results[prop]);
2874                          }
2875                      }             
2876                      
2877                  //no default
2878              }
2879              
2880              return text;
2881       
2882          }
2883  
2884          return "1.." + results.total + "\n" + serializeToTAP(results);
2885      };   
2886  
2887  })();
2888  YAHOO.namespace("tool.CoverageFormat");
2889  
2890  /**
2891   * Returns the coverage report in JSON format. This is the straight
2892   * JSON representation of the native coverage report.
2893   * @param {Object} coverage The coverage report object.
2894   * @return {String} A JSON-formatted string of coverage data.
2895   * @method JSON
2896   * @namespace YAHOO.tool.CoverageFormat
2897   */
2898  YAHOO.tool.CoverageFormat.JSON = function(coverage){
2899      return YAHOO.lang.JSON.stringify(coverage);
2900  };
2901  
2902  /**
2903   * Returns the coverage report in a JSON format compatible with
2904   * Xdebug. See <a href="http://www.xdebug.com/docs/code_coverage">Xdebug Documentation</a>
2905   * for more information. Note: function coverage is not available
2906   * in this format.
2907   * @param {Object} coverage The coverage report object.
2908   * @return {String} A JSON-formatted string of coverage data.
2909   * @method XdebugJSON
2910   * @namespace YAHOO.tool.CoverageFormat
2911   */
2912  YAHOO.tool.CoverageFormat.XdebugJSON = function(coverage){
2913      var report = {},
2914          prop;
2915      for (prop in coverage){
2916          if (coverage.hasOwnProperty(prop)){
2917              report[prop] = coverage[prop].lines;
2918          }
2919      }
2920  
2921      return YAHOO.lang.JSON.stringify(report);        
2922  };
2923  
2924  YAHOO.namespace("tool");
2925  
2926  /**
2927   * An object capable of sending test results to a server.
2928   * @param {String} url The URL to submit the results to.
2929   * @param {Function} format (Optiona) A function that outputs the results in a specific format.
2930   *      Default is YAHOO.tool.TestFormat.XML.
2931   * @constructor
2932   * @namespace YAHOO.tool
2933   * @class TestReporter
2934   */
2935  YAHOO.tool.TestReporter = function(url /*:String*/, format /*:Function*/) {
2936  
2937      /**
2938       * The URL to submit the data to.
2939       * @type String
2940       * @property url
2941       */
2942      this.url /*:String*/ = url;
2943  
2944      /**
2945       * The formatting function to call when submitting the data.
2946       * @type Function
2947       * @property format
2948       */
2949      this.format /*:Function*/ = format || YAHOO.tool.TestFormat.XML;
2950  
2951      /**
2952       * Extra fields to submit with the request.
2953       * @type Object
2954       * @property _fields
2955       * @private
2956       */
2957      this._fields /*:Object*/ = new Object();
2958      
2959      /**
2960       * The form element used to submit the results.
2961       * @type HTMLFormElement
2962       * @property _form
2963       * @private
2964       */
2965      this._form /*:HTMLElement*/ = null;
2966  
2967      /**
2968       * Iframe used as a target for form submission.
2969       * @type HTMLIFrameElement
2970       * @property _iframe
2971       * @private
2972       */
2973      this._iframe /*:HTMLElement*/ = null;
2974  };
2975  
2976  YAHOO.tool.TestReporter.prototype = {
2977  
2978      //restore missing constructor
2979      constructor: YAHOO.tool.TestReporter,
2980      
2981      /**
2982       * Convert a date into ISO format.
2983       * From Douglas Crockford's json2.js
2984       * @param {Date} date The date to convert.
2985       * @return {String} An ISO-formatted date string
2986       * @method _convertToISOString
2987       * @private
2988       */    
2989      _convertToISOString: function(date){
2990          function f(n) {
2991              // Format integers to have at least two digits.
2992              return n < 10 ? '0' + n : n;
2993          }
2994  
2995          return date.getUTCFullYear()   + '-' +
2996               f(date.getUTCMonth() + 1) + '-' +
2997               f(date.getUTCDate())      + 'T' +
2998               f(date.getUTCHours())     + ':' +
2999               f(date.getUTCMinutes())   + ':' +
3000               f(date.getUTCSeconds())   + 'Z';     
3001      
3002      },
3003  
3004      /**
3005       * Adds a field to the form that submits the results.
3006       * @param {String} name The name of the field.
3007       * @param {Variant} value The value of the field.
3008       * @return {Void}
3009       * @method addField
3010       */
3011      addField : function (name /*:String*/, value /*:Variant*/) /*:Void*/{
3012          this._fields[name] = value;    
3013      },
3014      
3015      /**
3016       * Removes all previous defined fields.
3017       * @return {Void}
3018       * @method addField
3019       */
3020      clearFields : function() /*:Void*/{
3021          this._fields = new Object();
3022      },
3023  
3024      /**
3025       * Cleans up the memory associated with the TestReporter, removing DOM elements
3026       * that were created.
3027       * @return {Void}
3028       * @method destroy
3029       */
3030      destroy : function() /*:Void*/ {
3031          if (this._form){
3032              this._form.parentNode.removeChild(this._form);
3033              this._form = null;
3034          }        
3035          if (this._iframe){
3036              this._iframe.parentNode.removeChild(this._iframe);
3037              this._iframe = null;
3038          }
3039          this._fields = null;
3040      },
3041  
3042      /**
3043       * Sends the report to the server.
3044       * @param {Object} results The results object created by TestRunner.
3045       * @return {Void}
3046       * @method report
3047       */
3048      report : function(results /*:Object*/) /*:Void*/{
3049      
3050          //if the form hasn't been created yet, create it
3051          if (!this._form){
3052              this._form = document.createElement("form");
3053              this._form.method = "post";
3054              this._form.style.visibility = "hidden";
3055              this._form.style.position = "absolute";
3056              this._form.style.top = 0;
3057              document.body.appendChild(this._form);
3058          
3059              //IE won't let you assign a name using the DOM, must do it the hacky way
3060              if (YAHOO.env.ua.ie){
3061                  this._iframe = document.createElement("<iframe name=\"yuiTestTarget\" />");
3062              } else {
3063                  this._iframe = document.createElement("iframe");
3064                  this._iframe.name = "yuiTestTarget";
3065              }
3066  
3067              this._iframe.src = "javascript:false";
3068              this._iframe.style.visibility = "hidden";
3069              this._iframe.style.position = "absolute";
3070              this._iframe.style.top = 0;
3071              document.body.appendChild(this._iframe);
3072  
3073              this._form.target = "yuiTestTarget";
3074          }
3075  
3076          //set the form's action
3077          this._form.action = this.url;
3078      
3079          //remove any existing fields
3080          while(this._form.hasChildNodes()){
3081              this._form.removeChild(this._form.lastChild);
3082          }
3083          
3084          //create default fields
3085          this._fields.results = this.format(results);
3086          this._fields.useragent = navigator.userAgent;
3087          this._fields.timestamp = this._convertToISOString(new Date());
3088  
3089          //add fields to the form
3090          for (var prop in this._fields){
3091              if (YAHOO.lang.hasOwnProperty(this._fields, prop) && typeof this._fields[prop] != "function"){
3092                  if (YAHOO.env.ua.ie){
3093                      input = document.createElement("<input name=\"" + prop + "\" >");
3094                  } else {
3095                      input = document.createElement("input");
3096                      input.name = prop;
3097                  }
3098                  input.type = "hidden";
3099                  input.value = this._fields[prop];
3100                  this._form.appendChild(input);
3101              }
3102          }
3103  
3104          //remove default fields
3105          delete this._fields.results;
3106          delete this._fields.useragent;
3107          delete this._fields.timestamp;
3108          
3109          if (arguments[1] !== false){
3110              this._form.submit();
3111          }
3112      
3113      }
3114  
3115  };
3116  /*Stub for future compatibility*/
3117  YUITest = {
3118      TestRunner:     YAHOO.tool.TestRunner,
3119      ResultsFormat:  YAHOO.tool.TestFormat,
3120      CoverageFormat: YAHOO.tool.CoverageFormat
3121  };
3122  YAHOO.register("yuitest", YAHOO.tool.TestRunner, {version: "2.9.0", build: "2800"});
3123  
3124  }, '2.9.0' ,{"requires": ["yui2-skin-sam-yuitest", "yui2-yahoo", "yui2-dom", "yui2-event", "yui2-skin-sam-logger", "yui2-logger"], "optional": ["yui2-event-simulate"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1