From: Jörn Zaefferer Date: Sun, 30 Aug 2009 10:46:20 +0000 (+0000) Subject: update to lastest QUnit X-Git-Tag: 1.8a2~121 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7f54a1bad9d9bb74e74904d584bfd9b0a4278663;p=jquery-ui.git update to lastest QUnit --- diff --git a/external/testrunner-r6343.js b/external/testrunner-r6343.js deleted file mode 100644 index 677bdd098..000000000 --- a/external/testrunner-r6343.js +++ /dev/null @@ -1,790 +0,0 @@ -/* - * QUnit - jQuery unit testrunner - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2008 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Id: testrunner.js 6343 2009-05-06 15:09:22Z joern.zaefferer $ - */ - -(function($) { - -// Tests for equality any JavaScript type and structure without unexpected results. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// Author: Philippe Rathé -var equiv = function () { - - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - - // Determine what is o. - function hoozit(o) { - if (typeof o === "string") { - return "string"; - - } else if (typeof o === "boolean") { - return "boolean"; - - } else if (typeof o === "number") { - - if (isNaN(o)) { - return "nan"; - } else { - return "number"; - } - - } else if (typeof o === "undefined") { - return "undefined"; - - // consider: typeof null === object - } else if (o === null) { - return "null"; - - // consider: typeof [] === object - } else if (o instanceof Array) { - return "array"; - - // consider: typeof new Date() === object - } else if (o instanceof Date) { - return "date"; - - // consider: /./ instanceof Object; - // /./ instanceof RegExp; - // typeof /./ === "function"; // => false in IE and Opera, - // true in FF and Safari - } else if (o instanceof RegExp) { - return "regexp"; - - } else if (typeof o === "object") { - return "object"; - - } else if (o instanceof Function) { - return "function"; - } - } - - // Call the o related callback with the given arguments. - function bindCallbacks(o, callbacks, args) { - var prop = hoozit(o); - if (prop) { - if (hoozit(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) { - 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 hoozit(b) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function (b, a) { - return hoozit(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; - var len; - - // b could be an object literal here - if ( ! (hoozit(b) === "array")) { - return false; - } - - len = a.length; - if (len !== b.length) { // safe and faster - return false; - } - for (i = 0; i < len; i++) { - if( ! innerEquiv(a[i], b[i])) { - return false; - } - } - return true; - }, - - "object": function (b, a) { - var i; - 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); - - for (i in a) { // be strict: don't ensures hasOwnProperty and go deep - - aProperties.push(i); // collect a's properties - - if ( ! innerEquiv(a[i], b[i])) { - eq = false; - } - } - - callers.pop(); // unstack, we are done - - 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 (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") { - 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; -}(); // equiv - -var GETParams = $.map( location.search.slice(1).split('&'), decodeURIComponent ), - ngindex = $.inArray("noglobals", GETParams), - noglobals = ngindex !== -1; - -if( noglobals ) - GETParams.splice( ngindex, 1 ); - -var config = { - stats: { - all: 0, - bad: 0 - }, - queue: [], - // block until document ready - blocking: true, - //restrict modules/tests by get parameters - filters: GETParams, - isLocal: !!(window.location.protocol == 'file:') -}; - -// public API as global methods -$.extend(window, { - test: test, - module: module, - expect: expect, - ok: ok, - equals: equals, - start: start, - stop: stop, - reset: reset, - isLocal: config.isLocal, - same: function(a, b, message) { - push(equiv(a, b), a, b, message); - }, - QUnit: { - equiv: equiv, - ok: ok, - done: function(failures, total){}, - log: function(result, message){} - }, - // legacy methods below - isSet: isSet, - isObj: isObj, - compare: function() { - throw "compare is deprecated - use same() instead"; - }, - compare2: function() { - throw "compare2 is deprecated - use same() instead"; - }, - serialArray: function() { - throw "serialArray is deprecated - use jsDump.parse() instead"; - }, - q: q, - t: t, - url: url, - triggerEvent: triggerEvent -}); - -$(window).load(function() { - - if (!$("#header, #banner, #userAgent, #tests").length) { - $('body').prepend( - '

' + document.title + '

' + - '' + - '

' + - '
    ' - ); - } - - $('#userAgent').html(navigator.userAgent); - var head = $('
    ').insertAfter("#userAgent"); - $('').attr("disabled", true).prependTo(head).click(function() { - $('li.pass')[this.checked ? 'hide' : 'show'](); - }); - $('').attr("disabled", true).appendTo(head).click(function() { - $("li.fail:contains('missing test - untested code is broken code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show'](); - }); - $("#filter-missing").after(''); - runTest(); -}); - -function synchronize(callback) { - config.queue.push(callback); - if(!config.blocking) { - process(); - } -} - -function process() { - while(config.queue.length && !config.blocking) { - config.queue.shift()(); - } -} - -function stop(timeout) { - config.blocking = true; - if (timeout) - config.timeout = setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - start(); - }, timeout); -} -function start() { - // A slight delay, to avoid any current callbacks - setTimeout(function() { - if(config.timeout) - clearTimeout(config.timeout); - config.blocking = false; - process(); - }, 13); -} - -function validTest( name ) { - var i = config.filters.length, - run = false; - - if( !i ) - return true; - - while( i-- ){ - var filter = config.filters[i], - not = filter.charAt(0) == '!'; - if( not ) - filter = filter.slice(1); - if( name.indexOf(filter) != -1 ) - return !not; - if( not ) - run = true; - } - return run; -} - -function runTest() { - config.blocking = false; - var started = +new Date; - config.fixture = document.getElementById('main').innerHTML; - config.ajaxSettings = $.ajaxSettings; - synchronize(function() { - $('

    ').html(['Tests completed in ', - +new Date - started, ' milliseconds.
    ', - '', config.stats.bad, ' tests of ', config.stats.all, ' failed.'] - .join('')) - .appendTo("body"); - $("#banner").addClass(config.stats.bad ? "fail" : "pass"); - QUnit.done( config.stats.bad, config.stats.all ); - }); -} - -var pollution; - -function saveGlobal(){ - pollution = [ ]; - - if( noglobals ) - for( var key in window ) - pollution.push(key); -} -function checkPollution( name ){ - var old = pollution; - saveGlobal(); - - if( pollution.length > old.length ){ - ok( false, "Introduced global variable(s): " + diff(old, pollution).join(", ") ); - config.expected++; - } -} - -function diff( clean, dirty ){ - return $.grep( dirty, function(name){ - return $.inArray( name, clean ) == -1; - }); -} - -function test(name, callback) { - if(config.currentModule) - name = config.currentModule + " module: " + name + ""; - var lifecycle = $.extend({ - setup: function() {}, - teardown: function() {} - }, config.moduleLifecycle); - - if ( !validTest(name) ) - return; - - synchronize(function() { - config.assertions = []; - config.expected = null; - try { - if( !pollution ) - saveGlobal(); - lifecycle.setup(); - } catch(e) { - QUnit.ok( false, "Setup failed on " + name + ": " + e.message ); - } - }) - synchronize(function() { - try { - callback(); - } catch(e) { - if( typeof console != "undefined" && console.error && console.warn ) { - console.error("Test " + name + " died, exception and test follows"); - console.error(e); - console.warn(callback.toString()); - } - QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message ); - // else next test will carry the responsibility - saveGlobal(); - } - }); - synchronize(function() { - try { - checkPollution(); - lifecycle.teardown(); - } catch(e) { - QUnit.ok( false, "Teardown failed on " + name + ": " + e.message ); - } - }) - synchronize(function() { - try { - reset(); - } catch(e) { - if( typeof console != "undefined" && console.error && console.warn ) { - console.error("reset() failed, following Test " + name + ", exception and reset fn follows"); - console.error(e); - console.warn(reset.toString()); - } - } - - if(config.expected && config.expected != config.assertions.length) { - QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" ); - } - - var good = 0, bad = 0; - var ol = $("

      ").hide(); - config.stats.all += config.assertions.length; - for ( var i = 0; i < config.assertions.length; i++ ) { - var assertion = config.assertions[i]; - $("
    1. ").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol); - assertion.result ? good++ : bad++; - } - config.stats.bad += bad; - - var b = $("").html(name + " (" + bad + ", " + good + ", " + config.assertions.length + ")") - .click(function(){ - $(this).next().toggle(); - }) - .dblclick(function(event) { - var target = $(event.target).filter("strong").clone(); - if ( target.length ) { - target.children().remove(); - location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text())); - } - }); - - $("
    2. ").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests"); - - if(bad) { - $("#filter-pass").attr("disabled", null); - $("#filter-missing").attr("disabled", null); - } - }); -} - -// call on start of module test to prepend name to all tests -function module(name, lifecycle) { - config.currentModule = name; - config.moduleLifecycle = lifecycle; -} - -/** - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - */ -function expect(asserts) { - config.expected = asserts; -} - -/** - * Resets the test setup. Useful for tests that modify the DOM. - */ -function reset() { - $("#main").html( config.fixture ); - $.event.global = {}; - $.ajaxSettings = $.extend({}, config.ajaxSettings); -} - -/** - * Asserts true. - * @example ok( $("a").size() > 5, "There must be at least 5 anchors" ); - */ -function ok(a, msg) { - QUnit.log(a, msg); - - config.assertions.push({ - result: !!a, - message: msg - }); -} - -/** - * Asserts that two arrays are the same - */ -function isSet(a, b, msg) { - function serialArray( a ) { - var r = []; - - if ( a && a.length ) - for ( var i = 0; i < a.length; i++ ) { - var str = a[i].nodeName; - if ( str ) { - str = str.toLowerCase(); - if ( a[i].id ) - str += "#" + a[i].id; - } else - str = a[i]; - r.push( str ); - } - - return "[ " + r.join(", ") + " ]"; - } - var ret = true; - if ( a && b && a.length != undefined && a.length == b.length ) { - for ( var i = 0; i < a.length; i++ ) - if ( a[i] != b[i] ) - ret = false; - } else - ret = false; - QUnit.ok( ret, !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg ); -} - -/** - * Asserts that two objects are equivalent - */ -function isObj(a, b, msg) { - var ret = true; - - if ( a && b ) { - for ( var i in a ) - if ( a[i] != b[i] ) - ret = false; - - for ( i in b ) - if ( a[i] != b[i] ) - ret = false; - } else - ret = false; - - QUnit.ok( ret, msg ); -} - -/** - * Returns an array of elements with the given IDs, eg. - * @example q("main", "foo", "bar") - * @result [
      , , ] - */ -function q() { - var r = []; - for ( var i = 0; i < arguments.length; i++ ) - r.push( document.getElementById( arguments[i] ) ); - return r; -} - -/** - * Asserts that a select matches the given IDs - * @example t("Check for something", "//[a]", ["foo", "baar"]); - * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' - */ -function t(a,b,c) { - var f = $(b); - var s = ""; - for ( var i = 0; i < f.length; i++ ) - s += (s && ",") + '"' + f[i].id + '"'; - isSet(f, q.apply(q,c), a + " (" + b + ")"); -} - -/** - * Add random number to url to stop IE from caching - * - * @example url("data/test.html") - * @result "data/test.html?10538358428943" - * - * @example url("data/test.php?foo=bar") - * @result "data/test.php?foo=bar&10538358345554" - */ -function url(value) { - return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); -} - -/** - * 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 equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." ); - * - * @param Object actual - * @param Object expected - * @param String message (optional) - */ -function equals(actual, expected, message) { - push(expected == actual, actual, expected, message); -} - -function push(result, actual, expected, message) { - message = message || (result ? "okay" : "failed"); - QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) ); -} - -/** - * Trigger an event on an element. - * - * @example triggerEvent( document.body, "click" ); - * - * @param DOMElement elem - * @param String type - */ -function triggerEvent( elem, type, event ) { - if ( $.browser.mozilla || $.browser.opera ) { - event = document.createEvent("MouseEvents"); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - elem.dispatchEvent( event ); - } else if ( $.browser.msie ) { - elem.fireEvent("on"+type); - } -} - -})(jQuery); - -/** - * 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} - */ -(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 = window.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 = typeof obj, - f = 'function';//we'll use it 3 times, save it - return type != 'object' && type != f ? type : - !obj ? 'null' : - obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions - obj.getHours ? 'date' : - obj.scrollBy ? 'window' : - obj.nodeName == '#document' ? 'document' : - obj.nodeName ? 'node' : - obj.item ? 'nodelist' : // Safari reports nodelists as functions - obj.callee ? 'arguments' : - obj.call || obj.constructor != Array && //an array would also fall on this hack - (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects - 'length' in obj ? 'array' : - type; - }, - separator:function(){ - return this.multiline ? this.HTML ? '
      ' : '\n' : this.HTML ? ' ' : ' '; - }, - 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,' '); - 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 = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); - return join( ret, this.parse(fn,'functionCode'), '}' ); - }, - array: array, - nodelist: array, - arguments: array, - object:function( map ){ - var ret = [ ]; - this.up(); - for( var key in map ) - ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); - this.down(); - return join( '{', ret, '}' ); - }, - node:function( node ){ - var open = this.HTML ? '<' : '<', - close = this.HTML ? '>' : '>'; - - var tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for( var a in this.DOMAttrs ){ - var val = node[this.DOMAttrs[a]]; - if( val ) - ret += ' ' + a + '=' + this.parse( val, 'attribute' ); - } - return ret + close + open + '/' + tag + close; - }, - functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function - var l = fn.length; - if( !l ) 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. - }; - -})(); diff --git a/external/testrunner-r6416.js b/external/testrunner-r6416.js new file mode 100644 index 000000000..8c28b6398 --- /dev/null +++ b/external/testrunner-r6416.js @@ -0,0 +1,803 @@ +/* + * QUnit - jQuery unit testrunner + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2008 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Id: testrunner.js 6416 2009-07-10 16:08:27Z joern.zaefferer $ + */ + +(function($) { + +// Test for equality any JavaScript type. +// Discussions and reference: http://philrathe.com/articles/equiv +// Test suites: http://philrathe.com/tests/equiv +// Author: Philippe Rathé +var equiv = function () { + + var innerEquiv; // the real equiv function + var callers = []; // stack to decide between skip/abort functions + + + // Determine what is o. + function hoozit(o) { + if (o.constructor === String) { + return "string"; + + } else if (o.constructor === Boolean) { + return "boolean"; + + } else if (o.constructor === Number) { + + if (isNaN(o)) { + return "nan"; + } else { + return "number"; + } + + } else if (typeof o === "undefined") { + return "undefined"; + + // consider: typeof null === object + } else if (o === null) { + return "null"; + + // consider: typeof [] === object + } else if (o instanceof Array) { + return "array"; + + // consider: typeof new Date() === object + } else if (o instanceof Date) { + return "date"; + + // consider: /./ instanceof Object; + // /./ instanceof RegExp; + // typeof /./ === "function"; // => false in IE and Opera, + // true in FF and Safari + } else if (o instanceof RegExp) { + return "regexp"; + + } else if (typeof o === "object") { + return "object"; + + } else if (o instanceof Function) { + return "function"; + } else { + return undefined; + } + } + + // Call the o related callback with the given arguments. + function bindCallbacks(o, callbacks, args) { + var prop = hoozit(o); + if (prop) { + if (hoozit(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 hoozit(b) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function (b, a) { + return hoozit(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; + var len; + + // b could be an object literal here + if ( ! (hoozit(b) === "array")) { + return false; + } + + len = a.length; + if (len !== b.length) { // safe and faster + return false; + } + for (i = 0; i < len; i++) { + if( ! innerEquiv(a[i], b[i])) { + return false; + } + } + return true; + }, + + "object": function (b, a) { + var i; + 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); + + for (i in a) { // be strict: don't ensures hasOwnProperty and go deep + + aProperties.push(i); // collect a's properties + + if ( ! innerEquiv(a[i], b[i])) { + eq = false; + } + } + + callers.pop(); // unstack, we are done + + 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" || hoozit(a) !== hoozit(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; + +}(); + +var GETParams = $.map( location.search.slice(1).split('&'), decodeURIComponent ), + ngindex = $.inArray("noglobals", GETParams), + noglobals = ngindex !== -1; + +if( noglobals ) + GETParams.splice( ngindex, 1 ); + +var config = { + stats: { + all: 0, + bad: 0 + }, + queue: [], + // block until document ready + blocking: true, + //restrict modules/tests by get parameters + filters: GETParams, + isLocal: !!(window.location.protocol == 'file:') +}; + +// public API as global methods +$.extend(window, { + test: test, + module: module, + expect: expect, + ok: ok, + equals: equals, + start: start, + stop: stop, + reset: reset, + isLocal: config.isLocal, + same: function(a, b, message) { + push(equiv(a, b), a, b, message); + }, + QUnit: { + equiv: equiv, + ok: ok, + done: function(failures, total){}, + log: function(result, message){} + }, + // legacy methods below + isSet: isSet, + isObj: isObj, + compare: function() { + throw "compare is deprecated - use same() instead"; + }, + compare2: function() { + throw "compare2 is deprecated - use same() instead"; + }, + serialArray: function() { + throw "serialArray is deprecated - use jsDump.parse() instead"; + }, + q: q, + t: t, + url: url, + triggerEvent: triggerEvent +}); + +$(window).load(function() { + + if (!$("#header, #banner, #userAgent, #tests").length) { + $('body').prepend( + '

      ' + document.title + '

      ' + + '' + + '

      ' + + '
        ' + ); + } + + $('#userAgent').html(navigator.userAgent); + var head = $('
        ').insertAfter("#userAgent"); + $('').attr("disabled", true).prependTo(head).click(function() { + $('li.pass')[this.checked ? 'hide' : 'show'](); + }); + $('').attr("disabled", true).appendTo(head).click(function() { + $("li.fail:contains('missing test - untested code is broken code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show'](); + }); + $("#filter-missing").after(''); + runTest(); +}); + +function synchronize(callback) { + config.queue.push(callback); + if(!config.blocking) { + process(); + } +} + +function process() { + while(config.queue.length && !config.blocking) { + config.queue.shift()(); + } +} + +function stop(timeout) { + config.blocking = true; + if (timeout) + config.timeout = setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + start(); + }, timeout); +} +function start() { + // A slight delay, to avoid any current callbacks + setTimeout(function() { + if(config.timeout) + clearTimeout(config.timeout); + config.blocking = false; + process(); + }, 13); +} + +function validTest( name ) { + var i = config.filters.length, + run = false; + + if( !i ) + return true; + + while( i-- ){ + var filter = config.filters[i], + not = filter.charAt(0) == '!'; + if( not ) + filter = filter.slice(1); + if( name.indexOf(filter) != -1 ) + return !not; + if( not ) + run = true; + } + return run; +} + +function runTest() { + config.blocking = false; + var started = +new Date; + config.fixture = document.getElementById('main').innerHTML; + config.ajaxSettings = $.ajaxSettings; + synchronize(function() { + $('

        ').html(['Tests completed in ', + +new Date - started, ' milliseconds.
        ', + '', config.stats.all - config.stats.bad, ' tests of ', config.stats.all, ' passed, ', config.stats.bad,' failed.'] + .join('')) + .appendTo("body"); + $("#banner").addClass(config.stats.bad ? "fail" : "pass"); + QUnit.done( config.stats.bad, config.stats.all ); + }); +} + +var pollution; + +function saveGlobal(){ + pollution = [ ]; + + if( noglobals ) + for( var key in window ) + pollution.push(key); +} +function checkPollution( name ){ + var old = pollution; + saveGlobal(); + + if( pollution.length > old.length ){ + ok( false, "Introduced global variable(s): " + diff(old, pollution).join(", ") ); + config.expected++; + } +} + +function diff( clean, dirty ){ + return $.grep( dirty, function(name){ + return $.inArray( name, clean ) == -1; + }); +} + +function test(name, callback) { + if(config.currentModule) + name = config.currentModule + " module: " + name + ""; + var lifecycle = $.extend({ + setup: function() {}, + teardown: function() {} + }, config.moduleLifecycle); + + if ( !validTest(name) ) + return; + + var testEnvironment = {}; + + synchronize(function() { + config.assertions = []; + config.expected = null; + try { + if( !pollution ) + saveGlobal(); + lifecycle.setup.call(testEnvironment); + } catch(e) { + QUnit.ok( false, "Setup failed on " + name + ": " + e.message ); + } + }); + synchronize(function() { + try { + callback.call(testEnvironment); + } catch(e) { + fail("Test " + name + " died, exception and test follows", e, callback); + QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message ); + // else next test will carry the responsibility + saveGlobal(); + } + }); + synchronize(function() { + try { + checkPollution(); + lifecycle.teardown.call(testEnvironment); + } catch(e) { + QUnit.ok( false, "Teardown failed on " + name + ": " + e.message ); + } + }); + synchronize(function() { + try { + reset(); + } catch(e) { + fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset); + } + + if(config.expected && config.expected != config.assertions.length) { + QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" ); + } + + var good = 0, bad = 0; + var ol = $("

          ").hide(); + config.stats.all += config.assertions.length; + for ( var i = 0; i < config.assertions.length; i++ ) { + var assertion = config.assertions[i]; + $("
        1. ").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol); + assertion.result ? good++ : bad++; + } + config.stats.bad += bad; + + var b = $("").html(name + " (" + bad + ", " + good + ", " + config.assertions.length + ")") + .click(function(){ + $(this).next().toggle(); + }) + .dblclick(function(event) { + var target = $(event.target).filter("strong").clone(); + if ( target.length ) { + target.children().remove(); + location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text())); + } + }); + + $("
        2. ").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests"); + + if(bad) { + $("#filter-pass").attr("disabled", null); + $("#filter-missing").attr("disabled", null); + } + }); +} + +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); + } +} + +// call on start of module test to prepend name to all tests +function module(name, lifecycle) { + config.currentModule = name; + config.moduleLifecycle = lifecycle; +} + +/** + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + */ +function expect(asserts) { + config.expected = asserts; +} + +/** + * Resets the test setup. Useful for tests that modify the DOM. + */ +function reset() { + $("#main").html( config.fixture ); + $.event.global = {}; + $.ajaxSettings = $.extend({}, config.ajaxSettings); +} + +/** + * Asserts true. + * @example ok( $("a").size() > 5, "There must be at least 5 anchors" ); + */ +function ok(a, msg) { + QUnit.log(a, msg); + + config.assertions.push({ + result: !!a, + message: msg + }); +} + +/** + * Asserts that two arrays are the same + */ +function isSet(a, b, msg) { + function serialArray( a ) { + var r = []; + + if ( a && a.length ) + for ( var i = 0; i < a.length; i++ ) { + var str = a[i].nodeName; + if ( str ) { + str = str.toLowerCase(); + if ( a[i].id ) + str += "#" + a[i].id; + } else + str = a[i]; + r.push( str ); + } + + return "[ " + r.join(", ") + " ]"; + } + var ret = true; + if ( a && b && a.length != undefined && a.length == b.length ) { + for ( var i = 0; i < a.length; i++ ) + if ( a[i] != b[i] ) + ret = false; + } else + ret = false; + QUnit.ok( ret, !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg ); +} + +/** + * Asserts that two objects are equivalent + */ +function isObj(a, b, msg) { + var ret = true; + + if ( a && b ) { + for ( var i in a ) + if ( a[i] != b[i] ) + ret = false; + + for ( i in b ) + if ( a[i] != b[i] ) + ret = false; + } else + ret = false; + + QUnit.ok( ret, msg ); +} + +/** + * Returns an array of elements with the given IDs, eg. + * @example q("main", "foo", "bar") + * @result [
          , , ] + */ +function q() { + var r = []; + for ( var i = 0; i < arguments.length; i++ ) + r.push( document.getElementById( arguments[i] ) ); + return r; +} + +/** + * Asserts that a select matches the given IDs + * @example t("Check for something", "//[a]", ["foo", "baar"]); + * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' + */ +function t(a,b,c) { + var f = $(b); + var s = ""; + for ( var i = 0; i < f.length; i++ ) + s += (s && ",") + '"' + f[i].id + '"'; + isSet(f, q.apply(q,c), a + " (" + b + ")"); +} + +/** + * Add random number to url to stop IE from caching + * + * @example url("data/test.html") + * @result "data/test.html?10538358428943" + * + * @example url("data/test.php?foo=bar") + * @result "data/test.php?foo=bar&10538358345554" + */ +function url(value) { + return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); +} + +/** + * 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 equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." ); + * + * @param Object actual + * @param Object expected + * @param String message (optional) + */ +function equals(actual, expected, message) { + push(expected == actual, actual, expected, message); +} + +function push(result, actual, expected, message) { + message = message || (result ? "okay" : "failed"); + QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) ); +} + +/** + * Trigger an event on an element. + * + * @example triggerEvent( document.body, "click" ); + * + * @param DOMElement elem + * @param String type + */ +function triggerEvent( elem, type, event ) { + if ( $.browser.mozilla || $.browser.opera ) { + event = document.createEvent("MouseEvents"); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + elem.dispatchEvent( event ); + } else if ( $.browser.msie ) { + elem.fireEvent("on"+type); + } +} + +})(jQuery); + +/** + * 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} + */ +(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 = window.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 = typeof obj, + f = 'function';//we'll use it 3 times, save it + return type != 'object' && type != f ? type : + !obj ? 'null' : + obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions + obj.getHours ? 'date' : + obj.scrollBy ? 'window' : + obj.nodeName == '#document' ? 'document' : + obj.nodeName ? 'node' : + obj.item ? 'nodelist' : // Safari reports nodelists as functions + obj.callee ? 'arguments' : + obj.call || obj.constructor != Array && //an array would also fall on this hack + (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects + 'length' in obj ? 'array' : + type; + }, + separator:function(){ + return this.multiline ? this.HTML ? '
          ' : '\n' : this.HTML ? ' ' : ' '; + }, + 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,' '); + 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 = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, this.parse(fn,'functionCode'), '}' ); + }, + array: array, + nodelist: array, + arguments: array, + object:function( map ){ + var ret = [ ]; + this.up(); + for( var key in map ) + ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); + this.down(); + return join( '{', ret, '}' ); + }, + node:function( node ){ + var open = this.HTML ? '<' : '<', + close = this.HTML ? '>' : '>'; + + var tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for( var a in this.DOMAttrs ){ + var val = node[this.DOMAttrs[a]]; + if( val ) + ret += ' ' + a + '=' + this.parse( val, 'attribute' ); + } + return ret + close + open + '/' + tag + close; + }, + functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function + var l = fn.length; + if( !l ) 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. + }; + +})(); diff --git a/tests/unit/accordion/accordion.html b/tests/unit/accordion/accordion.html index cb4b67f32..9e1e9a3c8 100644 --- a/tests/unit/accordion/accordion.html +++ b/tests/unit/accordion/accordion.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/all/all.html b/tests/unit/all/all.html index e5e739eb0..c8e444048 100644 --- a/tests/unit/all/all.html +++ b/tests/unit/all/all.html @@ -18,7 +18,7 @@ - + diff --git a/tests/unit/all/all_2.html b/tests/unit/all/all_2.html index 4cefb599e..88bdb6dbc 100644 --- a/tests/unit/all/all_2.html +++ b/tests/unit/all/all_2.html @@ -51,7 +51,7 @@ - + diff --git a/tests/unit/core/core.html b/tests/unit/core/core.html index 308f22b84..49caa2ab7 100644 --- a/tests/unit/core/core.html +++ b/tests/unit/core/core.html @@ -8,7 +8,7 @@ - + diff --git a/tests/unit/datepicker/datepicker.html b/tests/unit/datepicker/datepicker.html index 917f43d5f..5b62f72b9 100644 --- a/tests/unit/datepicker/datepicker.html +++ b/tests/unit/datepicker/datepicker.html @@ -13,7 +13,7 @@ - + diff --git a/tests/unit/defaults.html b/tests/unit/defaults.html index 9f7565541..19e7b6ee8 100644 --- a/tests/unit/defaults.html +++ b/tests/unit/defaults.html @@ -19,7 +19,7 @@ - + diff --git a/tests/unit/dialog/dialog.html b/tests/unit/dialog/dialog.html index 635ac8bf7..4679c3131 100644 --- a/tests/unit/dialog/dialog.html +++ b/tests/unit/dialog/dialog.html @@ -13,7 +13,7 @@ - + diff --git a/tests/unit/draggable/draggable.html b/tests/unit/draggable/draggable.html index a5ae27ff8..921baae31 100644 --- a/tests/unit/draggable/draggable.html +++ b/tests/unit/draggable/draggable.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/droppable/droppable.html b/tests/unit/droppable/droppable.html index 972c8b8ff..0a5d35f94 100644 --- a/tests/unit/droppable/droppable.html +++ b/tests/unit/droppable/droppable.html @@ -10,7 +10,7 @@ - + diff --git a/tests/unit/position/position.html b/tests/unit/position/position.html index 6d9a00008..1381ce558 100644 --- a/tests/unit/position/position.html +++ b/tests/unit/position/position.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/progressbar/progressbar.html b/tests/unit/progressbar/progressbar.html index 9306e836d..b678f3df6 100644 --- a/tests/unit/progressbar/progressbar.html +++ b/tests/unit/progressbar/progressbar.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/resizable/resizable.html b/tests/unit/resizable/resizable.html index f5aba9a66..c9260f2f5 100644 --- a/tests/unit/resizable/resizable.html +++ b/tests/unit/resizable/resizable.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/selectable/selectable.html b/tests/unit/selectable/selectable.html index f398eb237..1b401f13a 100644 --- a/tests/unit/selectable/selectable.html +++ b/tests/unit/selectable/selectable.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/slider/slider.html b/tests/unit/slider/slider.html index c811cac0c..c4d97de82 100644 --- a/tests/unit/slider/slider.html +++ b/tests/unit/slider/slider.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/sortable/sortable.html b/tests/unit/sortable/sortable.html index 487771f32..e3a87a9b0 100644 --- a/tests/unit/sortable/sortable.html +++ b/tests/unit/sortable/sortable.html @@ -9,7 +9,7 @@ - + diff --git a/tests/unit/tabs/tabs.html b/tests/unit/tabs/tabs.html index 9adc938c7..644f21bc8 100644 --- a/tests/unit/tabs/tabs.html +++ b/tests/unit/tabs/tabs.html @@ -9,7 +9,7 @@ - +