~ubuntu-branches/ubuntu/trusty/almond/trusty

« back to all changes in this revision

Viewing changes to tests/doh/runner.js

  • Committer: Package Import Robot
  • Author(s): Georges Khaznadar
  • Date: 2013-11-02 16:28:01 UTC
  • Revision ID: package-import@ubuntu.com-20131102162801-c33r5wt6efwq52n7
Tags: upstream-0.2.6
ImportĀ upstreamĀ versionĀ 0.2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// package system gunk.
 
2
//try{
 
3
//      dojo.provide("doh.runner");
 
4
//}catch(e){
 
5
        if(!this["doh"]){
 
6
                doh = {};
 
7
        }
 
8
//}
 
9
 
 
10
//
 
11
// Utility Functions and Classes
 
12
//
 
13
 
 
14
doh.selfTest = false;
 
15
 
 
16
doh.global = this;
 
17
 
 
18
doh.hitch = function(/*Object*/thisObject, /*Function|String*/method /*, ...*/){
 
19
        var args = [];
 
20
        for(var x=2; x<arguments.length; x++){
 
21
                args.push(arguments[x]);
 
22
        }
 
23
        var fcn = ((typeof method == "string") ? thisObject[method] : method) || function(){};
 
24
        return function(){
 
25
                var ta = args.concat([]); // make a copy
 
26
                for(var x=0; x<arguments.length; x++){
 
27
                        ta.push(arguments[x]);
 
28
                }
 
29
                return fcn.apply(thisObject, ta); // Function
 
30
        };
 
31
}
 
32
 
 
33
doh._mixin = function(/*Object*/ obj, /*Object*/ props){
 
34
        // summary:
 
35
        //              Adds all properties and methods of props to obj. This addition is
 
36
        //              "prototype extension safe", so that instances of objects will not
 
37
        //              pass along prototype defaults.
 
38
        var tobj = {};
 
39
        for(var x in props){
 
40
                // the "tobj" condition avoid copying properties in "props"
 
41
                // inherited from Object.prototype.  For example, if obj has a custom
 
42
                // toString() method, don't overwrite it with the toString() method
 
43
                // that props inherited from Object.protoype
 
44
                if(tobj[x] === undefined || tobj[x] != props[x]){
 
45
                        obj[x] = props[x];
 
46
                }
 
47
        }
 
48
        // IE doesn't recognize custom toStrings in for..in
 
49
        if(     this["document"]
 
50
                && document.all
 
51
                && (typeof props["toString"] == "function")
 
52
                && (props["toString"] != obj["toString"])
 
53
                && (props["toString"] != tobj["toString"])
 
54
        ){
 
55
                obj.toString = props.toString;
 
56
        }
 
57
        return obj; // Object
 
58
}
 
59
 
 
60
doh.mixin = function(/*Object*/obj, /*Object...*/props){
 
61
        // summary:     Adds all properties and methods of props to obj.
 
62
        for(var i=1, l=arguments.length; i<l; i++){
 
63
                doh._mixin(obj, arguments[i]);
 
64
        }
 
65
        return obj; // Object
 
66
}
 
67
 
 
68
doh.extend = function(/*Object*/ constructor, /*Object...*/ props){
 
69
        // summary:
 
70
        //              Adds all properties and methods of props to constructor's
 
71
        //              prototype, making them available to all instances created with
 
72
        //              constructor.
 
73
        for(var i=1, l=arguments.length; i<l; i++){
 
74
                doh._mixin(constructor.prototype, arguments[i]);
 
75
        }
 
76
        return constructor; // Object
 
77
}
 
78
 
 
79
 
 
80
doh._line = "------------------------------------------------------------";
 
81
 
 
82
/*
 
83
doh._delegate = function(obj, props){
 
84
        // boodman-crockford delegation
 
85
        function TMP(){};
 
86
        TMP.prototype = obj;
 
87
        var tmp = new TMP();
 
88
        if(props){
 
89
                dojo.lang.mixin(tmp, props);
 
90
        }
 
91
        return tmp;
 
92
}
 
93
*/
 
94
 
 
95
doh.debug = function(){
 
96
        // summary:
 
97
        //              takes any number of arguments and sends them to whatever debugging
 
98
        //              or logging facility is available in this environment
 
99
 
 
100
        // YOUR TEST RUNNER NEEDS TO IMPLEMENT THIS
 
101
}
 
102
 
 
103
doh._AssertFailure = function(msg, hint){
 
104
        // idea for this as way of dis-ambiguating error types is from JUM.
 
105
        // The JUM is dead! Long live the JUM!
 
106
 
 
107
        if(!(this instanceof doh._AssertFailure)){
 
108
                return new doh._AssertFailure(msg, hint);
 
109
        }
 
110
        if(hint){
 
111
                msg = (new String(msg||""))+" with hint: \n\t\t"+(new String(hint)+"\n");
 
112
        }
 
113
        this.message = new String(msg||"");
 
114
        return this;
 
115
}
 
116
doh._AssertFailure.prototype = new Error();
 
117
doh._AssertFailure.prototype.constructor = doh._AssertFailure;
 
118
doh._AssertFailure.prototype.name = "doh._AssertFailure";
 
119
 
 
120
doh.Deferred = function(canceller){
 
121
        this.chain = [];
 
122
        this.id = this._nextId();
 
123
        this.fired = -1;
 
124
        this.paused = 0;
 
125
        this.results = [null, null];
 
126
        this.canceller = canceller;
 
127
        this.silentlyCancelled = false;
 
128
};
 
129
 
 
130
doh.extend(doh.Deferred, {
 
131
        getTestErrback: function(cb, scope){
 
132
                // summary: Replaces outer getTextCallback's in nested situations to avoid multiple callback(true)'s
 
133
                var _this = this;
 
134
                return function(){
 
135
                        try{
 
136
                                cb.apply(scope||doh.global||_this, arguments);
 
137
                        }catch(e){
 
138
                                _this.errback(e);
 
139
                        }
 
140
                };
 
141
        },
 
142
 
 
143
        getTestCallback: function(cb, scope){
 
144
                var _this = this;
 
145
                return function(){
 
146
                        try{
 
147
                                cb.apply(scope||doh.global||_this, arguments);
 
148
                        }catch(e){
 
149
                                _this.errback(e);
 
150
                                return;
 
151
                        }
 
152
                        _this.callback(true);
 
153
                };
 
154
        },
 
155
 
 
156
        getFunctionFromArgs: function(){
 
157
                var a = arguments;
 
158
                if((a[0])&&(!a[1])){
 
159
                        if(typeof a[0] == "function"){
 
160
                                return a[0];
 
161
                        }else if(typeof a[0] == "string"){
 
162
                                return doh.global[a[0]];
 
163
                        }
 
164
                }else if((a[0])&&(a[1])){
 
165
                        return doh.hitch(a[0], a[1]);
 
166
                }
 
167
                return null;
 
168
        },
 
169
 
 
170
        makeCalled: function() {
 
171
                var deferred = new doh.Deferred();
 
172
                deferred.callback();
 
173
                return deferred;
 
174
        },
 
175
 
 
176
        _nextId: (function(){
 
177
                var n = 1;
 
178
                return function(){ return n++; };
 
179
        })(),
 
180
 
 
181
        cancel: function(){
 
182
                if(this.fired == -1){
 
183
                        if (this.canceller){
 
184
                                this.canceller(this);
 
185
                        }else{
 
186
                                this.silentlyCancelled = true;
 
187
                        }
 
188
                        if(this.fired == -1){
 
189
                                this.errback(new Error("Deferred(unfired)"));
 
190
                        }
 
191
                }else if(this.fired == 0 &&
 
192
                                        (this.results[0] instanceof doh.Deferred)){
 
193
                        this.results[0].cancel();
 
194
                }
 
195
        },
 
196
 
 
197
 
 
198
        _pause: function(){
 
199
                this.paused++;
 
200
        },
 
201
 
 
202
        _unpause: function(){
 
203
                this.paused--;
 
204
                if ((this.paused == 0) && (this.fired >= 0)) {
 
205
                        this._fire();
 
206
                }
 
207
        },
 
208
 
 
209
        _continue: function(res){
 
210
                this._resback(res);
 
211
                this._unpause();
 
212
        },
 
213
 
 
214
        _resback: function(res){
 
215
                this.fired = ((res instanceof Error) ? 1 : 0);
 
216
                this.results[this.fired] = res;
 
217
                this._fire();
 
218
        },
 
219
 
 
220
        _check: function(){
 
221
                if(this.fired != -1){
 
222
                        if(!this.silentlyCancelled){
 
223
                                throw new Error("already called!");
 
224
                        }
 
225
                        this.silentlyCancelled = false;
 
226
                        return;
 
227
                }
 
228
        },
 
229
 
 
230
        callback: function(res){
 
231
                this._check();
 
232
                this._resback(res);
 
233
        },
 
234
 
 
235
        errback: function(res){
 
236
                this._check();
 
237
                if(!(res instanceof Error)){
 
238
                        res = new Error(res);
 
239
                }
 
240
                this._resback(res);
 
241
        },
 
242
 
 
243
        addBoth: function(cb, cbfn){
 
244
                var enclosed = this.getFunctionFromArgs(cb, cbfn);
 
245
                if(arguments.length > 2){
 
246
                        enclosed = doh.hitch(null, enclosed, arguments, 2);
 
247
                }
 
248
                return this.addCallbacks(enclosed, enclosed);
 
249
        },
 
250
 
 
251
        addCallback: function(cb, cbfn){
 
252
                var enclosed = this.getFunctionFromArgs(cb, cbfn);
 
253
                if(arguments.length > 2){
 
254
                        enclosed = doh.hitch(null, enclosed, arguments, 2);
 
255
                }
 
256
                return this.addCallbacks(enclosed, null);
 
257
        },
 
258
 
 
259
        addErrback: function(cb, cbfn){
 
260
                var enclosed = this.getFunctionFromArgs(cb, cbfn);
 
261
                if(arguments.length > 2){
 
262
                        enclosed = doh.hitch(null, enclosed, arguments, 2);
 
263
                }
 
264
                return this.addCallbacks(null, enclosed);
 
265
        },
 
266
 
 
267
        addCallbacks: function(cb, eb){
 
268
                this.chain.push([cb, eb]);
 
269
                if(this.fired >= 0){
 
270
                        this._fire();
 
271
                }
 
272
                return this;
 
273
        },
 
274
 
 
275
        _fire: function(){
 
276
                var chain = this.chain;
 
277
                var fired = this.fired;
 
278
                var res = this.results[fired];
 
279
                var self = this;
 
280
                var cb = null;
 
281
                while(chain.length > 0 && this.paused == 0){
 
282
                        // Array
 
283
                        var pair = chain.shift();
 
284
                        var f = pair[fired];
 
285
                        if(f == null){
 
286
                                continue;
 
287
                        }
 
288
                        try {
 
289
                                res = f(res);
 
290
                                fired = ((res instanceof Error) ? 1 : 0);
 
291
                                if(res instanceof doh.Deferred){
 
292
                                        cb = function(res){
 
293
                                                self._continue(res);
 
294
                                        };
 
295
                                        this._pause();
 
296
                                }
 
297
                        }catch(err){
 
298
                                fired = 1;
 
299
                                res = err;
 
300
                        }
 
301
                }
 
302
                this.fired = fired;
 
303
                this.results[fired] = res;
 
304
                if((cb)&&(this.paused)){
 
305
                        res.addBoth(cb);
 
306
                }
 
307
        }
 
308
});
 
309
 
 
310
//
 
311
// State Keeping and Reporting
 
312
//
 
313
 
 
314
doh._testCount = 0;
 
315
doh._groupCount = 0;
 
316
doh._errorCount = 0;
 
317
doh._failureCount = 0;
 
318
doh._currentGroup = null;
 
319
doh._currentTest = null;
 
320
doh._paused = true;
 
321
 
 
322
doh._init = function(){
 
323
        this._currentGroup = null;
 
324
        this._currentTest = null;
 
325
        this._errorCount = 0;
 
326
        this._failureCount = 0;
 
327
        this.debug(this._testCount, "tests to run in", this._groupCount, "groups");
 
328
}
 
329
 
 
330
// doh._urls = [];
 
331
doh._groups = {};
 
332
 
 
333
//
 
334
// Test Registration
 
335
//
 
336
 
 
337
doh.registerTestNs = function(/*String*/ group, /*Object*/ ns){
 
338
        // summary:
 
339
        //              adds the passed namespace object to the list of objects to be
 
340
        //              searched for test groups. Only "public" functions (not prefixed
 
341
        //              with "_") will be added as tests to be run. If you'd like to use
 
342
        //              fixtures (setUp(), tearDown(), and runTest()), please use
 
343
        //              registerTest() or registerTests().
 
344
        for(var x in ns){
 
345
                if(     (x.charAt(0) != "_") &&
 
346
                        (typeof ns[x] == "function") ){
 
347
                        this.registerTest(group, ns[x]);
 
348
                }
 
349
        }
 
350
}
 
351
 
 
352
doh._testRegistered = function(group, fixture){
 
353
        // slot to be filled in
 
354
}
 
355
 
 
356
doh._groupStarted = function(group){
 
357
        // slot to be filled in
 
358
}
 
359
 
 
360
doh._groupFinished = function(group, success){
 
361
        // slot to be filled in
 
362
}
 
363
 
 
364
doh._testStarted = function(group, fixture){
 
365
        // slot to be filled in
 
366
}
 
367
 
 
368
doh._testFinished = function(group, fixture, success){
 
369
        // slot to be filled in
 
370
}
 
371
 
 
372
doh.registerGroup = function(   /*String*/ group,
 
373
                                                                /*Array||Function||Object*/ tests,
 
374
                                                                /*Function*/ setUp,
 
375
                                                                /*Function*/ tearDown,
 
376
                                                                /*String*/ type){
 
377
        // summary:
 
378
        //              registers an entire group of tests at once and provides a setUp and
 
379
        //              tearDown facility for groups. If you call this method with only
 
380
        //              setUp and tearDown parameters, they will replace previously
 
381
        //              installed setUp or tearDown functions for the group with the new
 
382
        //              methods.
 
383
        // group:
 
384
        //              string name of the group
 
385
        // tests:
 
386
        //              either a function or an object or an array of functions/objects. If
 
387
        //              an object, it must contain at *least* a "runTest" method, and may
 
388
        //              also contain "setUp" and "tearDown" methods. These will be invoked
 
389
        //              on either side of the "runTest" method (respectively) when the test
 
390
        //              is run. If an array, it must contain objects matching the above
 
391
        //              description or test functions.
 
392
        // setUp: a function for initializing the test group
 
393
        // tearDown: a function for initializing the test group
 
394
        // type: The type of tests these are, such as a group of performance tests
 
395
        //              null/undefied are standard DOH tests, the valye 'perf' enables
 
396
        //              registering them as performance tests.
 
397
        if(tests){
 
398
                this.register(group, tests, type);
 
399
        }
 
400
        if(setUp){
 
401
                this._groups[group].setUp = setUp;
 
402
        }
 
403
        if(tearDown){
 
404
                this._groups[group].tearDown = tearDown;
 
405
        }
 
406
}
 
407
 
 
408
doh._getTestObj = function(group, test, type){
 
409
        var tObj = test;
 
410
        if(typeof test == "string"){
 
411
                if(test.substr(0, 4)=="url:"){
 
412
                        return this.registerUrl(group, test);
 
413
                }else{
 
414
                        tObj = {
 
415
                                name: test.replace("/\s/g", "_") // FIXME: bad escapement
 
416
                        };
 
417
                        tObj.runTest = new Function("t", test);
 
418
                }
 
419
        }else if(typeof test == "function"){
 
420
                // if we didn't get a fixture, wrap the function
 
421
                tObj = { "runTest": test };
 
422
                if(test["name"]){
 
423
                        tObj.name = test.name;
 
424
                }else{
 
425
                        try{
 
426
                                var fStr = "function ";
 
427
                                var ts = tObj.runTest+"";
 
428
                                if(0 <= ts.indexOf(fStr)){
 
429
                                        tObj.name = ts.split(fStr)[1].split("(", 1)[0];
 
430
                                }
 
431
                                // doh.debug(tObj.runTest.toSource());
 
432
                        }catch(e){
 
433
                        }
 
434
                }
 
435
                // FIXME: try harder to get the test name here
 
436
        }
 
437
 
 
438
        //Augment the test with some specific options to make it identifiable as a
 
439
        //particular type of test so it can be executed properly.
 
440
        if(type === "perf" || tObj.testType === "perf"){
 
441
                tObj.testType = "perf";
 
442
 
 
443
                //Build an object on the root DOH class to contain all the test results.
 
444
                //Cache it on the test object for quick lookup later for results storage.
 
445
                if(!doh.perfTestResults){
 
446
                        doh.perfTestResults = {};
 
447
                        doh.perfTestResults[group] = {};
 
448
                }
 
449
                if(!doh.perfTestResults[group]){
 
450
                        doh.perfTestResults[group] = {};
 
451
                }
 
452
                if(!doh.perfTestResults[group][tObj.name]){
 
453
                        doh.perfTestResults[group][tObj.name] = {};
 
454
                }
 
455
                tObj.results = doh.perfTestResults[group][tObj.name];
 
456
 
 
457
                //If it's not set, then set the trial duration
 
458
                //default to 100ms.
 
459
                if(!("trialDuration" in tObj)){
 
460
                        tObj.trialDuration = 100;
 
461
                }
 
462
 
 
463
                //If it's not set, then set the delay between trial runs to 100ms
 
464
                //default to 100ms to allow for GC and to make IE happy.
 
465
                if(!("trialDelay" in tObj)){
 
466
                        tObj.trialDelay = 100;
 
467
                }
 
468
 
 
469
                //If it's not set, then set number of times a trial is run to 10.
 
470
                if(!("trialIterations" in tObj)){
 
471
                        tObj.trialIterations = 10;
 
472
                }
 
473
        }
 
474
        return tObj;
 
475
}
 
476
 
 
477
doh.registerTest = function(/*String*/ group, /*Function||Object*/ test, /*String*/ type){
 
478
        // summary:
 
479
        //              add the provided test function or fixture object to the specified
 
480
        //              test group.
 
481
        // group:
 
482
        //              string name of the group to add the test to
 
483
        // test:
 
484
        //              either a function or an object. If an object, it must contain at
 
485
        //              *least* a "runTest" method, and may also contain "setUp" and
 
486
        //              "tearDown" methods. These will be invoked on either side of the
 
487
        //              "runTest" method (respectively) when the test is run.
 
488
        // type:
 
489
        //              An identifier denoting the type of testing that the test performs, such
 
490
        //              as a performance test.  If null, defaults to regular DOH test.
 
491
        if(!this._groups[group]){
 
492
                this._groupCount++;
 
493
                this._groups[group] = [];
 
494
                this._groups[group].inFlight = 0;
 
495
        }
 
496
        var tObj = this._getTestObj(group, test, type);
 
497
        if(!tObj){ return null; }
 
498
        this._groups[group].push(tObj);
 
499
        this._testCount++;
 
500
        this._testRegistered(group, tObj);
 
501
        return tObj;
 
502
}
 
503
 
 
504
doh.registerTests = function(/*String*/ group, /*Array*/ testArr, /*String*/ type){
 
505
        // summary:
 
506
        //              registers a group of tests, treating each element of testArr as
 
507
        //              though it were being (along with group) passed to the registerTest
 
508
        //              method.  It also uses the type to decide how the tests should
 
509
        //              behave, by defining the type of tests these are, such as performance tests
 
510
        for(var x=0; x<testArr.length; x++){
 
511
                this.registerTest(group, testArr[x], type);
 
512
        }
 
513
}
 
514
 
 
515
// FIXME: move implementation to _browserRunner?
 
516
doh.registerUrl = function(     /*String*/ group,
 
517
                                                                /*String*/ url,
 
518
                                                                /*Integer*/ timeout,
 
519
                                                                /*String*/ type){
 
520
        this.debug("ERROR:");
 
521
        this.debug("\tNO registerUrl() METHOD AVAILABLE.");
 
522
        // this._urls.push(url);
 
523
}
 
524
 
 
525
doh.registerString = function(group, str, type){
 
526
}
 
527
 
 
528
// FIXME: remove the doh.add alias SRTL.
 
529
doh.register = doh.add = function(groupOrNs, testOrNull, type){
 
530
        // summary:
 
531
        //              "magical" variant of registerTests, registerTest, and
 
532
        //              registerTestNs. Will accept the calling arguments of any of these
 
533
        //              methods and will correctly guess the right one to register with.
 
534
        if(     (arguments.length == 1)&&
 
535
                (typeof groupOrNs == "string") ){
 
536
                if(groupOrNs.substr(0, 4)=="url:"){
 
537
                        this.registerUrl(groupOrNs, null, null, type);
 
538
                }else{
 
539
                        this.registerTest("ungrouped", groupOrNs, type);
 
540
                }
 
541
        }
 
542
        if(arguments.length == 1){
 
543
                this.debug("invalid args passed to doh.register():", groupOrNs, ",", testOrNull);
 
544
                return;
 
545
        }
 
546
        if(typeof testOrNull == "string"){
 
547
                if(testOrNull.substr(0, 4)=="url:"){
 
548
                        this.registerUrl(testOrNull, null, null, type);
 
549
                }else{
 
550
                        this.registerTest(groupOrNs, testOrNull, type);
 
551
                }
 
552
                // this.registerTestNs(groupOrNs, testOrNull);
 
553
                return;
 
554
        }
 
555
        if(doh._isArray(testOrNull)){
 
556
                this.registerTests(groupOrNs, testOrNull, type);
 
557
                return;
 
558
        }
 
559
        this.registerTest(groupOrNs, testOrNull, type);
 
560
};
 
561
 
 
562
doh.registerDocTests = function(module){
 
563
        // no-op for when Dojo isn't loaded into the page
 
564
        this.debug("registerDocTests() requires dojo to be loaded into the environment. Skipping doctest set for module:", module);
 
565
};
 
566
(function(){
 
567
        if(typeof dojo != "undefined"){
 
568
                try{
 
569
                        dojo.require("dojox.testing.DocTest");
 
570
                }catch(e){
 
571
                        // if the DocTest module isn't available (e.g., the build we're
 
572
                        // running from doesn't include it), stub it out and log the error
 
573
                        console.debug(e);
 
574
 
 
575
                        doh.registerDocTests = function(){}
 
576
                        return;
 
577
                }
 
578
                doh.registerDocTests = function(module){
 
579
                        //      summary:
 
580
                        //              Get all the doctests from the given module and register each of them
 
581
                        //              as a single test case here.
 
582
                        //
 
583
 
 
584
                        var docTest = new dojox.testing.DocTest();
 
585
                        var docTests = docTest.getTests(module);
 
586
                        var len = docTests.length;
 
587
                        var tests = [];
 
588
                        for (var i=0; i<len; i++){
 
589
                                var test = docTests[i];
 
590
                                // Extract comment on first line and add to test name.
 
591
                                var comment = "";
 
592
                                if (test.commands.length && test.commands[0].indexOf("//")!=-1) {
 
593
                                        var parts = test.commands[0].split("//");
 
594
                                        comment = ", "+parts[parts.length-1]; // Get all after the last //, so we dont get trapped by http:// or alikes :-).
 
595
                                }
 
596
                                tests.push({
 
597
                                        runTest: (function(test){
 
598
                                                return function(t){
 
599
                                                        var r = docTest.runTest(test.commands, test.expectedResult);
 
600
                                                        t.assertTrue(r.success);
 
601
                                                }
 
602
                                        })(test),
 
603
                                        name:"Line "+test.line+comment
 
604
                                }
 
605
                                );
 
606
                        }
 
607
                        this.register("DocTests: "+module, tests);
 
608
                }
 
609
        }
 
610
})();
 
611
 
 
612
//
 
613
// Assertions and In-Test Utilities
 
614
//
 
615
 
 
616
doh.t = doh.assertTrue = function(/*Object*/ condition, /*String?*/ hint){
 
617
        // summary:
 
618
        //              is the passed item "truthy"?
 
619
        if(arguments.length < 1){
 
620
                throw new doh._AssertFailure("assertTrue failed because it was not passed at least 1 argument");
 
621
        }
 
622
        if(!eval(condition)){
 
623
                throw new doh._AssertFailure("assertTrue('" + condition + "') failed", hint);
 
624
        }
 
625
}
 
626
 
 
627
doh.f = doh.assertFalse = function(/*Object*/ condition, /*String?*/ hint){
 
628
        // summary:
 
629
        //              is the passed item "falsey"?
 
630
        if(arguments.length < 1){
 
631
                throw new doh._AssertFailure("assertFalse failed because it was not passed at least 1 argument");
 
632
        }
 
633
        if(eval(condition)){
 
634
                throw new doh._AssertFailure("assertFalse('" + condition + "') failed", hint);
 
635
        }
 
636
}
 
637
 
 
638
doh.e = doh.assertError = function(/*Error object*/expectedError, /*Object*/scope, /*String*/functionName, /*Array*/args, /*String?*/ hint){
 
639
        //      summary:
 
640
        //              Test for a certain error to be thrown by the given function.
 
641
        //      example:
 
642
        //              t.assertError(dojox.data.QueryReadStore.InvalidAttributeError, store, "getValue", [item, "NOT THERE"]);
 
643
        //              t.assertError(dojox.data.QueryReadStore.InvalidItemError, store, "getValue", ["not an item", "NOT THERE"]);
 
644
        try{
 
645
                scope[functionName].apply(scope, args);
 
646
        }catch (e){
 
647
                if(e instanceof expectedError){
 
648
                        return true;
 
649
                }else{
 
650
                        throw new doh._AssertFailure("assertError() failed:\n\texpected error\n\t\t"+expectedError+"\n\tbut got\n\t\t"+e+"\n\n", hint);
 
651
                }
 
652
        }
 
653
        throw new doh._AssertFailure("assertError() failed:\n\texpected error\n\t\t"+expectedError+"\n\tbut no error caught\n\n", hint);
 
654
}
 
655
 
 
656
 
 
657
doh.is = doh.assertEqual = function(/*Object*/ expected, /*Object*/ actual, /*String?*/ hint){
 
658
        // summary:
 
659
        //              are the passed expected and actual objects/values deeply
 
660
        //              equivalent?
 
661
 
 
662
        // Compare undefined always with three equal signs, because undefined==null
 
663
        // is true, but undefined===null is false.
 
664
        if((expected === undefined)&&(actual === undefined)){
 
665
                return true;
 
666
        }
 
667
        if(arguments.length < 2){
 
668
                throw doh._AssertFailure("assertEqual failed because it was not passed 2 arguments");
 
669
        }
 
670
        if((expected === actual)||(expected == actual)||
 
671
                                ( typeof expected == "number" && typeof actual == "number" && isNaN(expected) && isNaN(actual) )){
 
672
                return true;
 
673
        }
 
674
        if(     (this._isArray(expected) && this._isArray(actual))&&
 
675
                (this._arrayEq(expected, actual)) ){
 
676
                return true;
 
677
        }
 
678
        if( ((typeof expected == "object")&&((typeof actual == "object")))&&
 
679
                (this._objPropEq(expected, actual)) ){
 
680
                return true;
 
681
        }
 
682
        throw new doh._AssertFailure("assertEqual() failed:\n\texpected\n\t\t"+expected+"\n\tbut got\n\t\t"+actual+"\n\n", hint);
 
683
}
 
684
 
 
685
doh.isNot = doh.assertNotEqual = function(/*Object*/ notExpected, /*Object*/ actual, /*String?*/ hint){
 
686
        // summary:
 
687
        //              are the passed notexpected and actual objects/values deeply
 
688
        //              not equivalent?
 
689
 
 
690
        // Compare undefined always with three equal signs, because undefined==null
 
691
        // is true, but undefined===null is false.
 
692
        if((notExpected === undefined)&&(actual === undefined)){
 
693
        throw new doh._AssertFailure("assertNotEqual() failed: not expected |"+notExpected+"| but got |"+actual+"|", hint);
 
694
        }
 
695
        if(arguments.length < 2){
 
696
                throw doh._AssertFailure("assertEqual failed because it was not passed 2 arguments");
 
697
        }
 
698
        if((notExpected === actual)||(notExpected == actual)){
 
699
        throw new doh._AssertFailure("assertNotEqual() failed: not expected |"+notExpected+"| but got |"+actual+"|", hint);
 
700
        }
 
701
        if(     (this._isArray(notExpected) && this._isArray(actual))&&
 
702
                (this._arrayEq(notExpected, actual)) ){
 
703
                throw new doh._AssertFailure("assertNotEqual() failed: not expected |"+notExpected+"| but got |"+actual+"|", hint);
 
704
        }
 
705
        if( ((typeof notExpected == "object")&&((typeof actual == "object")))&&
 
706
                (this._objPropEq(notExpected, actual)) ){
 
707
        throw new doh._AssertFailure("assertNotEqual() failed: not expected |"+notExpected+"| but got |"+actual+"|", hint);
 
708
        }
 
709
    return true;
 
710
}
 
711
 
 
712
doh._arrayEq = function(expected, actual){
 
713
        if(expected.length != actual.length){ return false; }
 
714
        // FIXME: we're not handling circular refs. Do we care?
 
715
        for(var x=0; x<expected.length; x++){
 
716
                if(!doh.assertEqual(expected[x], actual[x])){ return false; }
 
717
        }
 
718
        return true;
 
719
}
 
720
 
 
721
doh._objPropEq = function(expected, actual){
 
722
        // Degenerate case: if they are both null, then their "properties" are equal.
 
723
        if(expected === null && actual === null){
 
724
                return true;
 
725
        }
 
726
        // If only one is null, they aren't equal.
 
727
        if(expected === null || actual === null){
 
728
                return false;
 
729
        }
 
730
        if(expected instanceof Date){
 
731
                return actual instanceof Date && expected.getTime()==actual.getTime();
 
732
        }
 
733
        var x;
 
734
        // Make sure ALL THE SAME properties are in both objects!
 
735
        for(x in actual){ // Lets check "actual" here, expected is checked below.
 
736
                if(expected[x] === undefined){
 
737
                        return false;
 
738
                }
 
739
        };
 
740
 
 
741
        for(x in expected){
 
742
                if(!doh.assertEqual(expected[x], actual[x])){
 
743
                        return false;
 
744
                }
 
745
        }
 
746
        return true;
 
747
}
 
748
 
 
749
doh._isArray = function(it){
 
750
        return (it && it instanceof Array || typeof it == "array" ||
 
751
                (
 
752
                        !!doh.global["dojo"] &&
 
753
                        doh.global["dojo"]["NodeList"] !== undefined &&
 
754
                        it instanceof doh.global["dojo"]["NodeList"]
 
755
                )
 
756
        );
 
757
}
 
758
 
 
759
//
 
760
// Runner-Wrapper
 
761
//
 
762
 
 
763
doh._setupGroupForRun = function(/*String*/ groupName, /*Integer*/ idx){
 
764
        var tg = this._groups[groupName];
 
765
        this.debug(this._line);
 
766
        this.debug("GROUP", "\""+groupName+"\"", "has", tg.length, "test"+((tg.length > 1) ? "s" : "")+" to run");
 
767
}
 
768
 
 
769
doh._handleFailure = function(groupName, fixture, e){
 
770
        // this.debug("FAILED test:", fixture.name);
 
771
        // mostly borrowed from JUM
 
772
        this._groups[groupName].failures++;
 
773
        var out = "";
 
774
        if(e instanceof this._AssertFailure){
 
775
                this._failureCount++;
 
776
                if(e["fileName"]){ out += e.fileName + ':'; }
 
777
                if(e["lineNumber"]){ out += e.lineNumber + ' '; }
 
778
                out += e+": "+e.message;
 
779
                this.debug("\t_AssertFailure:", out);
 
780
        }else{
 
781
                this._errorCount++;
 
782
        }
 
783
        this.debug(e);
 
784
        if(fixture.runTest["toSource"]){
 
785
                var ss = fixture.runTest.toSource();
 
786
                this.debug("\tERROR IN:\n\t\t", ss);
 
787
        }else{
 
788
                this.debug("\tERROR IN:\n\t\t", fixture.runTest);
 
789
        }
 
790
 
 
791
        if(e.rhinoException){
 
792
                e.rhinoException.printStackTrace();
 
793
        }else if(e.javaException){
 
794
                e.javaException.printStackTrace();
 
795
        }
 
796
}
 
797
 
 
798
//Assume a setTimeout implementation that is synchronous, so that
 
799
//the Node and Rhino envs work similar to each other. Node defines
 
800
//a setTimeout, so testing for setTimeout is not enough, each environment
 
801
//adapter should set this value accordingly.
 
802
doh.setTimeout = function(func){
 
803
        return func();
 
804
};
 
805
 
 
806
doh._runPerfFixture = function(/*String*/groupName, /*Object*/fixture){
 
807
        //      summary:
 
808
        //              This function handles how to execute a 'performance' test
 
809
        //              which is different from a straight UT style test.  These
 
810
        //              will often do numerous iterations of the same operation and
 
811
        //              gather execution statistics about it, like max, min, average,
 
812
        //              etc.  It makes use of the already in place DOH deferred test
 
813
        //              handling since it is a good idea to put a pause inbetween each
 
814
        //              iteration to allow for GC cleanup and the like.
 
815
        //
 
816
        //      groupName:
 
817
        //              The test group that contains this performance test.
 
818
        //      fixture:
 
819
        //              The performance test fixture.
 
820
        var tg = this._groups[groupName];
 
821
        fixture.startTime = new Date();
 
822
 
 
823
        //Perf tests always need to act in an async manner as there is a
 
824
        //number of iterations to flow through.
 
825
        var def = new doh.Deferred();
 
826
        tg.inFlight++;
 
827
        def.groupName = groupName;
 
828
        def.fixture = fixture;
 
829
 
 
830
        def.addErrback(function(err){
 
831
                doh._handleFailure(groupName, fixture, err);
 
832
        });
 
833
 
 
834
        //Set up the finalizer.
 
835
        var retEnd = function(){
 
836
                if(fixture["tearDown"]){ fixture.tearDown(doh); }
 
837
                tg.inFlight--;
 
838
                if((!tg.inFlight)&&(tg.iterated)){
 
839
                        doh._groupFinished(groupName, !tg.failures);
 
840
                }
 
841
                doh._testFinished(groupName, fixture, def.results[0]);
 
842
                if(doh._paused){
 
843
                        doh.run();
 
844
                }
 
845
        };
 
846
 
 
847
        //Since these can take who knows how long, we don't want to timeout
 
848
        //unless explicitly set
 
849
        var timer;
 
850
        var to = fixture.timeout;
 
851
        if(to > 0) {
 
852
                timer = doh.setTimeout(function(){
 
853
                        // ret.cancel();
 
854
                        // retEnd();
 
855
                        def.errback(new Error("test timeout in "+fixture.name.toString()));
 
856
                }, to);
 
857
        }
 
858
 
 
859
        //Set up the end calls to the test into the deferred we'll return.
 
860
        def.addBoth(function(arg){
 
861
                if(timer){
 
862
                        clearTimeout(timer);
 
863
                }
 
864
                retEnd();
 
865
        });
 
866
 
 
867
        //Okay, now set up the timing loop for the actual test.
 
868
        //This is down as an async type test where there is a delay
 
869
        //between each execution to allow for GC time, etc, so the GC
 
870
        //has less impact on the tests.
 
871
        var res = fixture.results;
 
872
        res.trials = [];
 
873
 
 
874
        //Try to figure out how many calls are needed to hit a particular threshold.
 
875
        var itrDef = doh._calcTrialIterations(groupName, fixture);
 
876
        itrDef.addErrback(function(err){
 
877
                fixture.endTime = new Date();
 
878
                def.errback(err);
 
879
        });
 
880
 
 
881
        //Blah, since tests can be deferred, the actual run has to be deferred until after
 
882
        //we know how many iterations to run.  This is just plain ugly.
 
883
        itrDef.addCallback(function(iterations){
 
884
                if(iterations){
 
885
                        var countdown = fixture.trialIterations;
 
886
                        doh.debug("TIMING TEST: [" + fixture.name +
 
887
                                          "]\n\t\tITERATIONS PER TRIAL: " +
 
888
                                          iterations + "\n\tTRIALS: " +
 
889
                                          countdown);
 
890
 
 
891
                        //Figure out how many times we want to run our 'trial'.
 
892
                        //Where each trial consists of 'iterations' of the test.
 
893
 
 
894
                        var trialRunner = function() {
 
895
                                //Set up our function to execute a block of tests
 
896
                                var start = new Date();
 
897
                                var tTimer = new doh.Deferred();
 
898
                                var tCountdown = iterations;
 
899
 
 
900
                                var tState = {
 
901
                                        countdown: iterations
 
902
                                };
 
903
                                var testRunner = function(state){
 
904
                                        while(state){
 
905
                                                try{
 
906
                                                        state.countdown--;
 
907
                                                        if(state.countdown){
 
908
                                                                var ret = fixture.runTest(doh);
 
909
                                                                if(ret instanceof doh.Deferred){
 
910
                                                                        //Deferreds have to be handled async,
 
911
                                                                        //otherwise we just keep looping.
 
912
                                                                        var atState = {
 
913
                                                                                countdown: state.countdown
 
914
                                                                        };
 
915
                                                                        ret.addCallback(function(){
 
916
                                                                                testRunner(atState);
 
917
                                                                        });
 
918
                                                                        ret.addErrback(function(err) {
 
919
                                                                                doh._handleFailure(groupName, fixture, err);
 
920
                                                                                fixture.endTime = new Date();
 
921
                                                                                def.errback(err);
 
922
                                                                        });
 
923
                                                                        state = null;
 
924
                                                                }
 
925
                                                        }else{
 
926
                                                                tTimer.callback(new Date());
 
927
                                                                state = null;
 
928
                                                        }
 
929
                                                }catch(err){
 
930
                                                        fixture.endTime = new Date();
 
931
                                                        tTimer.errback(err);
 
932
                                                }
 
933
                                        }
 
934
                                };
 
935
                                tTimer.addCallback(function(end){
 
936
                                        //Figure out the results and try to factor out function call costs.
 
937
                                        var tResults = {
 
938
                                                trial: (fixture.trialIterations - countdown),
 
939
                                                testIterations: iterations,
 
940
                                                executionTime: (end.getTime() - start.getTime()),
 
941
                                                average: (end.getTime() - start.getTime())/iterations
 
942
                                        };
 
943
                                        res.trials.push(tResults);
 
944
                                        doh.debug("\n\t\tTRIAL #: " +
 
945
                                                          tResults.trial + "\n\tTIME: " +
 
946
                                                          tResults.executionTime + "ms.\n\tAVG TEST TIME: " +
 
947
                                                          (tResults.executionTime/tResults.testIterations) + "ms.");
 
948
 
 
949
                                        //Okay, have we run all the trials yet?
 
950
                                        countdown--;
 
951
                                        if(countdown){
 
952
                                                doh.setTimeout(trialRunner, fixture.trialDelay);
 
953
                                        }else{
 
954
                                                //Okay, we're done, lets compute some final performance results.
 
955
                                                var t = res.trials;
 
956
 
 
957
 
 
958
 
 
959
                                                //We're done.
 
960
                                                fixture.endTime = new Date();
 
961
                                                def.callback(true);
 
962
                                        }
 
963
                                });
 
964
                                tTimer.addErrback(function(err){
 
965
                                        fixture.endTime = new Date();
 
966
                                        def.errback(err);
 
967
                                });
 
968
                                testRunner(tState);
 
969
                        };
 
970
                        trialRunner();
 
971
                }
 
972
        });
 
973
 
 
974
        //Set for a pause, returned the deferred.
 
975
        if(def.fired < 0){
 
976
                doh.pause();
 
977
        }
 
978
        return def;
 
979
};
 
980
 
 
981
doh._calcTrialIterations =  function(/*String*/ groupName, /*Object*/ fixture){
 
982
        //      summary:
 
983
        //              This function determines the rough number of iterations to
 
984
        //              use to reach a particular MS threshold.  This returns a deferred
 
985
        //              since tests can theoretically by async.  Async tests aren't going to
 
986
        //              give great perf #s, though.
 
987
        //              The callback is passed the # of iterations to hit the requested
 
988
        //              threshold.
 
989
        //
 
990
        //      fixture:
 
991
        //              The test fixture we want to calculate iterations for.
 
992
        var def = new doh.Deferred();
 
993
        var calibrate = function () {
 
994
                var testFunc = fixture.runTest;
 
995
 
 
996
                //Set the initial state.  We have to do this as a loop instead
 
997
                //of a recursive function.  Otherwise, it blows the call stack
 
998
                //on some browsers.
 
999
                var iState = {
 
1000
                        start: new Date(),
 
1001
                        curIter: 0,
 
1002
                        iterations: 5
 
1003
                };
 
1004
                var handleIteration = function(state){
 
1005
                        while(state){
 
1006
                                if(state.curIter < state.iterations){
 
1007
                                        try{
 
1008
                                                var ret = testFunc(doh);
 
1009
                                                if(ret instanceof doh.Deferred){
 
1010
                                                        var aState = {
 
1011
                                                                start: state.start,
 
1012
                                                                curIter: state.curIter + 1,
 
1013
                                                                iterations: state.iterations
 
1014
                                                        };
 
1015
                                                        ret.addCallback(function(){
 
1016
                                                                handleIteration(aState);
 
1017
                                                        });
 
1018
                                                        ret.addErrback(function(err) {
 
1019
                                                                fixture.endTime = new Date();
 
1020
                                                                def.errback(err);
 
1021
                                                        });
 
1022
                                                        state = null;
 
1023
                                                }else{
 
1024
                                                        state.curIter++;
 
1025
                                                }
 
1026
                                        }catch(err){
 
1027
                                                fixture.endTime = new Date();
 
1028
                                                def.errback(err);
 
1029
                                                return;
 
1030
                                        }
 
1031
                                }else{
 
1032
                                        var end = new Date();
 
1033
                                        var totalTime = (end.getTime() - state.start.getTime());
 
1034
                                        if(totalTime < fixture.trialDuration){
 
1035
                                                var nState = {
 
1036
                                                        iterations: state.iterations * 2,
 
1037
                                                        curIter: 0
 
1038
                                                }
 
1039
                                                state = null;
 
1040
                                                doh.setTimeout(function(){
 
1041
                                                        nState.start = new Date();
 
1042
                                                        handleIteration(nState);
 
1043
                                                }, 50);
 
1044
                                        }else{
 
1045
                                                var itrs = state.iterations;
 
1046
                                                doh.setTimeout(function(){def.callback(itrs)}, 50);
 
1047
                                                state = null;
 
1048
                                        }
 
1049
                                }
 
1050
                        }
 
1051
                };
 
1052
                handleIteration(iState);
 
1053
        };
 
1054
        doh.setTimeout(calibrate, 10);
 
1055
        return def;
 
1056
};
 
1057
 
 
1058
doh._runRegFixture = function(/*String*/groupName, /*Object*/fixture){
 
1059
        //      summary:
 
1060
        //              Function to run a generic doh test.  These are not
 
1061
        //              specialized tests, like performance groups and such.
 
1062
        //
 
1063
        //      groupName:
 
1064
        //              The groupName of the test.
 
1065
        //      fixture:
 
1066
        //              The test fixture to execute.
 
1067
        var tg = this._groups[groupName];
 
1068
        fixture.startTime = new Date();
 
1069
        var ret = fixture.runTest(this);
 
1070
        fixture.endTime = new Date();
 
1071
        // if we get a deferred back from the test runner, we know we're
 
1072
        // gonna wait for an async result. It's up to the test code to trap
 
1073
        // errors and give us an errback or callback.
 
1074
        if(ret instanceof doh.Deferred){
 
1075
                tg.inFlight++;
 
1076
                ret.groupName = groupName;
 
1077
                ret.fixture = fixture;
 
1078
 
 
1079
                ret.addErrback(function(err){
 
1080
                        doh._handleFailure(groupName, fixture, err);
 
1081
                });
 
1082
 
 
1083
                var retEnd = function(){
 
1084
                        if(fixture["tearDown"]){ fixture.tearDown(doh); }
 
1085
                        tg.inFlight--;
 
1086
                        if((!tg.inFlight)&&(tg.iterated)){
 
1087
                                doh._groupFinished(groupName, !tg.failures);
 
1088
                        }
 
1089
                        doh._testFinished(groupName, fixture, ret.results[0]);
 
1090
                        if(doh._paused){
 
1091
                                doh.run();
 
1092
                        }
 
1093
                }
 
1094
 
 
1095
                var timer = doh.setTimeout(function(){
 
1096
                        // ret.cancel();
 
1097
                        // retEnd();
 
1098
                        ret.errback(new Error("test timeout in "+fixture.name.toString()));
 
1099
                }, fixture["timeout"]||1000);
 
1100
 
 
1101
                ret.addBoth(function(arg){
 
1102
                        clearTimeout(timer);
 
1103
                        retEnd();
 
1104
                });
 
1105
                if(ret.fired < 0){
 
1106
                        doh.pause();
 
1107
                }
 
1108
                return ret;
 
1109
        }
 
1110
};
 
1111
 
 
1112
doh._runFixture = function(groupName, fixture){
 
1113
        var tg = this._groups[groupName];
 
1114
        this._testStarted(groupName, fixture);
 
1115
        var threw = false;
 
1116
        var err = null;
 
1117
        // run it, catching exceptions and reporting them
 
1118
        try{
 
1119
                // let doh reference "this.group.thinger..." which can be set by
 
1120
                // another test or group-level setUp function
 
1121
                fixture.group = tg;
 
1122
                // only execute the parts of the fixture we've got
 
1123
 
 
1124
                if(fixture["setUp"]){ fixture.setUp(this); }
 
1125
                if(fixture["runTest"]){  // should we error out of a fixture doesn't have a runTest?
 
1126
                        if(fixture.testType === "perf"){
 
1127
                                //Always async deferred, so return it.
 
1128
                                return doh._runPerfFixture(groupName, fixture);
 
1129
                        }else{
 
1130
                                //May or may not by async.
 
1131
                                var ret = doh._runRegFixture(groupName, fixture);
 
1132
                                if(ret){
 
1133
                                        return ret;
 
1134
                                }
 
1135
                        }
 
1136
                }
 
1137
                if(fixture["tearDown"]){ fixture.tearDown(this); }
 
1138
        }catch(e){
 
1139
                threw = true;
 
1140
                err = e;
 
1141
                if(!fixture.endTime){
 
1142
                        fixture.endTime = new Date();
 
1143
                }
 
1144
        }
 
1145
        var d = new doh.Deferred();
 
1146
        doh.setTimeout(this.hitch(this, function(){
 
1147
                if(threw){
 
1148
                        this._handleFailure(groupName, fixture, err);
 
1149
                }
 
1150
                this._testFinished(groupName, fixture, !threw);
 
1151
 
 
1152
                if((!tg.inFlight)&&(tg.iterated)){
 
1153
                        doh._groupFinished(groupName, !tg.failures);
 
1154
                }else if(tg.inFlight > 0){
 
1155
                        doh.setTimeout(this.hitch(this, function(){
 
1156
                                doh.runGroup(groupName); // , idx);
 
1157
                        }), 100);
 
1158
                        this._paused = true;
 
1159
                }
 
1160
                if(doh._paused){
 
1161
                        doh.run();
 
1162
                }
 
1163
        }), 30);
 
1164
        doh.pause();
 
1165
        return d;
 
1166
}
 
1167
 
 
1168
doh._testId = 0;
 
1169
doh.runGroup = function(/*String*/ groupName, /*Integer*/ idx){
 
1170
        // summary:
 
1171
        //              runs the specified test group
 
1172
 
 
1173
        // the general structure of the algorithm is to run through the group's
 
1174
        // list of doh, checking before and after each of them to see if we're in
 
1175
        // a paused state. This can be caused by the test returning a deferred or
 
1176
        // the user hitting the pause button. In either case, we want to halt
 
1177
        // execution of the test until something external to us restarts it. This
 
1178
        // means we need to pickle off enough state to pick up where we left off.
 
1179
 
 
1180
        // FIXME: need to make fixture execution async!!
 
1181
 
 
1182
        var tg = this._groups[groupName];
 
1183
        if(tg.skip === true){ return; }
 
1184
        if(this._isArray(tg)){
 
1185
                if(idx<=tg.length){
 
1186
                        if((!tg.inFlight)&&(tg.iterated == true)){
 
1187
                                if(tg["tearDown"]){ tg.tearDown(this); }
 
1188
                                doh._groupFinished(groupName, !tg.failures);
 
1189
                                return;
 
1190
                        }
 
1191
                }
 
1192
                if(!idx){
 
1193
                        tg.inFlight = 0;
 
1194
                        tg.iterated = false;
 
1195
                        tg.failures = 0;
 
1196
                }
 
1197
                doh._groupStarted(groupName);
 
1198
                if(!idx){
 
1199
                        this._setupGroupForRun(groupName, idx);
 
1200
                        if(tg["setUp"]){ tg.setUp(this); }
 
1201
                }
 
1202
                for(var y=(idx||0); y<tg.length; y++){
 
1203
                        if(this._paused){
 
1204
                                this._currentTest = y;
 
1205
                                // this.debug("PAUSED at:", tg[y].name, this._currentGroup, this._currentTest);
 
1206
                                return;
 
1207
                        }
 
1208
                        doh._runFixture(groupName, tg[y]);
 
1209
                        if(this._paused){
 
1210
                                this._currentTest = y+1;
 
1211
                                if(this._currentTest == tg.length){
 
1212
                                        tg.iterated = true;
 
1213
                                }
 
1214
                                // this.debug("PAUSED at:", tg[y].name, this._currentGroup, this._currentTest);
 
1215
                                return;
 
1216
                        }
 
1217
                }
 
1218
                tg.iterated = true;
 
1219
                if(!tg.inFlight){
 
1220
                        if(tg["tearDown"]){ tg.tearDown(this); }
 
1221
                        doh._groupFinished(groupName, !tg.failures);
 
1222
                }
 
1223
        }
 
1224
}
 
1225
 
 
1226
doh._onEnd = function(){}
 
1227
 
 
1228
doh._report = function(){
 
1229
        // summary:
 
1230
        //              a private method to be implemented/replaced by the "locally
 
1231
        //              appropriate" test runner
 
1232
 
 
1233
        // this.debug("ERROR:");
 
1234
        // this.debug("\tNO REPORTING OUTPUT AVAILABLE.");
 
1235
        // this.debug("\tIMPLEMENT doh._report() IN YOUR TEST RUNNER");
 
1236
 
 
1237
        this.debug(this._line);
 
1238
        this.debug("| TEST SUMMARY:");
 
1239
        this.debug(this._line);
 
1240
        this.debug("\t", this._testCount, "tests in", this._groupCount, "groups");
 
1241
        this.debug("\t", this._errorCount, "errors");
 
1242
        this.debug("\t", this._failureCount, "failures");
 
1243
}
 
1244
 
 
1245
doh.togglePaused = function(){
 
1246
        this[(this._paused) ? "run" : "pause"]();
 
1247
}
 
1248
 
 
1249
doh.pause = function(){
 
1250
        // summary:
 
1251
        //              halt test run. Can be resumed.
 
1252
        this._paused = true;
 
1253
}
 
1254
 
 
1255
doh.run = function(){
 
1256
        // summary:
 
1257
        //              begins or resumes the test process.
 
1258
        // this.debug("STARTING");
 
1259
        this._paused = false;
 
1260
        var cg = this._currentGroup;
 
1261
        var ct = this._currentTest;
 
1262
        var found = false;
 
1263
        if(!cg){
 
1264
                this._init(); // we weren't paused
 
1265
                found = true;
 
1266
        }
 
1267
        this._currentGroup = null;
 
1268
        this._currentTest = null;
 
1269
 
 
1270
        for(var x in this._groups){
 
1271
                if(
 
1272
                        ( (!found)&&(x == cg) )||( found )
 
1273
                ){
 
1274
                        if(this._paused){ return; }
 
1275
                        this._currentGroup = x;
 
1276
                        if(!found){
 
1277
                                found = true;
 
1278
                                this.runGroup(x, ct);
 
1279
                        }else{
 
1280
                                this.runGroup(x);
 
1281
                        }
 
1282
                        if(this._paused){ return; }
 
1283
                }
 
1284
        }
 
1285
        this._currentGroup = null;
 
1286
        this._currentTest = null;
 
1287
        this._paused = false;
 
1288
        this._onEnd();
 
1289
        this._report();
 
1290
}
 
1291
 
 
1292
//Statistics functions to handle computing performance metrics.
 
1293
//Taken from dojox.math
 
1294
//      basic statistics
 
1295
doh.standardDeviation = function(/* Number[] */a){
 
1296
        //      summary:
 
1297
        //              Returns the standard deviation of the passed arguments.
 
1298
        return Math.sqrt(this.variance(a));     //      Number
 
1299
};
 
1300
 
 
1301
doh.variance = function(/* Number[] */a){
 
1302
        //      summary:
 
1303
        //              Find the variance in the passed array of numbers.
 
1304
        var mean=0, squares=0;
 
1305
        dojo.forEach(a, function(item){
 
1306
                mean+=item;
 
1307
                squares+=Math.pow(item,2);
 
1308
        });
 
1309
        return (squares/a.length)-Math.pow(mean/a.length, 2);   //      Number
 
1310
};
 
1311
 
 
1312
doh.mean = function(/* Number[] */a){
 
1313
        //      summary:
 
1314
        //              Returns the mean value in the passed array.
 
1315
        var t=0;
 
1316
        dojo.forEach(a, function(v){
 
1317
                t += v;
 
1318
        });
 
1319
        return t / Math.max(a.length, 1);       //      Number
 
1320
};
 
1321
 
 
1322
doh.min = function(/* Number[] */a){
 
1323
        //      summary:
 
1324
        //              Returns the min value in the passed array.
 
1325
        return Math.min.apply(null, a);         //      Number
 
1326
};
 
1327
 
 
1328
doh.max = function(/* Number[] */a){
 
1329
        //      summary:
 
1330
        //              Returns the max value in the passed array.
 
1331
        return Math.max.apply(null, a);         //      Number
 
1332
},
 
1333
 
 
1334
doh.median= function(/* Number[] */a){
 
1335
        //      summary:
 
1336
        //              Returns the value closest to the middle from a sorted version of the passed array.
 
1337
        return a.slice(0).sort()[Math.ceil(a.length/2)-1];      //      Number
 
1338
},
 
1339
 
 
1340
doh.mode = function(/* Number[] */a){
 
1341
        //      summary:
 
1342
        //              Returns the mode from the passed array (number that appears the most often).
 
1343
        //              This is not the most efficient method, since it requires a double scan, but
 
1344
        //              is ensures accuracy.
 
1345
        var o = {}, r = 0, m = Number.MIN_VALUE;
 
1346
        dojo.forEach(a, function(v){
 
1347
                (o[v]!==undefined)?o[v]++:o[v]=1;
 
1348
        });
 
1349
 
 
1350
        //      we did the lookup map because we need the number that appears the most.
 
1351
        for(var p in o){
 
1352
                if(m < o[p]){
 
1353
                        m = o[p], r = p;
 
1354
                }
 
1355
        }
 
1356
        return r;       //      Number
 
1357
};
 
1358
 
 
1359
doh.average = function(/* Number [] */ a){
 
1360
        var i;
 
1361
        var s = 0;
 
1362
        for(i = 0; i < a.length; i++){
 
1363
                s += a[i];
 
1364
        }
 
1365
        return s/a.length;
 
1366
}
 
1367
 
 
1368
tests = doh;
 
1369
 
 
1370
if (typeof skipDohSetup === "undefined") {
 
1371
 
 
1372
    (function(){
 
1373
            // scope protection
 
1374
            var x;
 
1375
            try{
 
1376
                    if(typeof dojo != "undefined"){
 
1377
                            dojo.platformRequire({
 
1378
                                    browser: ["doh._browserRunner"],
 
1379
                                    rhino: ["doh._rhinoRunner"],
 
1380
                                    spidermonkey: ["doh._rhinoRunner"]
 
1381
                            });
 
1382
                            try{
 
1383
                                    var _shouldRequire = dojo.isBrowser ? (dojo.global == dojo.global["parent"] || !Boolean(dojo.global.parent.doh) ) : true;
 
1384
                            }catch(e){
 
1385
                                    //can't access dojo.global.parent.doh, then we need to do require
 
1386
                                    _shouldRequire = true;
 
1387
                            }
 
1388
                            if(_shouldRequire){
 
1389
                                    if(dojo.isBrowser){
 
1390
                                            dojo.addOnLoad(function(){
 
1391
                                                    if (dojo.global.registerModulePath){
 
1392
                                                            dojo.forEach(dojo.global.registerModulePath, function(m){
 
1393
                                                                    dojo.registerModulePath(m[0], m[1]);
 
1394
                                                            });
 
1395
                                                    }
 
1396
                                                    if(dojo.byId("testList")){
 
1397
                                                            var _tm = ( (dojo.global.testModule && dojo.global.testModule.length) ? dojo.global.testModule : "dojo.tests.module");
 
1398
                                                            dojo.forEach(_tm.split(","), dojo.require, dojo);
 
1399
                                                            doh.setTimeout(function(){
 
1400
                                                                    doh.run();
 
1401
                                                            }, 500);
 
1402
                                                    }
 
1403
                                            });
 
1404
                                    }else{
 
1405
                                            // dojo.require("doh._base");
 
1406
                                    }
 
1407
                            }
 
1408
                    }else{
 
1409
                            if(typeof load == "function" &&
 
1410
                                    (typeof Packages == "function" || typeof Packages == "object")){
 
1411
                                    throw new Error();
 
1412
                            }else if(typeof load == "function"){
 
1413
                                    throw new Error();
 
1414
                            }
 
1415
 
 
1416
                            if(this["document"]){
 
1417
                                    /*
 
1418
                                    // if we survived all of that, we're probably in a browser but
 
1419
                                    // don't have Dojo handy. Load _browserRunner.js using a
 
1420
                                    // document.write() call.
 
1421
 
 
1422
                                    // find runner.js, load _browserRunner relative to it
 
1423
                                    var scripts = document.getElementsByTagName("script"), runnerFile;
 
1424
                                    for(x=0; x<scripts.length; x++){
 
1425
                                            var s = scripts[x].src;
 
1426
                                            if(s){
 
1427
                                                    if(!runnerFile && s.substr(s.length - 9) == "runner.js"){
 
1428
                                                            runnerFile = s;
 
1429
                                                    }else if(s.substr(s.length - 17) == "_browserRunner.js"){
 
1430
                                                            runnerFile = null;
 
1431
                                                            break;
 
1432
                                                    }
 
1433
                                            }
 
1434
                                    }
 
1435
                                    if(runnerFile){
 
1436
                                            document.write("<scri"+"pt src='" + runnerFile.substr(0, runnerFile.length - 9)
 
1437
                                                    + "_browserRunner.js' type='text/javascript'></scr"+"ipt>");
 
1438
                                    }
 
1439
                                    */
 
1440
                            }
 
1441
                    }
 
1442
            }catch(e){
 
1443
                    print("\n"+doh._line);
 
1444
                    print("The Dojo Unit Test Harness, $Rev: 20389 $");
 
1445
                    print("Copyright (c) 2009, The Dojo Foundation, All Rights Reserved");
 
1446
                    print(doh._line, "\n");
 
1447
 
 
1448
                    try{
 
1449
                            var dojoUrl = "../../dojo/dojo.js";
 
1450
                            var testUrl = "";
 
1451
                            var testModule = "dojo.tests.module";
 
1452
                            var dohBase = "";
 
1453
                            for(x=0; x<arguments.length; x++){
 
1454
                                    if(arguments[x].indexOf("=") > 0){
 
1455
                                            var tp = arguments[x].split("=");
 
1456
                                            if(tp[0] == "dohBase"){
 
1457
                                                    dohBase = tp[1];
 
1458
                                                    //Convert slashes to unix style and make sure properly
 
1459
                                                    //ended.
 
1460
                                                    dohBase = dohBase.replace(/\\/g, "/");
 
1461
                                                    if(dohBase.charAt(dohBase.length - 1) != "/"){
 
1462
                                                            dohBase += "/";
 
1463
                                                    }
 
1464
                                            }
 
1465
                                            if(tp[0] == "dojoUrl"){
 
1466
                                                    dojoUrl = tp[1];
 
1467
                                            }
 
1468
                                            if(tp[0] == "testUrl"){
 
1469
                                                    testUrl = tp[1];
 
1470
                                            }
 
1471
                                            if(tp[0] == "testModule"){
 
1472
                                                    testModule = tp[1];
 
1473
                                            }
 
1474
                                    }
 
1475
                            }
 
1476
 
 
1477
                            load(dohBase + "_rhinoRunner.js");
 
1478
 
 
1479
                            if(dojoUrl.length){
 
1480
                                    if(!this["djConfig"]){
 
1481
                                            djConfig = {};
 
1482
                                    }
 
1483
                                    djConfig.baseUrl = dojoUrl.split("dojo.js")[0];
 
1484
                                    load(dojoUrl);
 
1485
                            }
 
1486
                            if(testUrl.length){
 
1487
                                    load(testUrl);
 
1488
                            }
 
1489
                            if(testModule.length){
 
1490
                                    dojo.forEach(testModule.split(","), dojo.require, dojo);
 
1491
                            }
 
1492
                    }catch(e){
 
1493
                            print("An exception occurred: " + e);
 
1494
                    }
 
1495
 
 
1496
                    doh.run();
 
1497
            }
 
1498
    }).apply(this, typeof arguments != "undefined" ? arguments : [null]);
 
1499
}