source: tol/TolJava/WebTOLJavaDEMO/web/sh/tests/js/qunit.js @ 9887b93

1941-docker-image-to-testdevel
Last change on this file since 9887b93 was 9887b93, checked in by Humberto Carralero <hacarralero@…>, 15 years ago

Importing TolJava

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@3900 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 28.4 KB
Line 
1/*
2 * QUnit - A JavaScript Unit Testing Framework
3 *
4 * http://docs.jquery.com/QUnit
5 *
6 * Copyright (c) 2009 John Resig, Jörn Zaefferer
7 * Dual licensed under the MIT (MIT-LICENSE.txt)
8 * and GPL (GPL-LICENSE.txt) licenses.
9 */
10
11(function(window) {
12
13var QUnit = {
14
15        // Initialize the configuration options
16        init: function() {
17                config = {
18                        stats: { all: 0, bad: 0 },
19                        moduleStats: { all: 0, bad: 0 },
20                        started: +new Date,
21                        updateRate: 1000,
22                        blocking: false,
23                        autorun: false,
24                        assertions: [],
25                        filters: [],
26                        queue: []
27                };
28
29                var tests = id("qunit-tests"),
30                        banner = id("qunit-banner"),
31                        result = id("qunit-testresult");
32
33                if ( tests ) {
34                        tests.innerHTML = "";
35                }
36
37                if ( banner ) {
38                        banner.className = "";
39                }
40
41                if ( result ) {
42                        result.parentNode.removeChild( result );
43                }
44        },
45       
46        // call on start of module test to prepend name to all tests
47        module: function(name, testEnvironment) {
48                config.currentModule = name;
49
50                synchronize(function() {
51                        if ( config.currentModule ) {
52                                QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
53                        }
54
55                        config.currentModule = name;
56                        config.moduleTestEnvironment = testEnvironment;
57                        config.moduleStats = { all: 0, bad: 0 };
58
59                        QUnit.moduleStart( name, testEnvironment );
60                });
61        },
62
63        asyncTest: function(testName, expected, callback) {
64                if ( arguments.length === 2 ) {
65                        callback = expected;
66                        expected = 0;
67                }
68
69                QUnit.test(testName, expected, callback, true);
70        },
71       
72        test: function(testName, expected, callback, async) {
73                var name = testName, testEnvironment, testEnvironmentArg;
74
75                if ( arguments.length === 2 ) {
76                        callback = expected;
77                        expected = null;
78                }
79                // is 2nd argument a testEnvironment?
80                if ( expected && typeof expected === 'object') {
81                        testEnvironmentArg =  expected;
82                        expected = null;
83                }
84
85                if ( config.currentModule ) {
86                        name = config.currentModule + " module: " + name;
87                }
88
89                if ( !validTest(name) ) {
90                        return;
91                }
92
93                synchronize(function() {
94                        QUnit.testStart( testName );
95
96                        testEnvironment = extend({
97                                setup: function() {},
98                                teardown: function() {}
99                        }, config.moduleTestEnvironment);
100                        if (testEnvironmentArg) {
101                                extend(testEnvironment,testEnvironmentArg);
102                        }
103
104                        // allow utility functions to access the current test environment
105                        QUnit.current_testEnvironment = testEnvironment;
106                       
107                        config.assertions = [];
108                        config.expected = expected;
109
110                        try {
111                                if ( !config.pollution ) {
112                                        saveGlobal();
113                                }
114
115                                testEnvironment.setup.call(testEnvironment);
116                        } catch(e) {
117                                QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
118                        }
119
120                        if ( async ) {
121                                QUnit.stop();
122                        }
123
124                        try {
125                                callback.call(testEnvironment);
126                        } catch(e) {
127                                fail("Test " + name + " died, exception and test follows", e, callback);
128                                QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
129                                // else next test will carry the responsibility
130                                saveGlobal();
131
132                                // Restart the tests if they're blocking
133                                if ( config.blocking ) {
134                                        start();
135                                }
136                        }
137                });
138
139                synchronize(function() {
140                        try {
141                                checkPollution();
142                                testEnvironment.teardown.call(testEnvironment);
143                        } catch(e) {
144                                QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
145                        }
146
147                        try {
148                                QUnit.reset();
149                        } catch(e) {
150                                fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
151                        }
152
153                        if ( config.expected && config.expected != config.assertions.length ) {
154                                QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
155                        }
156
157                        var good = 0, bad = 0,
158                                tests = id("qunit-tests");
159
160                        config.stats.all += config.assertions.length;
161                        config.moduleStats.all += config.assertions.length;
162
163                        if ( tests ) {
164                                var ol  = document.createElement("ol");
165                                ol.style.display = "none";
166
167                                for ( var i = 0; i < config.assertions.length; i++ ) {
168                                        var assertion = config.assertions[i];
169
170                                        var li = document.createElement("li");
171                                        li.className = assertion.result ? "pass" : "fail";
172                                        li.appendChild(document.createTextNode(assertion.message || "(no message)"));
173                                        ol.appendChild( li );
174
175                                        if ( assertion.result ) {
176                                                good++;
177                                        } else {
178                                                bad++;
179                                                config.stats.bad++;
180                                                config.moduleStats.bad++;
181                                        }
182                                }
183
184                                var b = document.createElement("strong");
185                                b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
186                               
187                                addEvent(b, "click", function() {
188                                        var next = b.nextSibling, display = next.style.display;
189                                        next.style.display = display === "none" ? "block" : "none";
190                                });
191                               
192                                addEvent(b, "dblclick", function(e) {
193                                        var target = e && e.target ? e.target : window.event.srcElement;
194                                        if ( target.nodeName.toLowerCase() === "strong" ) {
195                                                var text = "", node = target.firstChild;
196
197                                                while ( node.nodeType === 3 ) {
198                                                        text += node.nodeValue;
199                                                        node = node.nextSibling;
200                                                }
201
202                                                text = text.replace(/(^\s*|\s*$)/g, "");
203
204                                                if ( window.location ) {
205                                                        window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
206                                                }
207                                        }
208                                });
209
210                                var li = document.createElement("li");
211                                li.className = bad ? "fail" : "pass";
212                                li.appendChild( b );
213                                li.appendChild( ol );
214                                tests.appendChild( li );
215
216                                if ( bad ) {
217                                        var toolbar = id("qunit-testrunner-toolbar");
218                                        if ( toolbar ) {
219                                                toolbar.style.display = "block";
220                                                id("qunit-filter-pass").disabled = null;
221                                                id("qunit-filter-missing").disabled = null;
222                                        }
223                                }
224
225                        } else {
226                                for ( var i = 0; i < config.assertions.length; i++ ) {
227                                        if ( !config.assertions[i].result ) {
228                                                bad++;
229                                                config.stats.bad++;
230                                                config.moduleStats.bad++;
231                                        }
232                                }
233                        }
234
235                        QUnit.testDone( testName, bad, config.assertions.length );
236
237                        if ( !window.setTimeout && !config.queue.length ) {
238                                done();
239                        }
240                });
241
242                if ( window.setTimeout && !config.doneTimer ) {
243                        config.doneTimer = window.setTimeout(function(){
244                                if ( !config.queue.length ) {
245                                        done();
246                                } else {
247                                        synchronize( done );
248                                }
249                        }, 13);
250                }
251        },
252       
253        /**
254         * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
255         */
256        expect: function(asserts) {
257                config.expected = asserts;
258        },
259
260        /**
261         * Asserts true.
262         * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
263         */
264        ok: function(a, msg) {
265                QUnit.log(a, msg);
266
267                config.assertions.push({
268                        result: !!a,
269                        message: msg
270                });
271        },
272
273        /**
274         * Checks that the first two arguments are equal, with an optional message.
275         * Prints out both actual and expected values.
276         *
277         * Prefered to ok( actual == expected, message )
278         *
279         * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
280         *
281         * @param Object actual
282         * @param Object expected
283         * @param String message (optional)
284         */
285        equal: function(actual, expected, message) {
286                push(expected == actual, actual, expected, message);
287        },
288
289        notEqual: function(actual, expected, message) {
290                push(expected != actual, actual, expected, message);
291        },
292       
293        deepEqual: function(a, b, message) {
294                push(QUnit.equiv(a, b), a, b, message);
295        },
296
297        notDeepEqual: function(a, b, message) {
298                push(!QUnit.equiv(a, b), a, b, message);
299        },
300
301        strictEqual: function(actual, expected, message) {
302                push(expected === actual, actual, expected, message);
303        },
304
305        notStrictEqual: function(actual, expected, message) {
306                push(expected !== actual, actual, expected, message);
307        },
308       
309        start: function() {
310                // A slight delay, to avoid any current callbacks
311                if ( window.setTimeout ) {
312                        window.setTimeout(function() {
313                                if ( config.timeout ) {
314                                        clearTimeout(config.timeout);
315                                }
316
317                                config.blocking = false;
318                                process();
319                        }, 13);
320                } else {
321                        config.blocking = false;
322                        process();
323                }
324        },
325       
326        stop: function(timeout) {
327                config.blocking = true;
328
329                if ( timeout && window.setTimeout ) {
330                        config.timeout = window.setTimeout(function() {
331                                QUnit.ok( false, "Test timed out" );
332                                QUnit.start();
333                        }, timeout);
334                }
335        },
336       
337        /**
338         * Resets the test setup. Useful for tests that modify the DOM.
339         */
340        reset: function() {
341                if ( window.jQuery ) {
342                        jQuery("#main").html( config.fixture );
343                        jQuery.event.global = {};
344                        jQuery.ajaxSettings = extend({}, config.ajaxSettings);
345                }
346        },
347       
348        /**
349         * Trigger an event on an element.
350         *
351         * @example triggerEvent( document.body, "click" );
352         *
353         * @param DOMElement elem
354         * @param String type
355         */
356        triggerEvent: function( elem, type, event ) {
357                if ( document.createEvent ) {
358                        event = document.createEvent("MouseEvents");
359                        event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
360                                0, 0, 0, 0, 0, false, false, false, false, 0, null);
361                        elem.dispatchEvent( event );
362
363                } else if ( elem.fireEvent ) {
364                        elem.fireEvent("on"+type);
365                }
366        },
367       
368        // Safe object type checking
369        is: function( type, obj ) {
370                return Object.prototype.toString.call( obj ) === "[object "+ type +"]";
371        },
372       
373        // Logging callbacks
374        done: function(failures, total) {},
375        log: function(result, message) {},
376        testStart: function(name) {},
377        testDone: function(name, failures, total) {},
378        moduleStart: function(name, testEnvironment) {},
379        moduleDone: function(name, failures, total) {}
380};
381
382// Backwards compatibility, deprecated
383QUnit.equals = QUnit.equal;
384QUnit.same = QUnit.deepEqual;
385
386// Maintain internal state
387var config = {
388        // The queue of tests to run
389        queue: [],
390
391        // block until document ready
392        blocking: true
393};
394
395// Load paramaters
396(function() {
397        var location = window.location || { search: "", protocol: "file:" },
398                GETParams = location.search.slice(1).split('&');
399
400        for ( var i = 0; i < GETParams.length; i++ ) {
401                GETParams[i] = decodeURIComponent( GETParams[i] );
402                if ( GETParams[i] === "noglobals" ) {
403                        GETParams.splice( i, 1 );
404                        i--;
405                        config.noglobals = true;
406                } else if ( GETParams[i].search('=') > -1 ) {
407                        GETParams.splice( i, 1 );
408                        i--;
409                }
410        }
411       
412        // restrict modules/tests by get parameters
413        config.filters = GETParams;
414       
415        // Figure out if we're running the tests from a server or not
416        QUnit.isLocal = !!(location.protocol === 'file:');
417})();
418
419// Expose the API as global variables, unless an 'exports'
420// object exists, in that case we assume we're in CommonJS
421if ( typeof exports === "undefined" || typeof require === "undefined" ) {
422        extend(window, QUnit);
423        window.QUnit = QUnit;
424} else {
425        extend(exports, QUnit);
426        exports.QUnit = QUnit;
427}
428
429if ( typeof document === "undefined" || document.readyState === "complete" ) {
430        config.autorun = true;
431}
432
433addEvent(window, "load", function() {
434        // Initialize the config, saving the execution queue
435        var oldconfig = extend({}, config);
436        QUnit.init();
437        extend(config, oldconfig);
438
439        config.blocking = false;
440
441        var userAgent = id("qunit-userAgent");
442        if ( userAgent ) {
443                userAgent.innerHTML = navigator.userAgent;
444        }
445       
446        var toolbar = id("qunit-testrunner-toolbar");
447        if ( toolbar ) {
448                toolbar.style.display = "none";
449               
450                var filter = document.createElement("input");
451                filter.type = "checkbox";
452                filter.id = "qunit-filter-pass";
453                filter.disabled = true;
454                addEvent( filter, "click", function() {
455                        var li = document.getElementsByTagName("li");
456                        for ( var i = 0; i < li.length; i++ ) {
457                                if ( li[i].className.indexOf("pass") > -1 ) {
458                                        li[i].style.display = filter.checked ? "none" : "";
459                                }
460                        }
461                });
462                toolbar.appendChild( filter );
463
464                var label = document.createElement("label");
465                label.setAttribute("for", "qunit-filter-pass");
466                label.innerHTML = "Hide passed tests";
467                toolbar.appendChild( label );
468
469                var missing = document.createElement("input");
470                missing.type = "checkbox";
471                missing.id = "qunit-filter-missing";
472                missing.disabled = true;
473                addEvent( missing, "click", function() {
474                        var li = document.getElementsByTagName("li");
475                        for ( var i = 0; i < li.length; i++ ) {
476                                if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
477                                        li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
478                                }
479                        }
480                });
481                toolbar.appendChild( missing );
482
483                label = document.createElement("label");
484                label.setAttribute("for", "qunit-filter-missing");
485                label.innerHTML = "Hide missing tests (untested code is broken code)";
486                toolbar.appendChild( label );
487        }
488
489        var main = id('main');
490        if ( main ) {
491                config.fixture = main.innerHTML;
492        }
493
494        if ( window.jQuery ) {
495                config.ajaxSettings = window.jQuery.ajaxSettings;
496        }
497
498        QUnit.start();
499});
500
501function done() {
502        if ( config.doneTimer && window.clearTimeout ) {
503                window.clearTimeout( config.doneTimer );
504                config.doneTimer = null;
505        }
506
507        if ( config.queue.length ) {
508                config.doneTimer = window.setTimeout(function(){
509                        if ( !config.queue.length ) {
510                                done();
511                        } else {
512                                synchronize( done );
513                        }
514                }, 13);
515
516                return;
517        }
518
519        config.autorun = true;
520
521        // Log the last module results
522        if ( config.currentModule ) {
523                QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
524        }
525
526        var banner = id("qunit-banner"),
527                tests = id("qunit-tests"),
528                html = ['Tests completed in ',
529                +new Date - config.started, ' milliseconds.<br/>',
530                '<span class="passed">', config.stats.all - config.stats.bad, '</span> tests of <span class="total">', config.stats.all, '</span> passed, <span class="failed">', config.stats.bad,'</span> failed.'].join('');
531
532        if ( banner ) {
533                banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
534        }
535
536        if ( tests ) { 
537                var result = id("qunit-testresult");
538
539                if ( !result ) {
540                        result = document.createElement("p");
541                        result.id = "qunit-testresult";
542                        result.className = "result";
543                        tests.parentNode.insertBefore( result, tests.nextSibling );
544                }
545
546                result.innerHTML = html;
547        }
548
549        QUnit.done( config.stats.bad, config.stats.all );
550}
551
552function validTest( name ) {
553        var i = config.filters.length,
554                run = false;
555
556        if ( !i ) {
557                return true;
558        }
559       
560        while ( i-- ) {
561                var filter = config.filters[i],
562                        not = filter.charAt(0) == '!';
563
564                if ( not ) {
565                        filter = filter.slice(1);
566                }
567
568                if ( name.indexOf(filter) !== -1 ) {
569                        return !not;
570                }
571
572                if ( not ) {
573                        run = true;
574                }
575        }
576
577        return run;
578}
579
580function push(result, actual, expected, message) {
581        message = message || (result ? "okay" : "failed");
582        QUnit.ok( result, result ? message + ": " + QUnit.jsDump.parse(expected) : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
583}
584
585function synchronize( callback ) {
586        config.queue.push( callback );
587
588        if ( config.autorun && !config.blocking ) {
589                process();
590        }
591}
592
593function process() {
594        var start = (new Date()).getTime();
595
596        while ( config.queue.length && !config.blocking ) {
597                if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
598                        config.queue.shift()();
599
600                } else {
601                        setTimeout( process, 13 );
602                        break;
603                }
604        }
605}
606
607function saveGlobal() {
608        config.pollution = [];
609       
610        if ( config.noglobals ) {
611                for ( var key in window ) {
612                        config.pollution.push( key );
613                }
614        }
615}
616
617function checkPollution( name ) {
618        var old = config.pollution;
619        saveGlobal();
620       
621        var newGlobals = diff( old, config.pollution );
622        if ( newGlobals.length > 0 ) {
623                ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
624                config.expected++;
625        }
626
627        var deletedGlobals = diff( config.pollution, old );
628        if ( deletedGlobals.length > 0 ) {
629                ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
630                config.expected++;
631        }
632}
633
634// returns a new Array with the elements that are in a but not in b
635function diff( a, b ) {
636        var result = a.slice();
637        for ( var i = 0; i < result.length; i++ ) {
638                for ( var j = 0; j < b.length; j++ ) {
639                        if ( result[i] === b[j] ) {
640                                result.splice(i, 1);
641                                i--;
642                                break;
643                        }
644                }
645        }
646        return result;
647}
648
649function fail(message, exception, callback) {
650        if ( typeof console !== "undefined" && console.error && console.warn ) {
651                console.error(message);
652                console.error(exception);
653                console.warn(callback.toString());
654
655        } else if ( window.opera && opera.postError ) {
656                opera.postError(message, exception, callback.toString);
657        }
658}
659
660function extend(a, b) {
661        for ( var prop in b ) {
662                a[prop] = b[prop];
663        }
664
665        return a;
666}
667
668function addEvent(elem, type, fn) {
669        if ( elem.addEventListener ) {
670                elem.addEventListener( type, fn, false );
671        } else if ( elem.attachEvent ) {
672                elem.attachEvent( "on" + type, fn );
673        } else {
674                fn();
675        }
676}
677
678function id(name) {
679        return !!(typeof document !== "undefined" && document && document.getElementById) &&
680                document.getElementById( name );
681}
682
683// Test for equality any JavaScript type.
684// Discussions and reference: http://philrathe.com/articles/equiv
685// Test suites: http://philrathe.com/tests/equiv
686// Author: Philippe Rathé <prathe@gmail.com>
687QUnit.equiv = function () {
688
689    var innerEquiv; // the real equiv function
690    var callers = []; // stack to decide between skip/abort functions
691    var parents = []; // stack to avoiding loops from circular referencing
692
693
694    // Determine what is o.
695    function hoozit(o) {
696        if (QUnit.is("String", o)) {
697            return "string";
698           
699        } else if (QUnit.is("Boolean", o)) {
700            return "boolean";
701
702        } else if (QUnit.is("Number", o)) {
703
704            if (isNaN(o)) {
705                return "nan";
706            } else {
707                return "number";
708            }
709
710        } else if (typeof o === "undefined") {
711            return "undefined";
712
713        // consider: typeof null === object
714        } else if (o === null) {
715            return "null";
716
717        // consider: typeof [] === object
718        } else if (QUnit.is( "Array", o)) {
719            return "array";
720       
721        // consider: typeof new Date() === object
722        } else if (QUnit.is( "Date", o)) {
723            return "date";
724
725        // consider: /./ instanceof Object;
726        //           /./ instanceof RegExp;
727        //          typeof /./ === "function"; // => false in IE and Opera,
728        //                                          true in FF and Safari
729        } else if (QUnit.is( "RegExp", o)) {
730            return "regexp";
731
732        } else if (typeof o === "object") {
733            return "object";
734
735        } else if (QUnit.is( "Function", o)) {
736            return "function";
737        } else {
738            return undefined;
739        }
740    }
741
742    // Call the o related callback with the given arguments.
743    function bindCallbacks(o, callbacks, args) {
744        var prop = hoozit(o);
745        if (prop) {
746            if (hoozit(callbacks[prop]) === "function") {
747                return callbacks[prop].apply(callbacks, args);
748            } else {
749                return callbacks[prop]; // or undefined
750            }
751        }
752    }
753   
754    var callbacks = function () {
755
756        // for string, boolean, number and null
757        function useStrictEquality(b, a) {
758            if (b instanceof a.constructor || a instanceof b.constructor) {
759                // to catch short annotaion VS 'new' annotation of a declaration
760                // e.g. var i = 1;
761                //      var j = new Number(1);
762                return a == b;
763            } else {
764                return a === b;
765            }
766        }
767
768        return {
769            "string": useStrictEquality,
770            "boolean": useStrictEquality,
771            "number": useStrictEquality,
772            "null": useStrictEquality,
773            "undefined": useStrictEquality,
774
775            "nan": function (b) {
776                return isNaN(b);
777            },
778
779            "date": function (b, a) {
780                return hoozit(b) === "date" && a.valueOf() === b.valueOf();
781            },
782
783            "regexp": function (b, a) {
784                return hoozit(b) === "regexp" &&
785                    a.source === b.source && // the regex itself
786                    a.global === b.global && // and its modifers (gmi) ...
787                    a.ignoreCase === b.ignoreCase &&
788                    a.multiline === b.multiline;
789            },
790
791            // - skip when the property is a method of an instance (OOP)
792            // - abort otherwise,
793            //   initial === would have catch identical references anyway
794            "function": function () {
795                var caller = callers[callers.length - 1];
796                return caller !== Object &&
797                        typeof caller !== "undefined";
798            },
799
800            "array": function (b, a) {
801                var i, j, loop;
802                var len;
803
804                // b could be an object literal here
805                if ( ! (hoozit(b) === "array")) {
806                    return false;
807                }   
808               
809                len = a.length;
810                if (len !== b.length) { // safe and faster
811                    return false;
812                }
813               
814                //track reference to avoid circular references
815                parents.push(a);
816                for (i = 0; i < len; i++) {
817                    loop = false;
818                    for(j=0;j<parents.length;j++){
819                        if(parents[j] === a[i]){
820                            loop = true;//dont rewalk array
821                        }
822                    }
823                    if (!loop && ! innerEquiv(a[i], b[i])) {
824                        parents.pop();
825                        return false;
826                    }
827                }
828                parents.pop();
829                return true;
830            },
831
832            "object": function (b, a) {
833                var i, j, loop;
834                var eq = true; // unless we can proove it
835                var aProperties = [], bProperties = []; // collection of strings
836
837                // comparing constructors is more strict than using instanceof
838                if ( a.constructor !== b.constructor) {
839                    return false;
840                }
841
842                // stack constructor before traversing properties
843                callers.push(a.constructor);
844                //track reference to avoid circular references
845                parents.push(a);
846               
847                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
848                    loop = false;
849                    for(j=0;j<parents.length;j++){
850                        if(parents[j] === a[i])
851                            loop = true; //don't go down the same path twice
852                    }
853                    aProperties.push(i); // collect a's properties
854
855                    if (!loop && ! innerEquiv(a[i], b[i])) {
856                        eq = false;
857                        break;
858                    }
859                }
860
861                callers.pop(); // unstack, we are done
862                parents.pop();
863
864                for (i in b) {
865                    bProperties.push(i); // collect b's properties
866                }
867
868                // Ensures identical properties name
869                return eq && innerEquiv(aProperties.sort(), bProperties.sort());
870            }
871        };
872    }();
873
874    innerEquiv = function () { // can take multiple arguments
875        var args = Array.prototype.slice.apply(arguments);
876        if (args.length < 2) {
877            return true; // end transition
878        }
879
880        return (function (a, b) {
881            if (a === b) {
882                return true; // catch the most you can
883            } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
884                return false; // don't lose time with error prone cases
885            } else {
886                return bindCallbacks(a, callbacks, [b, a]);
887            }
888
889        // apply transition with (1..n) arguments
890        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
891    };
892
893    return innerEquiv;
894
895}();
896
897/**
898 * jsDump
899 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
900 * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
901 * Date: 5/15/2008
902 * @projectDescription Advanced and extensible data dumping for Javascript.
903 * @version 1.0.0
904 * @author Ariel Flesler
905 * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
906 */
907QUnit.jsDump = (function() {
908        function quote( str ) {
909                return '"' + str.toString().replace(/"/g, '\\"') + '"';
910        };
911        function literal( o ) {
912                return o + ''; 
913        };
914        function join( pre, arr, post ) {
915                var s = jsDump.separator(),
916                        base = jsDump.indent(),
917                        inner = jsDump.indent(1);
918                if ( arr.join )
919                        arr = arr.join( ',' + s + inner );
920                if ( !arr )
921                        return pre + post;
922                return [ pre, inner + arr, base + post ].join(s);
923        };
924        function array( arr ) {
925                var i = arr.length,     ret = Array(i);                                 
926                this.up();
927                while ( i-- )
928                        ret[i] = this.parse( arr[i] );                         
929                this.down();
930                return join( '[', ret, ']' );
931        };
932       
933        var reName = /^function (\w+)/;
934       
935        var jsDump = {
936                parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
937                        var     parser = this.parsers[ type || this.typeOf(obj) ];
938                        type = typeof parser;                   
939                       
940                        return type == 'function' ? parser.call( this, obj ) :
941                                   type == 'string' ? parser :
942                                   this.parsers.error;
943                },
944                typeOf:function( obj ) {
945                        var type;
946                        if ( obj === null ) {
947                                type = "null";
948                        } else if (typeof obj === "undefined") {
949                                type = "undefined";
950                        } else if (QUnit.is("RegExp", obj)) {
951                                type = "regexp";
952                        } else if (QUnit.is("Date", obj)) {
953                                type = "date";
954                        } else if (QUnit.is("Function", obj)) {
955                                type = "function";
956                        } else if (obj.setInterval && obj.document && !obj.nodeType) {
957                                type = "window";
958                        } else if (obj.nodeType === 9) {
959                                type = "document";
960                        } else if (obj.nodeType) {
961                                type = "node";
962                        } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
963                                type = "array";
964                        } else {
965                                type = typeof obj;
966                        }
967                        return type;
968                },
969                separator:function() {
970                        return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
971                },
972                indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
973                        if ( !this.multiline )
974                                return '';
975                        var chr = this.indentChar;
976                        if ( this.HTML )
977                                chr = chr.replace(/\t/g,'   ').replace(/ /g,'&nbsp;');
978                        return Array( this._depth_ + (extra||0) ).join(chr);
979                },
980                up:function( a ) {
981                        this._depth_ += a || 1;
982                },
983                down:function( a ) {
984                        this._depth_ -= a || 1;
985                },
986                setParser:function( name, parser ) {
987                        this.parsers[name] = parser;
988                },
989                // The next 3 are exposed so you can use them
990                quote:quote,
991                literal:literal,
992                join:join,
993                //
994                _depth_: 1,
995                // This is the list of parsers, to modify them, use jsDump.setParser
996                parsers:{
997                        window: '[Window]',
998                        document: '[Document]',
999                        error:'[ERROR]', //when no parser is found, shouldn't happen
1000                        unknown: '[Unknown]',
1001                        'null':'null',
1002                        undefined:'undefined',
1003                        'function':function( fn ) {
1004                                var ret = 'function',
1005                                        name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
1006                                if ( name )
1007                                        ret += ' ' + name;
1008                                ret += '(';
1009                               
1010                                ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
1011                                return join( ret, this.parse(fn,'functionCode'), '}' );
1012                        },
1013                        array: array,
1014                        nodelist: array,
1015                        arguments: array,
1016                        object:function( map ) {
1017                                var ret = [ ];
1018                                this.up();
1019                                for ( var key in map )
1020                                        ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
1021                                this.down();
1022                                return join( '{', ret, '}' );
1023                        },
1024                        node:function( node ) {
1025                                var open = this.HTML ? '&lt;' : '<',
1026                                        close = this.HTML ? '&gt;' : '>';
1027                                       
1028                                var tag = node.nodeName.toLowerCase(),
1029                                        ret = open + tag;
1030                                       
1031                                for ( var a in this.DOMAttrs ) {
1032                                        var val = node[this.DOMAttrs[a]];
1033                                        if ( val )
1034                                                ret += ' ' + a + '=' + this.parse( val, 'attribute' );
1035                                }
1036                                return ret + close + open + '/' + tag + close;
1037                        },
1038                        functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
1039                                var l = fn.length;
1040                                if ( !l ) return '';                           
1041                               
1042                                var args = Array(l);
1043                                while ( l-- )
1044                                        args[l] = String.fromCharCode(97+l);//97 is 'a'
1045                                return ' ' + args.join(', ') + ' ';
1046                        },
1047                        key:quote, //object calls it internally, the key part of an item in a map
1048                        functionCode:'[code]', //function calls it internally, it's the content of the function
1049                        attribute:quote, //node calls it internally, it's an html attribute value
1050                        string:quote,
1051                        date:quote,
1052                        regexp:literal, //regex
1053                        number:literal,
1054                        'boolean':literal
1055                },
1056                DOMAttrs:{//attributes to dump from nodes, name=>realName
1057                        id:'id',
1058                        name:'name',
1059                        'class':'className'
1060                },
1061                HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
1062                indentChar:'   ',//indentation unit
1063                multiline:false //if true, items in a collection, are separated by a \n, else just a space.
1064        };
1065
1066        return jsDump;
1067})();
1068
1069})(this);
Note: See TracBrowser for help on using the repository browser.