Upgrade QUnit to the current master

Exact commit ID: 96e42601cadcba989f80bd4c294b7e0ee4ff1d29
redux
David Majda 13 years ago
parent 468597be27
commit a92676edce

@ -1,7 +1,17 @@
/**
* 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.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
@ -74,10 +84,24 @@
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
@ -162,6 +186,14 @@
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
@ -174,7 +206,7 @@
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Footer */
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
@ -182,10 +214,7 @@
color: #2b81af;
background-color: #D2E0E6;
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
border-bottom: 1px solid white;
}
/** Fixture */

@ -1,4 +1,4 @@
/*
/**
* QUnit - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
@ -19,7 +19,7 @@ var defined = {
return false;
}
})()
}
};
var testId = 0;
@ -40,6 +40,7 @@ Test.prototype = {
b.innerHTML = "Running " + this.name;
var li = document.createElement("li");
li.appendChild( b );
li.className = "running";
li.id = this.id = "test-output" + testId++;
tests.appendChild( li );
}
@ -47,7 +48,7 @@ Test.prototype = {
setup: function() {
if (this.module != config.previousModule) {
if ( config.previousModule ) {
QUnit.moduleDone( {
runLoggingCallbacks('moduleDone', QUnit, {
name: config.previousModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
@ -56,7 +57,7 @@ Test.prototype = {
}
config.previousModule = this.module;
config.moduleStats = { all: 0, bad: 0 };
QUnit.moduleStart( {
runLoggingCallbacks( 'moduleStart', QUnit, {
name: this.module
} );
}
@ -70,7 +71,7 @@ Test.prototype = {
extend(this.testEnvironment, this.testEnvironmentArg);
}
QUnit.testStart( {
runLoggingCallbacks( 'testStart', QUnit, {
name: this.testName
} );
@ -113,8 +114,8 @@ Test.prototype = {
},
teardown: function() {
try {
checkPollution();
this.testEnvironment.teardown.call(this.testEnvironment);
checkPollution();
} catch(e) {
QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
}
@ -151,7 +152,13 @@ Test.prototype = {
}
// store result when possible
defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad);
if ( QUnit.config.reorder && defined.sessionStorage ) {
if (bad) {
sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
} else {
sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
}
}
if (bad == 0) {
ol.style.display = "none";
@ -160,8 +167,13 @@ Test.prototype = {
var b = document.createElement("strong");
b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
var a = document.createElement("a");
a.innerHTML = "Rerun";
a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
addEvent(b, "click", function() {
var next = b.nextSibling, display = next.style.display;
var next = b.nextSibling.nextSibling,
display = next.style.display;
next.style.display = display === "none" ? "block" : "none";
});
@ -171,15 +183,15 @@ Test.prototype = {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, ""));
window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
}
});
var li = id(this.id);
li.className = bad ? "fail" : "pass";
li.style.display = resultDisplayStyle(!bad);
li.removeChild( li.firstChild );
li.appendChild( b );
li.appendChild( a );
li.appendChild( ol );
} else {
@ -198,7 +210,7 @@ Test.prototype = {
fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
}
QUnit.testDone( {
runLoggingCallbacks( 'testDone', QUnit, {
name: this.testName,
failed: bad,
passed: this.assertions.length - bad,
@ -227,7 +239,7 @@ Test.prototype = {
});
}
// defer when previous test run passed, if storage is available
var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName);
var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
if (bad) {
run();
} else {
@ -235,7 +247,7 @@ Test.prototype = {
};
}
}
};
var QUnit = {
@ -299,7 +311,7 @@ var QUnit = {
message: msg
};
msg = escapeHtml(msg);
QUnit.log(details);
runLoggingCallbacks( 'log', QUnit, details );
config.current.assertions.push({
result: a,
message: msg
@ -388,6 +400,9 @@ var QUnit = {
// A slight delay, to avoid any current callbacks
if ( defined.setTimeout ) {
window.setTimeout(function() {
if (config.semaphore > 0) {
return;
}
if ( config.timeout ) {
clearTimeout(config.timeout);
}
@ -413,9 +428,17 @@ var QUnit = {
}, timeout);
}
}
};
//We want access to the constructor's prototype
(function() {
function F(){};
F.prototype = QUnit;
QUnit = new F();
//Make F QUnit's constructor so that we can add to the prototype later
QUnit.constructor = F;
})();
// Backwards compatibility, deprecated
QUnit.equals = QUnit.equal;
QUnit.same = QUnit.deepEqual;
@ -426,32 +449,51 @@ var config = {
queue: [],
// block until document ready
blocking: true
blocking: true,
// when enabled, show only failing tests
// gets persisted through sessionStorage and can be changed in UI via checkbox
hidepassed: false,
// by default, run previously failed tests first
// very useful in combination with "Hide passed tests" checked
reorder: true,
// by default, modify document.title when suite is done
altertitle: true,
urlConfig: ['noglobals', 'notrycatch'],
//logging callback queues
begin: [],
done: [],
log: [],
testStart: [],
testDone: [],
moduleStart: [],
moduleDone: []
};
// Load paramaters
(function() {
var location = window.location || { search: "", protocol: "file:" },
GETParams = location.search.slice(1).split('&');
params = location.search.slice( 1 ).split( "&" ),
length = params.length,
urlParams = {},
current;
for ( var i = 0; i < GETParams.length; i++ ) {
GETParams[i] = decodeURIComponent( GETParams[i] );
if ( GETParams[i] === "noglobals" ) {
GETParams.splice( i, 1 );
i--;
config.noglobals = true;
} else if ( GETParams[i] === "notrycatch" ) {
GETParams.splice( i, 1 );
i--;
config.notrycatch = true;
} else if ( GETParams[i].search('=') > -1 ) {
GETParams.splice( i, 1 );
i--;
if ( params[ 0 ] ) {
for ( var i = 0; i < length; i++ ) {
current = params[ i ].split( "=" );
current[ 0 ] = decodeURIComponent( current[ 0 ] );
// allow just a key to turn on a flag, e.g., test.html?noglobals
current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
urlParams[ current[ 0 ] ] = current[ 1 ];
}
}
// restrict modules/tests by get parameters
config.filters = GETParams;
QUnit.urlParams = urlParams;
config.filter = urlParams.filter;
// Figure out if we're running the tests from a server or not
QUnit.isLocal = !!(location.protocol === 'file:');
@ -481,7 +523,7 @@ extend(QUnit, {
blocking: false,
autostart: true,
autorun: false,
filters: [],
filter: "",
queue: [],
semaphore: 0
});
@ -501,6 +543,14 @@ extend(QUnit, {
if ( result ) {
result.parentNode.removeChild( result );
}
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
result.innerHTML = 'Running...<br/>&nbsp;';
}
},
/**
@ -510,9 +560,9 @@ extend(QUnit, {
*/
reset: function() {
if ( window.jQuery ) {
jQuery( "#main, #qunit-fixture" ).html( config.fixture );
jQuery( "#qunit-fixture" ).html( config.fixture );
} else {
var main = id( 'main' ) || id( 'qunit-fixture' );
var main = id( 'qunit-fixture' );
if ( main ) {
main.innerHTML = config.fixture;
}
@ -599,12 +649,12 @@ extend(QUnit, {
var source = sourceFromStacktrace();
if (source) {
details.source = source;
output += '<tr class="test-source"><th>Source: </th><td><pre>' + source +'</pre></td></tr>';
output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeHtml(source) + '</pre></td></tr>';
}
}
output += "</table>";
QUnit.log(details);
runLoggingCallbacks( 'log', QUnit, details );
config.current.assertions.push({
result: !!result,
@ -612,29 +662,49 @@ extend(QUnit, {
});
},
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var querystring = "?",
key;
for ( key in params ) {
querystring += encodeURIComponent( key ) + "=" +
encodeURIComponent( params[ key ] ) + "&";
}
return window.location.pathname + querystring.slice( 0, -1 );
},
extend: extend,
id: id,
addEvent: addEvent,
});
//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
//Doing this allows us to tell if the following methods have been overwritten on the actual
//QUnit object, which is a deprecated way of using the callbacks.
extend(QUnit.constructor.prototype, {
// Logging callbacks; all receive a single argument with the listed properties
// run test/logs.html for any related changes
begin: function() {},
begin: registerLoggingCallback('begin'),
// done: { failed, passed, total, runtime }
done: function() {},
done: registerLoggingCallback('done'),
// log: { result, actual, expected, message }
log: function() {},
log: registerLoggingCallback('log'),
// testStart: { name }
testStart: function() {},
testStart: registerLoggingCallback('testStart'),
// testDone: { name, failed, passed, total }
testDone: function() {},
testDone: registerLoggingCallback('testDone'),
// moduleStart: { name }
moduleStart: function() {},
moduleStart: registerLoggingCallback('moduleStart'),
// moduleDone: { name, failed, passed, total }
moduleDone: function() {}
moduleDone: registerLoggingCallback('moduleDone'),
});
if ( typeof document === "undefined" || document.readyState === "complete" ) {
config.autorun = true;
}
addEvent(window, "load", function() {
QUnit.begin({});
QUnit.load = function() {
runLoggingCallbacks( 'begin', QUnit, {} );
// Initialize the config, saving the execution queue
var oldconfig = extend({}, config);
@ -643,22 +713,24 @@ addEvent(window, "load", function() {
config.blocking = false;
var urlConfigHtml = '', len = config.urlConfig.length;
for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
config[val] = QUnit.urlParams[val];
urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
}
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 > -1 ) {
var mainPageLocation = location.href.slice(0, paramsIndex);
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>';
}
}
banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
addEvent( banner, "change", function( event ) {
var params = {};
params[ event.target.name ] = event.target.checked ? true : undefined;
window.location = QUnit.url( params );
});
}
var toolbar = id("qunit-testrunner-toolbar");
@ -667,18 +739,25 @@ addEvent(window, "load", function() {
filter.type = "checkbox";
filter.id = "qunit-filter-pass";
addEvent( filter, "click", function() {
var li = document.getElementsByTagName("li");
for ( var i = 0; i < li.length; i++ ) {
if ( li[i].className.indexOf("pass") > -1 ) {
li[i].style.display = filter.checked ? "none" : "";
}
var ol = document.getElementById("qunit-tests");
if ( filter.checked ) {
ol.className = ol.className + " hidepass";
} else {
var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
ol.className = tmp.replace(/ hidepass /, " ");
}
if ( defined.sessionStorage ) {
sessionStorage.setItem("qunit-filter-passed-tests", filter.checked ? "true" : "");
if (filter.checked) {
sessionStorage.setItem("qunit-filter-passed-tests", "true");
} else {
sessionStorage.removeItem("qunit-filter-passed-tests");
}
}
});
if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
filter.checked = true;
var ol = document.getElementById("qunit-tests");
ol.className = ol.className + " hidepass";
}
toolbar.appendChild( filter );
@ -688,7 +767,7 @@ addEvent(window, "load", function() {
toolbar.appendChild( label );
}
var main = id('main') || id('qunit-fixture');
var main = id('qunit-fixture');
if ( main ) {
config.fixture = main.innerHTML;
}
@ -696,14 +775,16 @@ addEvent(window, "load", function() {
if (config.autostart) {
QUnit.start();
}
});
};
addEvent(window, "load", QUnit.load);
function done() {
config.autorun = true;
// Log the last module results
if ( config.currentModule ) {
QUnit.moduleDone( {
runLoggingCallbacks( 'moduleDone', QUnit, {
name: config.currentModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
@ -733,19 +814,19 @@ function done() {
}
if ( tests ) {
var result = id("qunit-testresult");
if ( !result ) {
result = document.createElement("p");
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests.nextSibling );
id( "qunit-testresult" ).innerHTML = html;
}
result.innerHTML = html;
if ( config.altertitle && typeof document !== "undefined" && document.title ) {
// show ✖ for good, ✔ for bad suite result in title
// use escape sequences in case file gets loaded with non-utf-8-charset
document.title = [
(config.stats.bad ? "\u2716" : "\u2714"),
document.title.replace(/^[\u2714\u2716] /i, "")
].join(" ");
}
QUnit.done( {
runLoggingCallbacks( 'done', QUnit, {
failed: config.stats.bad,
passed: passed,
total: config.stats.all,
@ -754,17 +835,14 @@ function done() {
}
function validTest( name ) {
var i = config.filters.length,
var filter = config.filter,
run = false;
if ( !i ) {
if ( !filter ) {
return true;
}
while ( i-- ) {
var filter = config.filters[i],
not = filter.charAt(0) == '!';
var not = filter.charAt( 0 ) === "!";
if ( not ) {
filter = filter.slice( 1 );
}
@ -776,7 +854,6 @@ function validTest( name ) {
if ( not ) {
run = true;
}
}
return run;
}
@ -793,14 +870,14 @@ function sourceFromStacktrace() {
} else if (e.stack) {
// Firefox, Chrome
return e.stack.split("\n")[4];
} else if (e.sourceURL) {
// Safari, PhantomJS
// TODO sourceURL points at the 'throw new Error' line above, useless
//return e.sourceURL + ":" + e.line;
}
}
}
function resultDisplayStyle(passed) {
return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : '';
}
function escapeHtml(s) {
if (!s) {
return "";
@ -856,16 +933,14 @@ function checkPollution( name ) {
var old = config.pollution;
saveGlobal();
var newGlobals = diff( old, config.pollution );
var newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
config.current.expected++;
}
var deletedGlobals = diff( config.pollution, old );
var deletedGlobals = diff( old, config.pollution );
if ( deletedGlobals.length > 0 ) {
ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
config.current.expected++;
}
}
@ -897,8 +972,12 @@ function fail(message, exception, callback) {
function extend(a, b) {
for ( var prop in b ) {
if ( b[prop] === undefined ) {
delete a[prop];
} else {
a[prop] = b[prop];
}
}
return a;
}
@ -918,9 +997,27 @@ function id(name) {
document.getElementById( name );
}
function registerLoggingCallback(key){
return function(callback){
config[key].push( callback );
};
}
// Supports deprecated method of completely overwriting logging callbacks
function runLoggingCallbacks(key, scope, args) {
//debugger;
var callbacks;
if ( QUnit.hasOwnProperty(key) ) {
QUnit[key].call(scope, args);
} else {
callbacks = config[key];
for( var i = 0; i < callbacks.length; i++ ) {
callbacks[i].call( scope, args );
}
}
}
// 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 () {
@ -945,7 +1042,8 @@ QUnit.equiv = 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
// to catch short annotaion VS 'new' annotation of a
// declaration
// e.g. var i = 1;
// var j = new Number(1);
return a == b;
@ -966,15 +1064,17 @@ QUnit.equiv = function () {
},
"date" : function(b, a) {
return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
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;
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)
@ -982,8 +1082,7 @@ QUnit.equiv = function () {
// initial === would have catch identical references anyway
"function" : function() {
var caller = callers[callers.length - 1];
return caller !== Object &&
typeof caller !== "undefined";
return caller !== Object && typeof caller !== "undefined";
},
"array" : function(b, a) {
@ -1021,9 +1120,11 @@ QUnit.equiv = function () {
"object" : function(b, a) {
var i, j, loop;
var eq = true; // unless we can proove it
var aProperties = [], bProperties = []; // collection of strings
var aProperties = [], bProperties = []; // collection of
// strings
// comparing constructors is more strict than using instanceof
// comparing constructors is more strict than using
// instanceof
if (a.constructor !== b.constructor) {
return false;
}
@ -1033,11 +1134,13 @@ QUnit.equiv = function () {
// track reference to avoid circular references
parents.push(a);
for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
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
loop = true; // don't go down the same path
// twice
}
aProperties.push(i); // collect a's properties
@ -1055,7 +1158,9 @@ QUnit.equiv = function () {
}
// Ensures identical properties name
return eq && innerEquiv(aProperties.sort(), bProperties.sort());
return eq
&& innerEquiv(aProperties.sort(), bProperties
.sort());
}
};
}();
@ -1069,14 +1174,18 @@ QUnit.equiv = function () {
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)) {
} 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));
})(args[0], args[1])
&& arguments.callee.apply(this, args.splice(1,
args.length - 1));
};
return innerEquiv;
@ -1084,10 +1193,10 @@ QUnit.equiv = function () {
}();
/**
* 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
* 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
@ -1110,11 +1219,11 @@ QUnit.jsDump = (function() {
return pre + post;
return [ pre, inner + arr, base + post ].join(s);
};
function array( arr ) {
function array( arr, stack ) {
var i = arr.length, ret = Array(i);
this.up();
while ( i-- )
ret[i] = this.parse( arr[i] );
ret[i] = this.parse( arr[i] , undefined , stack);
this.down();
return join( '[', ret, ']' );
};
@ -1122,13 +1231,23 @@ QUnit.jsDump = (function() {
var reName = /^function (\w+)/;
var jsDump = {
parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
stack = stack || [ ];
var parser = this.parsers[ type || this.typeOf(obj) ];
type = typeof parser;
return type == 'function' ? parser.call( this, obj ) :
type == 'string' ? parser :
this.parsers.error;
var inStack = inArray(obj, stack);
if (inStack != -1) {
return 'recursion('+(inStack - stack.length)+')';
}
//else
if (type == 'function') {
stack.push(obj);
var res = parser.call( this, obj, stack );
stack.pop();
return res;
}
// else
return (type == 'string') ? parser : this.parsers.error;
},
typeOf:function( obj ) {
var type;
@ -1188,7 +1307,7 @@ QUnit.jsDump = (function() {
error:'[ERROR]', //when no parser is found, shouldn't happen
unknown: '[Unknown]',
'null':'null',
undefined:'undefined',
'undefined':'undefined',
'function':function( fn ) {
var ret = 'function',
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
@ -1202,11 +1321,13 @@ QUnit.jsDump = (function() {
array: array,
nodelist: array,
arguments: array,
object:function( map ) {
object:function( map, stack ) {
var ret = [ ];
QUnit.jsDump.up();
for ( var key in map )
ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
for ( var key in map ) {
var val = map[key];
ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
}
QUnit.jsDump.down();
return join( '{', ret, '}' );
},
@ -1275,6 +1396,21 @@ function getText( elems ) {
return ret;
};
//from jquery.js
function inArray( elem, array ) {
if ( array.indexOf ) {
return array.indexOf( elem );
}
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
}
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
@ -1291,13 +1427,13 @@ function getText( elems ) {
*/
QUnit.diff = (function() {
function diff(o, n) {
var ns = new Object();
var os = new Object();
var ns = {};
var os = {};
for (var i = 0; i < n.length; i++) {
if (ns[n[i]] == null)
ns[n[i]] = {
rows: new Array(),
rows: [],
o: null
};
ns[n[i]].rows.push(i);
@ -1306,7 +1442,7 @@ QUnit.diff = (function() {
for (var i = 0; i < o.length; i++) {
if (os[o[i]] == null)
os[o[i]] = {
rows: new Array(),
rows: [],
n: null
};
os[o[i]].rows.push(i);

Loading…
Cancel
Save