~ubuntu-branches/ubuntu/quantal/maas/quantal-updates

« back to all changes in this revision

Viewing changes to src/maasserver/static/jslibs/yui/3.4.1/build/test/test-debug.js

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2012-07-03 17:42:37 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20120703174237-p8l0keuuznfg721k
Tags: 0.1+bzr709+dfsg-0ubuntu1
* New Upstream release
* debian/control:
  - Depends on python-celery, python-tempita, libjs-yui3-{full,min},
    libjs-raphael
* debian/maas.install:
  - Install apiclient, celeryconfig.py, maas-import-pxe-files, preseeds_v2.
  - Update to install various files from chroot, rather tha manually copy
    them from the source.
* debian/maas.links: symlink celeryconfig.py
* debian/maas.maas-celery.upstart: Add job.
* debian/rules:
  - Install celery upstart job.
  - Do not install jslibs as packages are now used.
  - Drop copying of maas_local_settings_sample.py as source now ships
    a maas_local_settings.py
* debian/patches:
  - 04-maas-http-fix.patch: Drop. Merged upstream.
  - 01-fix-database-settings.patch: Refreshed.
  - 99_enums_js.patch: Added until creation of enum.js / build process
    is fixed.
* debian/maas.postinst: Update bzr version to correctly handle upgrades.

Show diffs side-by-side

added added

removed removed

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