Вход Регистрация
Файл: framework/thirdparty/jquery-validate/test/qunit/qunit.js
Строк: 1661
<?php
/*
 * QUnit - A JavaScript Unit Testing Framework
 * 
 * http://docs.jquery.com/QUnit
 *
 * Copyright (c) 2011 John Resig, Jörn Zaefferer
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * or GPL (GPL-LICENSE.txt) licenses.
 */

(function(window) {

var 
defined = {
    
setTimeouttypeof window.setTimeout !== "undefined",
    
sessionStorage: (function() {
        try {
            return !!
sessionStorage.getItem;
        } catch(
e){
            return 
false;
        }
  })()
}

var 
testId 0;

var 
Test = function(nametestNameexpectedtestEnvironmentArgasynccallback) {
    
this.name name;
    
this.testName testName;
    
this.expected expected;
    
this.testEnvironmentArg testEnvironmentArg;
    
this.async async;
    
this.callback callback;
    
this.assertions = [];
};
Test.prototype = {
    
init: function() {
        var 
tests id("qunit-tests");
        if (
tests) {
            var 
document.createElement("strong");
                
b.innerHTML "Running " this.name;
            var 
li document.createElement("li");
                
li.appendChild);
                
li.id this.id "test-output" testId++;
            
tests.appendChildli );
        }
    },
    
setup: function() {
        if (
this.module != config.previousModule) {
            if ( 
config.previousModule ) {
                
QUnit.moduleDone( {
                    
nameconfig.previousModule,
                    
failedconfig.moduleStats.bad,
                    
passedconfig.moduleStats.all config.moduleStats.bad,
                    
totalconfig.moduleStats.all
                
} );
            }
            
config.previousModule this.module;
            
config.moduleStats = { all0bad};
            
QUnit.moduleStart( {
                
namethis.module
            
} );
        }

        
config.current this;
        
this.testEnvironment extend({
            
setup: function() {},
            
teardown: function() {}
        }, 
this.moduleTestEnvironment);
        if (
this.testEnvironmentArg) {
            
extend(this.testEnvironmentthis.testEnvironmentArg);
        }

        
QUnit.testStart( {
            
namethis.testName
        
} );

        
// allow utility functions to access the current test environment
        // TODO why??
        
QUnit.current_testEnvironment this.testEnvironment;
        
        try {
            if ( !
config.pollution ) {
                
saveGlobal();
            }

            
this.testEnvironment.setup.call(this.testEnvironment);
        } catch(
e) {
            
QUnit.okfalse"Setup failed on " this.testName ": " e.message );
        }
    },
    
run: function() {
        if ( 
this.async ) {
            
QUnit.stop();
        }

        if ( 
config.notrycatch ) {
            
this.callback.call(this.testEnvironment);
            return;
        }
        try {
            
this.callback.call(this.testEnvironment);
        } catch(
e) {
            
fail("Test " this.testName " died, exception and test follows"ethis.callback);
            
QUnit.okfalse"Died on test #" + (this.assertions.length 1) + ": " e.message " - " QUnit.jsDump.parse(e) );
            
// else next test will carry the responsibility
            
saveGlobal();

            
// Restart the tests if they're blocking
            
if ( config.blocking ) {
                
start();
            }
        }
    },
    
teardown: function() {
        try {
            
checkPollution();
            
this.testEnvironment.teardown.call(this.testEnvironment);
        } catch(
e) {
            
QUnit.okfalse"Teardown failed on " this.testName ": " e.message );
        }
    },
    
finish: function() {
        if ( 
this.expected && this.expected != this.assertions.length ) {
            
QUnit.okfalse"Expected " this.expected " assertions, but " this.assertions.length " were run" );
        }
        
        var 
good 0bad 0,
            
tests id("qunit-tests");

        
config.stats.all += this.assertions.length;
        
config.moduleStats.all += this.assertions.length;

        if ( 
tests ) {
            var 
ol  document.createElement("ol");

            for ( var 
0this.assertions.lengthi++ ) {
                var 
assertion this.assertions[i];

                var 
li document.createElement("li");
                
li.className assertion.result "pass" "fail";
                
li.innerHTML assertion.message || (assertion.result "okay" "failed");
                
ol.appendChildli );

                if ( 
assertion.result ) {
                    
good++;
                } else {
                    
bad++;
                    
config.stats.bad++;
                    
config.moduleStats.bad++;
                }
            }

            
// store result when possible
            
defined.sessionStorage && sessionStorage.setItem("qunit-" this.testNamebad);

            if (
bad == 0) {
                
ol.style.display "none";
            }

            var 
document.createElement("strong");
            
b.innerHTML this.name " <b class='counts'>(<b class='failed'>" bad "</b>, <b class='passed'>" good "</b>, " this.assertions.length ")</b>";
            
            
addEvent(b"click", function() {
                var 
next b.nextSiblingdisplay next.style.display;
                
next.style.display display === "none" "block" "none";
            });
            
            
addEvent(b"dblclick", function(e) {
                var 
target && e.target e.target window.event.srcElement;
                if ( 
target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
                    
target target.parentNode;
                }
                if ( 
window.location && target.nodeName.toLowerCase() === "strong" ) {
                    
window.location.search "?" encodeURIComponent(getText([target]).replace(/(.+)$/, "").replace(/(^s*|s*$)/g""));
                }
            });

            var 
li id(this.id);
            
li.className bad "fail" "pass";
            
li.style.display resultDisplayStyle(!bad);
            
li.removeChildli.firstChild );
            
li.appendChild);
            
li.appendChildol );

        } else {
            for ( var 
0this.assertions.lengthi++ ) {
                if ( !
this.assertions[i].result ) {
                    
bad++;
                    
config.stats.bad++;
                    
config.moduleStats.bad++;
                }
            }
        }

        try {
            
QUnit.reset();
        } catch(
e) {
            
fail("reset() failed, following Test " this.testName ", exception and reset fn follows"eQUnit.reset);
        }

        
QUnit.testDone( {
            
namethis.testName,
            
failedbad,
            
passedthis.assertions.length bad,
            
totalthis.assertions.length
        
} );
    },
    
    
queue: function() {
        var 
test this;
        
synchronize(function() {
            
test.init();
        });
        function 
run() {
            
// each of these can by async
            
synchronize(function() {
                
test.setup();
            });
            
synchronize(function() {
                
test.run();
            });
            
synchronize(function() {
                
test.teardown();
            });
            
synchronize(function() {
                
test.finish();
            });
        }
        
// defer when previous test run passed, if storage is available
        
var bad defined.sessionStorage && +sessionStorage.getItem("qunit-" this.testName);
        if (
bad) {
            
run();
        } else {
            
synchronize(run);
        };
    }
    
}

var 
QUnit = {

    
// call on start of module test to prepend name to all tests
    
module: function(nametestEnvironment) {
        
config.currentModule name;
        
config.currentModuleTestEnviroment testEnvironment;
    },

    
asyncTest: function(testNameexpectedcallback) {
        if ( 
arguments.length === ) {
            
callback expected;
            
expected 0;
        }

        
QUnit.test(testNameexpectedcallbacktrue);
    },
    
    
test: function(testNameexpectedcallbackasync) {
        var 
name '<span class="test-name">' testName '</span>'testEnvironmentArg;

        if ( 
arguments.length === ) {
            
callback expected;
            
expected null;
        }
        
// is 2nd argument a testEnvironment?
        
if ( expected && typeof expected === 'object') {
            
testEnvironmentArg =  expected;
            
expected null;
        }

        if ( 
config.currentModule ) {
            
name '<span class="module-name">' config.currentModule "</span>: " name;
        }

        if ( !
validTest(config.currentModule ": " testName) ) {
            return;
        }
        
        var 
test = new Test(nametestNameexpectedtestEnvironmentArgasynccallback);
        
test.module config.currentModule;
        
test.moduleTestEnvironment config.currentModuleTestEnviroment;
        
test.queue();
    },
    
    
/**
     * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
     */
    
expect: function(asserts) {
        
config.current.expected asserts;
    },

    
/**
     * Asserts true.
     * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
     */
    
ok: function(amsg) {
        
= !!a;
        var 
details = {
            
resulta,
            
messagemsg
        
};
        
msg escapeHtml(msg);
        
QUnit.log(details);
        
config.current.assertions.push({
            
resulta,
            
messagemsg
        
});
    },

    
/**
     * Checks that the first two arguments are equal, with an optional message.
     * Prints out both actual and expected values.
     *
     * Prefered to ok( actual == expected, message )
     *
     * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
     *
     * @param Object actual
     * @param Object expected
     * @param String message (optional)
     */
    
equal: function(actualexpectedmessage) {
        
QUnit.push(expected == actualactualexpectedmessage);
    },

    
notEqual: function(actualexpectedmessage) {
        
QUnit.push(expected != actualactualexpectedmessage);
    },
    
    
deepEqual: function(actualexpectedmessage) {
        
QUnit.push(QUnit.equiv(actualexpected), actualexpectedmessage);
    },

    
notDeepEqual: function(actualexpectedmessage) {
        
QUnit.push(!QUnit.equiv(actualexpected), actualexpectedmessage);
    },

    
strictEqual: function(actualexpectedmessage) {
        
QUnit.push(expected === actualactualexpectedmessage);
    },

    
notStrictEqual: function(actualexpectedmessage) {
        
QUnit.push(expected !== actualactualexpectedmessage);
    },

    
raises: function(blockexpectedmessage) {
        var 
actualok false;
    
        if (
typeof expected === 'string') {
            
message expected;
            
expected null;
        }
    
        try {
            
block();
        } catch (
e) {
            
actual e;
        }
    
        if (
actual) {
            
// we don't want to validate thrown error
            
if (!expected) {
                
ok true;
            
// expected is a regexp    
            
} else if (QUnit.objectType(expected) === "regexp") {
                
ok expected.test(actual);
            
// expected is a constructor    
            
} else if (actual instanceof expected) {
                
ok true;
            
// expected is a validation function which returns true is validation passed    
            
} else if (expected.call({}, actual) === true) {
                
ok true;
            }
        }
            
        
QUnit.ok(okmessage);
    },

    
start: function() {
        
config.semaphore--;
        if (
config.semaphore 0) {
            
// don't start until equal number of stop-calls
            
return;
        }
        if (
config.semaphore 0) {
            
// ignore if start is called more often then stop
            
config.semaphore 0;
        }
        
// A slight delay, to avoid any current callbacks
        
if ( defined.setTimeout ) {
            
window.setTimeout(function() {
                if ( 
config.timeout ) {
                    
clearTimeout(config.timeout);
                }

                
config.blocking false;
                
process();
            }, 
13);
        } else {
            
config.blocking false;
            
process();
        }
    },
    
    
stop: function(timeout) {
        
config.semaphore++;
        
config.blocking true;

        if ( 
timeout && defined.setTimeout ) {
            
clearTimeout(config.timeout);
            
config.timeout window.setTimeout(function() {
                
QUnit.okfalse"Test timed out" );
                
QUnit.start();
            }, 
timeout);
        }
    }

};

// Backwards compatibility, deprecated
QUnit.equals QUnit.equal;
QUnit.same QUnit.deepEqual;

// Maintain internal state
var config = {
    
// The queue of tests to run
    
queue: [],

    
// block until document ready
    
blockingtrue
};

// Load paramaters
(function() {
    var 
location window.location || { search""protocol"file:" },
        
GETParams location.search.slice(1).split('&');

    for ( var 
0GETParams.lengthi++ ) {
        
GETParams[i] = decodeURIComponentGETParams[i] );
        if ( 
GETParams[i] === "noglobals" ) {
            
GETParams.splicei);
            
i--;
            
config.noglobals true;
        } else if ( 
GETParams[i] === "notrycatch" ) {
            
GETParams.splicei);
            
i--;
            
config.notrycatch true;
        } else if ( 
GETParams[i].search('=') > -) {
            
GETParams.splicei);
            
i--;
        }
    }
    
    
// restrict modules/tests by get parameters
    
config.filters GETParams;
    
    
// Figure out if we're running the tests from a server or not
    
QUnit.isLocal = !!(location.protocol === 'file:');
})();

// Expose the API as global variables, unless an 'exports'
// object exists, in that case we assume we're in CommonJS
if ( typeof exports === "undefined" || typeof require === "undefined" ) {
    
extend(windowQUnit);
    
window.QUnit QUnit;
} else {
    
extend(exportsQUnit);
    
exports.QUnit QUnit;
}

// define these after exposing globals to keep them in these QUnit namespace only
extend(QUnit, {
    
configconfig,

    
// Initialize the configuration options
    
init: function() {
        
extend(config, {
            
stats: { all0bad},
            
moduleStats: { all0bad},
            
started: +new Date,
            
updateRate1000,
            
blockingfalse,
            
autostarttrue,
            
autorunfalse,
            
filters: [],
            
queue: [],
            
semaphore0
        
});

        var 
tests id("qunit-tests"),
            
banner id("qunit-banner"),
            
result id("qunit-testresult");

        if ( 
tests ) {
            
tests.innerHTML "";
        }

        if ( 
banner ) {
            
banner.className "";
        }

        if ( 
result ) {
            
result.parentNode.removeChildresult );
        }
    },
    
    
/**
     * Resets the test setup. Useful for tests that modify the DOM.
     * 
     * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
     */
    
reset: function() {
        if ( 
window.jQuery ) {
            
jQuery"#main, #qunit-fixture" ).htmlconfig.fixture );
        } else {
            var 
main id'main' ) || id'qunit-fixture' );
            if ( 
main ) {
                
main.innerHTML config.fixture;
            }
        }
    },
    
    
/**
     * Trigger an event on an element.
     *
     * @example triggerEvent( document.body, "click" );
     *
     * @param DOMElement elem
     * @param String type
     */
    
triggerEvent: function( elemtypeevent ) {
        if ( 
document.createEvent ) {
            
event document.createEvent("MouseEvents");
            
event.initMouseEvent(typetruetrueelem.ownerDocument.defaultView,
                
00000falsefalsefalsefalse0null);
            
elem.dispatchEventevent );

        } else if ( 
elem.fireEvent ) {
            
elem.fireEvent("on"+type);
        }
    },
    
    
// Safe object type checking
    
is: function( typeobj ) {
        return 
QUnit.objectTypeobj ) == type;
    },
    
    
objectType: function( obj ) {
        if (
typeof obj === "undefined") {
                return 
"undefined";

        
// consider: typeof null === object
        
}
        if (
obj === null) {
                return 
"null";
        }

        var 
type Object.prototype.toString.callobj )
            .
match(/^[objects(.*)]$/)[1] || '';

        switch (
type) {
                case 
'Number':
                        if (
isNaN(obj)) {
                                return 
"nan";
                        } else {
                                return 
"number";
                        }
                case 
'String':
                case 
'Boolean':
                case 
'Array':
                case 
'Date':
                case 
'RegExp':
                case 
'Function':
                        return 
type.toLowerCase();
        }
        if (
typeof obj === "object") {
                return 
"object";
        }
        return 
undefined;
    },
    
    
push: function(resultactualexpectedmessage) {
        var 
details = {
            
resultresult,
            
messagemessage,
            
actualactual,
            
expectedexpected
        
};
        
        
message escapeHtml(message) || (result "okay" "failed");
        
message '<span class="test-message">' message "</span>";
        
expected escapeHtml(QUnit.jsDump.parse(expected));
        
actual escapeHtml(QUnit.jsDump.parse(actual));
        var 
output message '<table><tr class="test-expected"><th>Expected: </th><td><pre>' expected '</pre></td></tr>';
        if (
actual != expected) {
            
output += '<tr class="test-actual"><th>Result: </th><td><pre>' actual '</pre></td></tr>';
            
output += '<tr class="test-diff"><th>Diff: </th><td><pre>' QUnit.diff(expectedactual) +'</pre></td></tr>';
        }
        if (!
result) {
            var 
source sourceFromStacktrace();
            if (
source) {
                
details.source source;
                
output += '<tr class="test-source"><th>Source: </th><td><pre>' source +'</pre></td></tr>';
            }
        }
        
output += "</table>";
        
        
QUnit.log(details);
        
        
config.current.assertions.push({
            
result: !!result,
            
messageoutput
        
});
    },
    
    
// Logging callbacks; all receive a single argument with the listed properties
    // run test/logs.html for any related changes
    
begin: function() {},
    
// done: { failed, passed, total, runtime }
    
done: function() {},
    
// log: { result, actual, expected, message }
    
log: function() {},
    
// testStart: { name }
    
testStart: function() {},
    
// testDone: { name, failed, passed, total }
    
testDone: function() {},
    
// moduleStart: { name }
    
moduleStart: function() {},
    
// moduleDone: { name, failed, passed, total }
    
moduleDone: function() {}
});

if ( 
typeof document === "undefined" || document.readyState === "complete" ) {
    
config.autorun true;
}

addEvent(window"load", function() {
    
QUnit.begin({});
    
    
// Initialize the config, saving the execution queue
    
var oldconfig extend({}, config);
    
QUnit.init();
    
extend(configoldconfig);

    
config.blocking false;

    var 
userAgent id("qunit-userAgent");
    if ( 
userAgent ) {
        
userAgent.innerHTML navigator.userAgent;
    }
    var 
banner id("qunit-header");
    if ( 
banner ) {
        var 
paramsIndex location.href.lastIndexOf(location.search);
        if ( 
paramsIndex > -) {
            var 
mainPageLocation location.href.slice(0paramsIndex);
            if ( 
mainPageLocation == location.href ) {
                
banner.innerHTML '<a href=""> ' banner.innerHTML '</a> ';
            } else {
                var 
testName decodeURIComponent(location.search.slice(1));
                
banner.innerHTML '<a href="' mainPageLocation '">' banner.innerHTML '</a> &#8250; <a href="">' testName '</a>';
            }
        }
    }
    
    var 
toolbar id("qunit-testrunner-toolbar");
    if ( 
toolbar ) {
        var 
filter document.createElement("input");
        
filter.type "checkbox";
        
filter.id "qunit-filter-pass";
        
addEventfilter"click", function() {
            var 
li document.getElementsByTagName("li");
            for ( var 
0li.lengthi++ ) {
                if ( 
li[i].className.indexOf("pass") > -) {
                    
li[i].style.display filter.checked "none" "";
                }
            }
            if ( 
defined.sessionStorage ) {
                
sessionStorage.setItem("qunit-filter-passed-tests"filter.checked "true" "");
            }
        });
        if ( 
defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
            
filter.checked true;
        }
        
toolbar.appendChildfilter );

        var 
label document.createElement("label");
        
label.setAttribute("for""qunit-filter-pass");
        
label.innerHTML "Hide passed tests";
        
toolbar.appendChildlabel );
    }

    var 
main id('main') || id('qunit-fixture');
    if ( 
main ) {
        
config.fixture main.innerHTML;
    }

    if (
config.autostart) {
        
QUnit.start();
    }
});

function 
done() {
    
config.autorun true;

    
// Log the last module results
    
if ( config.currentModule ) {
        
QUnit.moduleDone( {
            
nameconfig.currentModule,
            
failedconfig.moduleStats.bad,
            
passedconfig.moduleStats.all config.moduleStats.bad,
            
totalconfig.moduleStats.all
        
} );
    }

    var 
banner id("qunit-banner"),
        
tests id("qunit-tests"),
        
runtime = +new Date config.started,
        
passed config.stats.all config.stats.bad,
        
html = [
            
'Tests completed in ',
            
runtime,
            
' milliseconds.<br/>',
            
'<span class="passed">',
            
passed,
            
'</span> tests of <span class="total">',
            
config.stats.all,
            
'</span> passed, <span class="failed">',
            
config.stats.bad,
            
'</span> failed.'
        
].join('');

    if ( 
banner ) {
        
banner.className = (config.stats.bad "qunit-fail" "qunit-pass");
    }

    if ( 
tests ) {    
        var 
result id("qunit-testresult");

        if ( !
result ) {
            
result document.createElement("p");
            
result.id "qunit-testresult";
            
result.className "result";
            
tests.parentNode.insertBeforeresulttests.nextSibling );
        }

        
result.innerHTML html;
    }

    
QUnit.done( {
        
failedconfig.stats.bad,
        
passedpassed
        
totalconfig.stats.all,
        
runtimeruntime
    
} );
}

function 
validTestname ) {
    var 
config.filters.length,
        
run false;

    if ( !
) {
        return 
true;
    }
    
    while ( 
i-- ) {
        var 
filter config.filters[i],
            
not filter.charAt(0) == '!';

        if ( 
not ) {
            
filter filter.slice(1);
        }

        if ( 
name.indexOf(filter) !== -) {
            return !
not;
        }

        if ( 
not ) {
            
run true;
        }
    }

    return 
run;
}

// so far supports only Firefox, Chrome and Opera (buggy)
// could be extended in the future to use something like https://github.com/csnover/TraceKit
function sourceFromStacktrace() {
    try {
        throw new 
Error();
    } catch ( 
) {
        if (
e.stacktrace) {
            
// Opera
            
return e.stacktrace.split("n")[6];
        } else if (
e.stack) {
            
// Firefox, Chrome
            
return e.stack.split("n")[4];
        }
    }
}

function 
resultDisplayStyle(passed) {
    return 
passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked 'none' '';
}

function 
escapeHtml(s) {
    if (!
s) {
        return 
"";
    }
    
"";
    return 
s.replace(/[&"<>\]/g, function(s) {
        switch(s) {
            case "
&": return "&amp;";
            case "
\": return "\\";
            case '"': return '"';
            case "
<": return "&lt;";
            case "
>": return "&gt;";
            default: return s;
        }
    });
}

function synchronize( callback ) {
    config.queue.push( callback );

    if ( config.autorun && !config.blocking ) {
        process();
    }
}

function process() {
    var start = (new Date()).getTime();
    while ( config.queue.length && !config.blocking ) {
        if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
            config.queue.shift()();
        } else {
            window.setTimeout( process, 13 );
            break;
        }
    }
  if (!config.blocking && !config.queue.length) {
    done();
  }
}

function saveGlobal() {
    config.pollution = [];
    
    if ( config.noglobals ) {
        for ( var key in window ) {
            config.pollution.push( key );
        }
    }
}

function checkPollution( name ) {
    var old = config.pollution;
    saveGlobal();
    
    var newGlobals = diff( old, config.pollution );
    if ( newGlobals.length > 0 ) {
        ok( false, "
Introduced global variable(s): " + newGlobals.join("") );
        config.current.expected++;
    }

    var deletedGlobals = diff( config.pollution, old );
    if ( deletedGlobals.length > 0 ) {
        ok( false, "
Deleted global variable(s): " + deletedGlobals.join("") );
        config.current.expected++;
    }
}

// returns a new Array with the elements that are in a but not in b
function diff( a, b ) {
    var result = a.slice();
    for ( var i = 0; i < result.length; i++ ) {
        for ( var j = 0; j < b.length; j++ ) {
            if ( result[i] === b[j] ) {
                result.splice(i, 1);
                i--;
                break;
            }
        }
    }
    return result;
}

function fail(message, exception, callback) {
    if ( typeof console !== "
undefined" && console.error && console.warn ) {
        console.error(message);
        console.error(exception);
        console.warn(callback.toString());

    } else if ( window.opera && opera.postError ) {
        opera.postError(message, exception, callback.toString);
    }
}

function extend(a, b) {
    for ( var prop in b ) {
        a[prop] = b[prop];
    }

    return a;
}

function addEvent(elem, type, fn) {
    if ( elem.addEventListener ) {
        elem.addEventListener( type, fn, false );
    } else if ( elem.attachEvent ) {
        elem.attachEvent( "
on" + type, fn );
    } else {
        fn();
    }
}

function id(name) {
    return !!(typeof document !== "
undefined" && document && document.getElementById) &&
        document.getElementById( name );
}

// Test for equality any JavaScript type.
// Discussions and reference: http://philrathe.com/articles/equiv
// Test suites: http://philrathe.com/tests/equiv
// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = function () {

    var innerEquiv; // the real equiv function
    var callers = []; // stack to decide between skip/abort functions
    var parents = []; // stack to avoiding loops from circular referencing

    // Call the o related callback with the given arguments.
    function bindCallbacks(o, callbacks, args) {
        var prop = QUnit.objectType(o);
        if (prop) {
            if (QUnit.objectType(callbacks[prop]) === "
function") {
                return callbacks[prop].apply(callbacks, args);
            } else {
                return callbacks[prop]; // or undefined
            }
        }
    }
    
    var callbacks = function () {

        // for string, boolean, number and null
        function useStrictEquality(b, a) {
            if (b instanceof a.constructor || a instanceof b.constructor) {
                // to catch short annotaion VS 'new' annotation of a declaration
                // e.g. var i = 1;
                //      var j = new Number(1);
                return a == b;
            } else {
                return a === b;
            }
        }

        return {
            "
string": useStrictEquality,
            "
boolean": useStrictEquality,
            "
number": useStrictEquality,
            "
null": useStrictEquality,
            "
undefined": useStrictEquality,

            "
nan": function (b) {
                return isNaN(b);
            },

            "
date": function (b, a) {
                return QUnit.objectType(b) === "
date" && a.valueOf() === b.valueOf();
            },

            "
regexp": function (b, a) {
                return QUnit.objectType(b) === "
regexp" &&
                    a.source === b.source && // the regex itself
                    a.global === b.global && // and its modifers (gmi) ...
                    a.ignoreCase === b.ignoreCase &&
                    a.multiline === b.multiline;
            },

            // - skip when the property is a method of an instance (OOP)
            // - abort otherwise,
            //   initial === would have catch identical references anyway
            "
function": function () {
                var caller = callers[callers.length - 1];
                return caller !== Object &&
                        typeof caller !== "
undefined";
            },

            "
array": function (b, a) {
                var i, j, loop;
                var len;

                // b could be an object literal here
                if ( ! (QUnit.objectType(b) === "
array")) {
                    return false;
                }   
                
                len = a.length;
                if (len !== b.length) { // safe and faster
                    return false;
                }
                
                //track reference to avoid circular references
                parents.push(a);
                for (i = 0; i < len; i++) {
                    loop = false;
                    for(j=0;j<parents.length;j++){
                        if(parents[j] === a[i]){
                            loop = true;//dont rewalk array
                        }
                    }
                    if (!loop && ! innerEquiv(a[i], b[i])) {
                        parents.pop();
                        return false;
                    }
                }
                parents.pop();
                return true;
            },

            "
object": function (b, a) {
                var i, j, loop;
                var eq = true; // unless we can proove it
                var aProperties = [], bProperties = []; // collection of strings

                // comparing constructors is more strict than using instanceof
                if ( a.constructor !== b.constructor) {
                    return false;
                }

                // stack constructor before traversing properties
                callers.push(a.constructor);
                //track reference to avoid circular references
                parents.push(a);
                
                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
                    loop = false;
                    for(j=0;j<parents.length;j++){
                        if(parents[j] === a[i])
                            loop = true; //don't go down the same path twice
                    }
                    aProperties.push(i); // collect a's properties

                    if (!loop && ! innerEquiv(a[i], b[i])) {
                        eq = false;
                        break;
                    }
                }

                callers.pop(); // unstack, we are done
                parents.pop();

                for (i in b) {
                    bProperties.push(i); // collect b's properties
                }

                // Ensures identical properties name
                return eq && innerEquiv(aProperties.sort(), bProperties.sort());
            }
        };
    }();

    innerEquiv = function () { // can take multiple arguments
        var args = Array.prototype.slice.apply(arguments);
        if (args.length < 2) {
            return true; // end transition
        }

        return (function (a, b) {
            if (a === b) {
                return true; // catch the most you can
            } else if (a === null || b === null || typeof a === "
undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
                return false; // don't lose time with error prone cases
            } else {
                return bindCallbacks(a, callbacks, [b, a]);
            }

        // apply transition with (1..n) arguments
        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
    };

    return innerEquiv;

}();

/**
 * jsDump
 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
 * Date: 5/15/2008
 * @projectDescription Advanced and extensible data dumping for Javascript.
 * @version 1.0.0
 * @author Ariel Flesler
 * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
 */
QUnit.jsDump = (function() {
    function quote( str ) {
        return '"' + str.toString().replace(/"/g, '
\"') + '"';
    };
    function literal( o ) {
        return o + '';    
    };
    function join( pre, arr, post ) {
        var s = jsDump.separator(),
            base = jsDump.indent(),
            inner = jsDump.indent(1);
        if ( arr.join )
            arr = arr.join( '
,' + s + inner );
        if ( !arr )
            return pre + post;
        return [ pre, inner + arr, base + post ].join(s);
    };
    function array( arr ) {
        var i = arr.length,    ret = Array(i);                    
        this.up();
        while ( i-- )
            ret[i] = this.parse( arr[i] );                
        this.down();
        return join( '
[', ret, ']' );
    };
    
    var reName = /^function (w+)/;
    
    var jsDump = {
        parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
            var    parser = this.parsers[ type || this.typeOf(obj) ];
            type = typeof parser;            
            
            return type == '
function' ? parser.call( this, obj ) :
                   type == '
string' ? parser :
                   this.parsers.error;
        },
        typeOf:function( obj ) {
            var type;
            if ( obj === null ) {
                type = "null";
            } else if (typeof obj === "undefined") {
                type = "undefined";
            } else if (QUnit.is("RegExp", obj)) {
                type = "regexp";
            } else if (QUnit.is("Date", obj)) {
                type = "date";
            } else if (QUnit.is("Function", obj)) {
                type = "function";
            } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
                type = "window";
            } else if (obj.nodeType === 9) {
                type = "document";
            } else if (obj.nodeType) {
                type = "node";
            } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
                type = "array";
            } else {
                type = typeof obj;
            }
            return type;
        },
        separator:function() {
            return this.multiline ?    this.HTML ? '
<br />' : 'n' : this.HTML ? '&nbsp;' : ' ';
        },
        indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
            if ( !this.multiline )
                return '';
            var chr = this.indentChar;
            if ( this.HTML )
                chr = chr.replace(/t/g,'   ').replace(/ /g,'
&nbsp;');
            return Array( this._depth_ + (extra||0) ).join(chr);
        },
        up:function( a ) {
            this._depth_ += a || 1;
        },
        down:function( a ) {
            this._depth_ -= a || 1;
        },
        setParser:function( name, parser ) {
            this.parsers[name] = parser;
        },
        // The next 3 are exposed so you can use them
        quote:quote, 
        literal:literal,
        join:join,
        //
        _depth_: 1,
        // This is the list of parsers, to modify them, use jsDump.setParser
        parsers:{
            window: '
[Window]',
            document: '
[Document]',
            error:'
[ERROR]', //when no parser is found, shouldn't happen
            unknown
'[Unknown]',
            
'null':'null',
            
undefined:'undefined',
            
'function':function( fn ) {
                var 
ret 'function',
                    
name 'name' in fn fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
                
if ( name )
                    
ret += ' ' name;
                
ret += '(';
                
                
ret = [ retQUnit.jsDump.parsefn'functionArgs' ), '){'].join('');
                return 
joinretQUnit.jsDump.parse(fn,'functionCode'), '}' );
            },
            array: array,
            
nodelist: array,
            
arguments: array,
            
object:function( map ) {
                var 
ret = [ ];
                
QUnit.jsDump.up();
                for ( var 
key in map )
                    
ret.pushQUnit.jsDump.parse(key,'key') + ': ' QUnit.jsDump.parse(map[key]) );
                
QUnit.jsDump.down();
                return 
join'{'ret'}' );
            },
            
node:function( node ) {
                var 
open QUnit.jsDump.HTML '&lt;' '<',
                    
close QUnit.jsDump.HTML '&gt;' '>';
                    
                var 
tag node.nodeName.toLowerCase(),
                    
ret open tag;
                    
                for ( var 
a in QUnit.jsDump.DOMAttrs ) {
                    var 
val node[QUnit.jsDump.DOMAttrs[a]];
                    if ( 
val )
                        
ret += ' ' '=' QUnit.jsDump.parseval'attribute' );
                }
                return 
ret close open '/' tag close;
            },
            
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
                
var fn.length;
                if ( !
) return '';                
                
                var 
args = Array(l);
                while ( 
l-- )
                    
args[l] = String.fromCharCode(97+l);//97 is 'a'
                
return ' ' args.join(', ') + ' ';
            },
            
key:quote//object calls it internally, the key part of an item in a map
            
functionCode:'[code]'//function calls it internally, it's the content of the function
            
attribute:quote//node calls it internally, it's an html attribute value
            
string:quote,
            
date:quote,
            
regexp:literal//regex
            
number:literal,
            
'boolean':literal
        
},
        
DOMAttrs:{//attributes to dump from nodes, name=>realName
            
id:'id',
            
name:'name',
            
'class':'className'
        
},
        
HTML:false,//if true, entities are escaped ( <, >, t, space and n )
        
indentChar:'  ',//indentation unit
        
multiline:true //if true, items in a collection, are separated by a n, else just a space.
    
};

    return 
jsDump;
})();

// from Sizzle.js
function getTextelems ) {
    var 
ret ""elem;

    for ( var 
0elems[i]; i++ ) {
        
elem elems[i];

        
// Get the text from text nodes and CDATA nodes
        
if ( elem.nodeType === || elem.nodeType === ) {
            
ret += elem.nodeValue;

        
// Traverse everything else, except comment nodes
        
} else if ( elem.nodeType !== ) {
            
ret += getTextelem.childNodes );
        }
    }

    return 
ret;
};

/*
 * Javascript Diff Algorithm
 *  By John Resig (http://ejohn.org/)
 *  Modified by Chu Alan "sprite"
 *
 * Released under the MIT license.
 *
 * More Info:
 *  http://ejohn.org/projects/javascript-diff-algorithm/
 *  
 * Usage: QUnit.diff(expected, actual)
 * 
 * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the  quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
 */
QUnit.diff = (function() {
    function 
diff(on){
        var 
ns = new Object();
        var 
os = new Object();
        
        for (var 
0n.lengthi++) {
            if (
ns[n[i]] == null
                
ns[n[i]] = {
                    
rows: new Array(),
                    
onull
                
};
            
ns[n[i]].rows.push(i);
        }
        
        for (var 
0o.lengthi++) {
            if (
os[o[i]] == null
                
os[o[i]] = {
                    
rows: new Array(),
                    
nnull
                
};
            
os[o[i]].rows.push(i);
        }
        
        for (var 
i in ns) {
            if (
ns[i].rows.length == && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
                
n[ns[i].rows[0]] = {
                    
textn[ns[i].rows[0]],
                    
rowos[i].rows[0]
                };
                
o[os[i].rows[0]] = {
                    
texto[os[i].rows[0]],
                    
rowns[i].rows[0]
                };
            }
        }
        
        for (var 
0n.length 1i++) {
            if (
n[i].text != null && n[1].text == null && n[i].row o.length && o[n[i].row 1].text == null &&
            
n[1] == o[n[i].row 1]) {
                
n[1] = {
                    
textn[1],
                    
rown[i].row 1
                
};
                
o[n[i].row 1] = {
                    
texto[n[i].row 1],
                    
row1
                
};
            }
        }
        
        for (var 
n.length 10i--) {
            if (
n[i].text != null && n[1].text == null && n[i].row && o[n[i].row 1].text == null &&
            
n[1] == o[n[i].row 1]) {
                
n[1] = {
                    
textn[1],
                    
rown[i].row 1
                
};
                
o[n[i].row 1] = {
                    
texto[n[i].row 1],
                    
row1
                
};
            }
        }
        
        return {
            
oo,
            
nn
        
};
    }
    
    return function(
on){
        
o.replace(/s+$/, '');
        
n.replace(/s+$/, '');
        var 
out diff(== "" ? [] : o.split(/s+/), == "" ? [] : n.split(/s+/));

        var 
str "";
        
        var 
oSpace o.match(/s+/g);
        if (
oSpace == null) {
            
oSpace = [" "];
        }
        else {
            
oSpace.push(" ");
        }
        var 
nSpace n.match(/s+/g);
        if (
nSpace == null) {
            
nSpace = [" "];
        }
        else {
            
nSpace.push(" ");
        }
        
        if (
out.n.length == 0) {
            for (var 
0out.o.lengthi++) {
                
str += '<del>' out.o[i] + oSpace[i] + "</del>";
            }
        }
        else {
            if (
out.n[0].text == null) {
                for (
0out.o.length && out.o[n].text == nulln++) {
                    
str += '<del>' out.o[n] + oSpace[n] + "</del>";
                }
            }
            
            for (var 
0out.n.lengthi++) {
                if (
out.n[i].text == null) {
                    
str += '<ins>' out.n[i] + nSpace[i] + "</ins>";
                }
                else {
                    var 
pre "";
                    
                    for (
out.n[i].row 1out.o.length && out.o[n].text == nulln++) {
                        
pre += '<del>' out.o[n] + oSpace[n] + "</del>";
                    }
                    
str += " " out.n[i].text nSpace[i] + pre;
                }
            }
        }
        
        return 
str;
    };
})();

})(
this);
?>
Онлайн: 1
Реклама