1.1 --- a/bootstrap-source/bootstrap-3.0.3/js/tests/vendor/qunit.js Sat Jan 18 12:34:36 2014 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1510 +0,0 @@
1.4 -/**
1.5 - * QUnit - A JavaScript Unit Testing Framework
1.6 - *
1.7 - * http://docs.jquery.com/QUnit
1.8 - *
1.9 - * Copyright (c) 2012 John Resig, Jörn Zaefferer
1.10 - * Dual licensed under the MIT (MIT-LICENSE.txt)
1.11 - * or GPL (GPL-LICENSE.txt) licenses.
1.12 - */
1.13 -
1.14 -(function(window) {
1.15 -
1.16 -var defined = {
1.17 - setTimeout: typeof window.setTimeout !== "undefined",
1.18 - sessionStorage: (function() {
1.19 - try {
1.20 - return !!sessionStorage.getItem;
1.21 - } catch(e) {
1.22 - return false;
1.23 - }
1.24 - })()
1.25 -};
1.26 -
1.27 -var testId = 0;
1.28 -
1.29 -var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
1.30 - this.name = name;
1.31 - this.testName = testName;
1.32 - this.expected = expected;
1.33 - this.testEnvironmentArg = testEnvironmentArg;
1.34 - this.async = async;
1.35 - this.callback = callback;
1.36 - this.assertions = [];
1.37 -};
1.38 -Test.prototype = {
1.39 - init: function() {
1.40 - var tests = id("qunit-tests");
1.41 - if (tests) {
1.42 - var b = document.createElement("strong");
1.43 - b.innerHTML = "Running " + this.name;
1.44 - var li = document.createElement("li");
1.45 - li.appendChild( b );
1.46 - li.className = "running";
1.47 - li.id = this.id = "test-output" + testId++;
1.48 - tests.appendChild( li );
1.49 - }
1.50 - },
1.51 - setup: function() {
1.52 - if (this.module != config.previousModule) {
1.53 - if ( config.previousModule ) {
1.54 - QUnit.moduleDone( {
1.55 - name: config.previousModule,
1.56 - failed: config.moduleStats.bad,
1.57 - passed: config.moduleStats.all - config.moduleStats.bad,
1.58 - total: config.moduleStats.all
1.59 - } );
1.60 - }
1.61 - config.previousModule = this.module;
1.62 - config.moduleStats = { all: 0, bad: 0 };
1.63 - QUnit.moduleStart( {
1.64 - name: this.module
1.65 - } );
1.66 - }
1.67 -
1.68 - config.current = this;
1.69 - this.testEnvironment = extend({
1.70 - setup: function() {},
1.71 - teardown: function() {}
1.72 - }, this.moduleTestEnvironment);
1.73 - if (this.testEnvironmentArg) {
1.74 - extend(this.testEnvironment, this.testEnvironmentArg);
1.75 - }
1.76 -
1.77 - QUnit.testStart( {
1.78 - name: this.testName
1.79 - } );
1.80 -
1.81 - // allow utility functions to access the current test environment
1.82 - // TODO why??
1.83 - QUnit.current_testEnvironment = this.testEnvironment;
1.84 -
1.85 - try {
1.86 - if ( !config.pollution ) {
1.87 - saveGlobal();
1.88 - }
1.89 -
1.90 - this.testEnvironment.setup.call(this.testEnvironment);
1.91 - } catch(e) {
1.92 - QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
1.93 - }
1.94 - },
1.95 - run: function() {
1.96 - if ( this.async ) {
1.97 - QUnit.stop();
1.98 - }
1.99 -
1.100 - if ( config.notrycatch ) {
1.101 - this.callback.call(this.testEnvironment);
1.102 - return;
1.103 - }
1.104 - try {
1.105 - this.callback.call(this.testEnvironment);
1.106 - } catch(e) {
1.107 - fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
1.108 - QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
1.109 - // else next test will carry the responsibility
1.110 - saveGlobal();
1.111 -
1.112 - // Restart the tests if they're blocking
1.113 - if ( config.blocking ) {
1.114 - start();
1.115 - }
1.116 - }
1.117 - },
1.118 - teardown: function() {
1.119 - try {
1.120 - this.testEnvironment.teardown.call(this.testEnvironment);
1.121 - checkPollution();
1.122 - } catch(e) {
1.123 - QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
1.124 - }
1.125 - },
1.126 - finish: function() {
1.127 - if ( this.expected && this.expected != this.assertions.length ) {
1.128 - QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
1.129 - }
1.130 -
1.131 - var good = 0, bad = 0,
1.132 - tests = id("qunit-tests");
1.133 -
1.134 - config.stats.all += this.assertions.length;
1.135 - config.moduleStats.all += this.assertions.length;
1.136 -
1.137 - if ( tests ) {
1.138 - var ol = document.createElement("ol");
1.139 -
1.140 - for ( var i = 0; i < this.assertions.length; i++ ) {
1.141 - var assertion = this.assertions[i];
1.142 -
1.143 - var li = document.createElement("li");
1.144 - li.className = assertion.result ? "pass" : "fail";
1.145 - li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
1.146 - ol.appendChild( li );
1.147 -
1.148 - if ( assertion.result ) {
1.149 - good++;
1.150 - } else {
1.151 - bad++;
1.152 - config.stats.bad++;
1.153 - config.moduleStats.bad++;
1.154 - }
1.155 - }
1.156 -
1.157 - // store result when possible
1.158 - if ( QUnit.config.reorder && defined.sessionStorage ) {
1.159 - if (bad) {
1.160 - sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
1.161 - } else {
1.162 - sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
1.163 - }
1.164 - }
1.165 -
1.166 - if (bad == 0) {
1.167 - ol.style.display = "none";
1.168 - }
1.169 -
1.170 - var b = document.createElement("strong");
1.171 - b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
1.172 -
1.173 - var a = document.createElement("a");
1.174 - a.innerHTML = "Rerun";
1.175 - a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
1.176 -
1.177 - addEvent(b, "click", function() {
1.178 - var next = b.nextSibling.nextSibling,
1.179 - display = next.style.display;
1.180 - next.style.display = display === "none" ? "block" : "none";
1.181 - });
1.182 -
1.183 - addEvent(b, "dblclick", function(e) {
1.184 - var target = e && e.target ? e.target : window.event.srcElement;
1.185 - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
1.186 - target = target.parentNode;
1.187 - }
1.188 - if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
1.189 - window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
1.190 - }
1.191 - });
1.192 -
1.193 - var li = id(this.id);
1.194 - li.className = bad ? "fail" : "pass";
1.195 - li.removeChild( li.firstChild );
1.196 - li.appendChild( b );
1.197 - li.appendChild( a );
1.198 - li.appendChild( ol );
1.199 -
1.200 - } else {
1.201 - for ( var i = 0; i < this.assertions.length; i++ ) {
1.202 - if ( !this.assertions[i].result ) {
1.203 - bad++;
1.204 - config.stats.bad++;
1.205 - config.moduleStats.bad++;
1.206 - }
1.207 - }
1.208 - }
1.209 -
1.210 - try {
1.211 - QUnit.reset();
1.212 - } catch(e) {
1.213 - fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
1.214 - }
1.215 -
1.216 - QUnit.testDone( {
1.217 - name: this.testName,
1.218 - failed: bad,
1.219 - passed: this.assertions.length - bad,
1.220 - total: this.assertions.length
1.221 - } );
1.222 - },
1.223 -
1.224 - queue: function() {
1.225 - var test = this;
1.226 - synchronize(function() {
1.227 - test.init();
1.228 - });
1.229 - function run() {
1.230 - // each of these can by async
1.231 - synchronize(function() {
1.232 - test.setup();
1.233 - });
1.234 - synchronize(function() {
1.235 - test.run();
1.236 - });
1.237 - synchronize(function() {
1.238 - test.teardown();
1.239 - });
1.240 - synchronize(function() {
1.241 - test.finish();
1.242 - });
1.243 - }
1.244 - // defer when previous test run passed, if storage is available
1.245 - var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
1.246 - if (bad) {
1.247 - run();
1.248 - } else {
1.249 - synchronize(run);
1.250 - };
1.251 - }
1.252 -
1.253 -};
1.254 -
1.255 -var QUnit = {
1.256 -
1.257 - // call on start of module test to prepend name to all tests
1.258 - module: function(name, testEnvironment) {
1.259 - config.currentModule = name;
1.260 - config.currentModuleTestEnviroment = testEnvironment;
1.261 - },
1.262 -
1.263 - asyncTest: function(testName, expected, callback) {
1.264 - if ( arguments.length === 2 ) {
1.265 - callback = expected;
1.266 - expected = 0;
1.267 - }
1.268 -
1.269 - QUnit.test(testName, expected, callback, true);
1.270 - },
1.271 -
1.272 - test: function(testName, expected, callback, async) {
1.273 - var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
1.274 -
1.275 - if ( arguments.length === 2 ) {
1.276 - callback = expected;
1.277 - expected = null;
1.278 - }
1.279 - // is 2nd argument a testEnvironment?
1.280 - if ( expected && typeof expected === 'object') {
1.281 - testEnvironmentArg = expected;
1.282 - expected = null;
1.283 - }
1.284 -
1.285 - if ( config.currentModule ) {
1.286 - name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
1.287 - }
1.288 -
1.289 - if ( !validTest(config.currentModule + ": " + testName) ) {
1.290 - return;
1.291 - }
1.292 -
1.293 - var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
1.294 - test.module = config.currentModule;
1.295 - test.moduleTestEnvironment = config.currentModuleTestEnviroment;
1.296 - test.queue();
1.297 - },
1.298 -
1.299 - /**
1.300 - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
1.301 - */
1.302 - expect: function(asserts) {
1.303 - config.current.expected = asserts;
1.304 - },
1.305 -
1.306 - /**
1.307 - * Asserts true.
1.308 - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
1.309 - */
1.310 - ok: function(a, msg) {
1.311 - a = !!a;
1.312 - var details = {
1.313 - result: a,
1.314 - message: msg
1.315 - };
1.316 - msg = escapeHtml(msg);
1.317 - QUnit.log(details);
1.318 - config.current.assertions.push({
1.319 - result: a,
1.320 - message: msg
1.321 - });
1.322 - },
1.323 -
1.324 - /**
1.325 - * Checks that the first two arguments are equal, with an optional message.
1.326 - * Prints out both actual and expected values.
1.327 - *
1.328 - * Prefered to ok( actual == expected, message )
1.329 - *
1.330 - * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
1.331 - *
1.332 - * @param Object actual
1.333 - * @param Object expected
1.334 - * @param String message (optional)
1.335 - */
1.336 - equal: function(actual, expected, message) {
1.337 - QUnit.push(expected == actual, actual, expected, message);
1.338 - },
1.339 -
1.340 - notEqual: function(actual, expected, message) {
1.341 - QUnit.push(expected != actual, actual, expected, message);
1.342 - },
1.343 -
1.344 - deepEqual: function(actual, expected, message) {
1.345 - QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
1.346 - },
1.347 -
1.348 - notDeepEqual: function(actual, expected, message) {
1.349 - QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
1.350 - },
1.351 -
1.352 - strictEqual: function(actual, expected, message) {
1.353 - QUnit.push(expected === actual, actual, expected, message);
1.354 - },
1.355 -
1.356 - notStrictEqual: function(actual, expected, message) {
1.357 - QUnit.push(expected !== actual, actual, expected, message);
1.358 - },
1.359 -
1.360 - raises: function(block, expected, message) {
1.361 - var actual, ok = false;
1.362 -
1.363 - if (typeof expected === 'string') {
1.364 - message = expected;
1.365 - expected = null;
1.366 - }
1.367 -
1.368 - try {
1.369 - block();
1.370 - } catch (e) {
1.371 - actual = e;
1.372 - }
1.373 -
1.374 - if (actual) {
1.375 - // we don't want to validate thrown error
1.376 - if (!expected) {
1.377 - ok = true;
1.378 - // expected is a regexp
1.379 - } else if (QUnit.objectType(expected) === "regexp") {
1.380 - ok = expected.test(actual);
1.381 - // expected is a constructor
1.382 - } else if (actual instanceof expected) {
1.383 - ok = true;
1.384 - // expected is a validation function which returns true is validation passed
1.385 - } else if (expected.call({}, actual) === true) {
1.386 - ok = true;
1.387 - }
1.388 - }
1.389 -
1.390 - QUnit.ok(ok, message);
1.391 - },
1.392 -
1.393 - start: function() {
1.394 - config.semaphore--;
1.395 - if (config.semaphore > 0) {
1.396 - // don't start until equal number of stop-calls
1.397 - return;
1.398 - }
1.399 - if (config.semaphore < 0) {
1.400 - // ignore if start is called more often then stop
1.401 - config.semaphore = 0;
1.402 - }
1.403 - // A slight delay, to avoid any current callbacks
1.404 - if ( defined.setTimeout ) {
1.405 - window.setTimeout(function() {
1.406 - if (config.semaphore > 0) {
1.407 - return;
1.408 - }
1.409 - if ( config.timeout ) {
1.410 - clearTimeout(config.timeout);
1.411 - }
1.412 -
1.413 - config.blocking = false;
1.414 - process();
1.415 - }, 13);
1.416 - } else {
1.417 - config.blocking = false;
1.418 - process();
1.419 - }
1.420 - },
1.421 -
1.422 - stop: function(timeout) {
1.423 - config.semaphore++;
1.424 - config.blocking = true;
1.425 -
1.426 - if ( timeout && defined.setTimeout ) {
1.427 - clearTimeout(config.timeout);
1.428 - config.timeout = window.setTimeout(function() {
1.429 - QUnit.ok( false, "Test timed out" );
1.430 - QUnit.start();
1.431 - }, timeout);
1.432 - }
1.433 - }
1.434 -};
1.435 -
1.436 -// Backwards compatibility, deprecated
1.437 -QUnit.equals = QUnit.equal;
1.438 -QUnit.same = QUnit.deepEqual;
1.439 -
1.440 -// Maintain internal state
1.441 -var config = {
1.442 - // The queue of tests to run
1.443 - queue: [],
1.444 -
1.445 - // block until document ready
1.446 - blocking: true,
1.447 -
1.448 - // when enabled, show only failing tests
1.449 - // gets persisted through sessionStorage and can be changed in UI via checkbox
1.450 - hidepassed: false,
1.451 -
1.452 - // by default, run previously failed tests first
1.453 - // very useful in combination with "Hide passed tests" checked
1.454 - reorder: true,
1.455 -
1.456 - // by default, modify document.title when suite is done
1.457 - altertitle: true,
1.458 -
1.459 - urlConfig: ['noglobals', 'notrycatch']
1.460 -};
1.461 -
1.462 -// Load paramaters
1.463 -(function() {
1.464 - var location = window.location || { search: "", protocol: "file:" },
1.465 - params = location.search.slice( 1 ).split( "&" ),
1.466 - length = params.length,
1.467 - urlParams = {},
1.468 - current;
1.469 -
1.470 - if ( params[ 0 ] ) {
1.471 - for ( var i = 0; i < length; i++ ) {
1.472 - current = params[ i ].split( "=" );
1.473 - current[ 0 ] = decodeURIComponent( current[ 0 ] );
1.474 - // allow just a key to turn on a flag, e.g., test.html?noglobals
1.475 - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
1.476 - urlParams[ current[ 0 ] ] = current[ 1 ];
1.477 - }
1.478 - }
1.479 -
1.480 - QUnit.urlParams = urlParams;
1.481 - config.filter = urlParams.filter;
1.482 -
1.483 - // Figure out if we're running the tests from a server or not
1.484 - QUnit.isLocal = !!(location.protocol === 'file:');
1.485 -})();
1.486 -
1.487 -// Expose the API as global variables, unless an 'exports'
1.488 -// object exists, in that case we assume we're in CommonJS
1.489 -if ( typeof exports === "undefined" || typeof require === "undefined" ) {
1.490 - extend(window, QUnit);
1.491 - window.QUnit = QUnit;
1.492 -} else {
1.493 - extend(exports, QUnit);
1.494 - exports.QUnit = QUnit;
1.495 -}
1.496 -
1.497 -// define these after exposing globals to keep them in these QUnit namespace only
1.498 -extend(QUnit, {
1.499 - config: config,
1.500 -
1.501 - // Initialize the configuration options
1.502 - init: function() {
1.503 - extend(config, {
1.504 - stats: { all: 0, bad: 0 },
1.505 - moduleStats: { all: 0, bad: 0 },
1.506 - started: +new Date,
1.507 - updateRate: 1000,
1.508 - blocking: false,
1.509 - autostart: true,
1.510 - autorun: false,
1.511 - filter: "",
1.512 - queue: [],
1.513 - semaphore: 0
1.514 - });
1.515 -
1.516 - var tests = id( "qunit-tests" ),
1.517 - banner = id( "qunit-banner" ),
1.518 - result = id( "qunit-testresult" );
1.519 -
1.520 - if ( tests ) {
1.521 - tests.innerHTML = "";
1.522 - }
1.523 -
1.524 - if ( banner ) {
1.525 - banner.className = "";
1.526 - }
1.527 -
1.528 - if ( result ) {
1.529 - result.parentNode.removeChild( result );
1.530 - }
1.531 -
1.532 - if ( tests ) {
1.533 - result = document.createElement( "p" );
1.534 - result.id = "qunit-testresult";
1.535 - result.className = "result";
1.536 - tests.parentNode.insertBefore( result, tests );
1.537 - result.innerHTML = 'Running...<br/> ';
1.538 - }
1.539 - },
1.540 -
1.541 - /**
1.542 - * Resets the test setup. Useful for tests that modify the DOM.
1.543 - *
1.544 - * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
1.545 - */
1.546 - reset: function() {
1.547 - if ( window.jQuery ) {
1.548 - jQuery( "#qunit-fixture" ).html( config.fixture );
1.549 - } else {
1.550 - var main = id( 'qunit-fixture' );
1.551 - if ( main ) {
1.552 - main.innerHTML = config.fixture;
1.553 - }
1.554 - }
1.555 - },
1.556 -
1.557 - /**
1.558 - * Trigger an event on an element.
1.559 - *
1.560 - * @example triggerEvent( document.body, "click" );
1.561 - *
1.562 - * @param DOMElement elem
1.563 - * @param String type
1.564 - */
1.565 - triggerEvent: function( elem, type, event ) {
1.566 - if ( document.createEvent ) {
1.567 - event = document.createEvent("MouseEvents");
1.568 - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
1.569 - 0, 0, 0, 0, 0, false, false, false, false, 0, null);
1.570 - elem.dispatchEvent( event );
1.571 -
1.572 - } else if ( elem.fireEvent ) {
1.573 - elem.fireEvent("on"+type);
1.574 - }
1.575 - },
1.576 -
1.577 - // Safe object type checking
1.578 - is: function( type, obj ) {
1.579 - return QUnit.objectType( obj ) == type;
1.580 - },
1.581 -
1.582 - objectType: function( obj ) {
1.583 - if (typeof obj === "undefined") {
1.584 - return "undefined";
1.585 -
1.586 - // consider: typeof null === object
1.587 - }
1.588 - if (obj === null) {
1.589 - return "null";
1.590 - }
1.591 -
1.592 - var type = Object.prototype.toString.call( obj )
1.593 - .match(/^\[object\s(.*)\]$/)[1] || '';
1.594 -
1.595 - switch (type) {
1.596 - case 'Number':
1.597 - if (isNaN(obj)) {
1.598 - return "nan";
1.599 - } else {
1.600 - return "number";
1.601 - }
1.602 - case 'String':
1.603 - case 'Boolean':
1.604 - case 'Array':
1.605 - case 'Date':
1.606 - case 'RegExp':
1.607 - case 'Function':
1.608 - return type.toLowerCase();
1.609 - }
1.610 - if (typeof obj === "object") {
1.611 - return "object";
1.612 - }
1.613 - return undefined;
1.614 - },
1.615 -
1.616 - push: function(result, actual, expected, message) {
1.617 - var details = {
1.618 - result: result,
1.619 - message: message,
1.620 - actual: actual,
1.621 - expected: expected
1.622 - };
1.623 -
1.624 - message = escapeHtml(message) || (result ? "okay" : "failed");
1.625 - message = '<span class="test-message">' + message + "</span>";
1.626 - expected = escapeHtml(QUnit.jsDump.parse(expected));
1.627 - actual = escapeHtml(QUnit.jsDump.parse(actual));
1.628 - var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
1.629 - if (actual != expected) {
1.630 - output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
1.631 - output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
1.632 - }
1.633 - if (!result) {
1.634 - var source = sourceFromStacktrace();
1.635 - if (source) {
1.636 - details.source = source;
1.637 - output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeHtml(source) + '</pre></td></tr>';
1.638 - }
1.639 - }
1.640 - output += "</table>";
1.641 -
1.642 - QUnit.log(details);
1.643 -
1.644 - config.current.assertions.push({
1.645 - result: !!result,
1.646 - message: output
1.647 - });
1.648 - },
1.649 -
1.650 - url: function( params ) {
1.651 - params = extend( extend( {}, QUnit.urlParams ), params );
1.652 - var querystring = "?",
1.653 - key;
1.654 - for ( key in params ) {
1.655 - querystring += encodeURIComponent( key ) + "=" +
1.656 - encodeURIComponent( params[ key ] ) + "&";
1.657 - }
1.658 - return window.location.pathname + querystring.slice( 0, -1 );
1.659 - },
1.660 -
1.661 - extend: extend,
1.662 - id: id,
1.663 - addEvent: addEvent,
1.664 -
1.665 - // Logging callbacks; all receive a single argument with the listed properties
1.666 - // run test/logs.html for any related changes
1.667 - begin: function() {},
1.668 - // done: { failed, passed, total, runtime }
1.669 - done: function() {},
1.670 - // log: { result, actual, expected, message }
1.671 - log: function() {},
1.672 - // testStart: { name }
1.673 - testStart: function() {},
1.674 - // testDone: { name, failed, passed, total }
1.675 - testDone: function() {},
1.676 - // moduleStart: { name }
1.677 - moduleStart: function() {},
1.678 - // moduleDone: { name, failed, passed, total }
1.679 - moduleDone: function() {}
1.680 -});
1.681 -
1.682 -if ( typeof document === "undefined" || document.readyState === "complete" ) {
1.683 - config.autorun = true;
1.684 -}
1.685 -
1.686 -QUnit.load = function() {
1.687 - QUnit.begin({});
1.688 -
1.689 - // Initialize the config, saving the execution queue
1.690 - var oldconfig = extend({}, config);
1.691 - QUnit.init();
1.692 - extend(config, oldconfig);
1.693 -
1.694 - config.blocking = false;
1.695 -
1.696 - var urlConfigHtml = '', len = config.urlConfig.length;
1.697 - for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
1.698 - config[val] = QUnit.urlParams[val];
1.699 - urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
1.700 - }
1.701 -
1.702 - var userAgent = id("qunit-userAgent");
1.703 - if ( userAgent ) {
1.704 - userAgent.innerHTML = navigator.userAgent;
1.705 - }
1.706 - var banner = id("qunit-header");
1.707 - if ( banner ) {
1.708 - banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
1.709 - addEvent( banner, "change", function( event ) {
1.710 - var params = {};
1.711 - params[ event.target.name ] = event.target.checked ? true : undefined;
1.712 - window.location = QUnit.url( params );
1.713 - });
1.714 - }
1.715 -
1.716 - var toolbar = id("qunit-testrunner-toolbar");
1.717 - if ( toolbar ) {
1.718 - var filter = document.createElement("input");
1.719 - filter.type = "checkbox";
1.720 - filter.id = "qunit-filter-pass";
1.721 - addEvent( filter, "click", function() {
1.722 - var ol = document.getElementById("qunit-tests");
1.723 - if ( filter.checked ) {
1.724 - ol.className = ol.className + " hidepass";
1.725 - } else {
1.726 - var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
1.727 - ol.className = tmp.replace(/ hidepass /, " ");
1.728 - }
1.729 - if ( defined.sessionStorage ) {
1.730 - if (filter.checked) {
1.731 - sessionStorage.setItem("qunit-filter-passed-tests", "true");
1.732 - } else {
1.733 - sessionStorage.removeItem("qunit-filter-passed-tests");
1.734 - }
1.735 - }
1.736 - });
1.737 - if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
1.738 - filter.checked = true;
1.739 - var ol = document.getElementById("qunit-tests");
1.740 - ol.className = ol.className + " hidepass";
1.741 - }
1.742 - toolbar.appendChild( filter );
1.743 -
1.744 - var label = document.createElement("label");
1.745 - label.setAttribute("for", "qunit-filter-pass");
1.746 - label.innerHTML = "Hide passed tests";
1.747 - toolbar.appendChild( label );
1.748 - }
1.749 -
1.750 - var main = id('qunit-fixture');
1.751 - if ( main ) {
1.752 - config.fixture = main.innerHTML;
1.753 - }
1.754 -
1.755 - if (config.autostart) {
1.756 - QUnit.start();
1.757 - }
1.758 -};
1.759 -
1.760 -addEvent(window, "load", QUnit.load);
1.761 -
1.762 -function done() {
1.763 - config.autorun = true;
1.764 -
1.765 - // Log the last module results
1.766 - if ( config.currentModule ) {
1.767 - QUnit.moduleDone( {
1.768 - name: config.currentModule,
1.769 - failed: config.moduleStats.bad,
1.770 - passed: config.moduleStats.all - config.moduleStats.bad,
1.771 - total: config.moduleStats.all
1.772 - } );
1.773 - }
1.774 -
1.775 - var banner = id("qunit-banner"),
1.776 - tests = id("qunit-tests"),
1.777 - runtime = +new Date - config.started,
1.778 - passed = config.stats.all - config.stats.bad,
1.779 - html = [
1.780 - 'Tests completed in ',
1.781 - runtime,
1.782 - ' milliseconds.<br/>',
1.783 - '<span class="passed">',
1.784 - passed,
1.785 - '</span> tests of <span class="total">',
1.786 - config.stats.all,
1.787 - '</span> passed, <span class="failed">',
1.788 - config.stats.bad,
1.789 - '</span> failed.'
1.790 - ].join('');
1.791 -
1.792 - if ( banner ) {
1.793 - banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
1.794 - }
1.795 -
1.796 - if ( tests ) {
1.797 - id( "qunit-testresult" ).innerHTML = html;
1.798 - }
1.799 -
1.800 - if ( config.altertitle && typeof document !== "undefined" && document.title ) {
1.801 - // show ✖ for good, ✔ for bad suite result in title
1.802 - // use escape sequences in case file gets loaded with non-utf-8-charset
1.803 - document.title = [
1.804 - (config.stats.bad ? "\u2716" : "\u2714"),
1.805 - document.title.replace(/^[\u2714\u2716] /i, "")
1.806 - ].join(" ");
1.807 - }
1.808 -
1.809 - QUnit.done( {
1.810 - failed: config.stats.bad,
1.811 - passed: passed,
1.812 - total: config.stats.all,
1.813 - runtime: runtime
1.814 - } );
1.815 -}
1.816 -
1.817 -function validTest( name ) {
1.818 - var filter = config.filter,
1.819 - run = false;
1.820 -
1.821 - if ( !filter ) {
1.822 - return true;
1.823 - }
1.824 -
1.825 - var not = filter.charAt( 0 ) === "!";
1.826 - if ( not ) {
1.827 - filter = filter.slice( 1 );
1.828 - }
1.829 -
1.830 - if ( name.indexOf( filter ) !== -1 ) {
1.831 - return !not;
1.832 - }
1.833 -
1.834 - if ( not ) {
1.835 - run = true;
1.836 - }
1.837 -
1.838 - return run;
1.839 -}
1.840 -
1.841 -// so far supports only Firefox, Chrome and Opera (buggy)
1.842 -// could be extended in the future to use something like https://github.com/csnover/TraceKit
1.843 -function sourceFromStacktrace() {
1.844 - try {
1.845 - throw new Error();
1.846 - } catch ( e ) {
1.847 - if (e.stacktrace) {
1.848 - // Opera
1.849 - return e.stacktrace.split("\n")[6];
1.850 - } else if (e.stack) {
1.851 - // Firefox, Chrome
1.852 - return e.stack.split("\n")[4];
1.853 - } else if (e.sourceURL) {
1.854 - // Safari, PhantomJS
1.855 - // TODO sourceURL points at the 'throw new Error' line above, useless
1.856 - //return e.sourceURL + ":" + e.line;
1.857 - }
1.858 - }
1.859 -}
1.860 -
1.861 -function escapeHtml(s) {
1.862 - if (!s) {
1.863 - return "";
1.864 - }
1.865 - s = s + "";
1.866 - return s.replace(/[\&"<>\\]/g, function(s) {
1.867 - switch(s) {
1.868 - case "&": return "&";
1.869 - case "\\": return "\\\\";
1.870 - case '"': return '\"';
1.871 - case "<": return "<";
1.872 - case ">": return ">";
1.873 - default: return s;
1.874 - }
1.875 - });
1.876 -}
1.877 -
1.878 -function synchronize( callback ) {
1.879 - config.queue.push( callback );
1.880 -
1.881 - if ( config.autorun && !config.blocking ) {
1.882 - process();
1.883 - }
1.884 -}
1.885 -
1.886 -function process() {
1.887 - var start = (new Date()).getTime();
1.888 -
1.889 - while ( config.queue.length && !config.blocking ) {
1.890 - if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
1.891 - config.queue.shift()();
1.892 - } else {
1.893 - window.setTimeout( process, 13 );
1.894 - break;
1.895 - }
1.896 - }
1.897 - if (!config.blocking && !config.queue.length) {
1.898 - done();
1.899 - }
1.900 -}
1.901 -
1.902 -function saveGlobal() {
1.903 - config.pollution = [];
1.904 -
1.905 - if ( config.noglobals ) {
1.906 - for ( var key in window ) {
1.907 - config.pollution.push( key );
1.908 - }
1.909 - }
1.910 -}
1.911 -
1.912 -function checkPollution( name ) {
1.913 - var old = config.pollution;
1.914 - saveGlobal();
1.915 -
1.916 - var newGlobals = diff( config.pollution, old );
1.917 - if ( newGlobals.length > 0 ) {
1.918 - ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
1.919 - }
1.920 -
1.921 - var deletedGlobals = diff( old, config.pollution );
1.922 - if ( deletedGlobals.length > 0 ) {
1.923 - ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
1.924 - }
1.925 -}
1.926 -
1.927 -// returns a new Array with the elements that are in a but not in b
1.928 -function diff( a, b ) {
1.929 - var result = a.slice();
1.930 - for ( var i = 0; i < result.length; i++ ) {
1.931 - for ( var j = 0; j < b.length; j++ ) {
1.932 - if ( result[i] === b[j] ) {
1.933 - result.splice(i, 1);
1.934 - i--;
1.935 - break;
1.936 - }
1.937 - }
1.938 - }
1.939 - return result;
1.940 -}
1.941 -
1.942 -function fail(message, exception, callback) {
1.943 - if ( typeof console !== "undefined" && console.error && console.warn ) {
1.944 - console.error(message);
1.945 - console.error(exception);
1.946 - console.warn(callback.toString());
1.947 -
1.948 - } else if ( window.opera && opera.postError ) {
1.949 - opera.postError(message, exception, callback.toString);
1.950 - }
1.951 -}
1.952 -
1.953 -function extend(a, b) {
1.954 - for ( var prop in b ) {
1.955 - if ( b[prop] === undefined ) {
1.956 - delete a[prop];
1.957 - } else {
1.958 - a[prop] = b[prop];
1.959 - }
1.960 - }
1.961 -
1.962 - return a;
1.963 -}
1.964 -
1.965 -function addEvent(elem, type, fn) {
1.966 - if ( elem.addEventListener ) {
1.967 - elem.addEventListener( type, fn, false );
1.968 - } else if ( elem.attachEvent ) {
1.969 - elem.attachEvent( "on" + type, fn );
1.970 - } else {
1.971 - fn();
1.972 - }
1.973 -}
1.974 -
1.975 -function id(name) {
1.976 - return !!(typeof document !== "undefined" && document && document.getElementById) &&
1.977 - document.getElementById( name );
1.978 -}
1.979 -
1.980 -// Test for equality any JavaScript type.
1.981 -// Discussions and reference: http://philrathe.com/articles/equiv
1.982 -// Test suites: http://philrathe.com/tests/equiv
1.983 -// Author: Philippe Rathé <prathe@gmail.com>
1.984 -QUnit.equiv = function () {
1.985 -
1.986 - var innerEquiv; // the real equiv function
1.987 - var callers = []; // stack to decide between skip/abort functions
1.988 - var parents = []; // stack to avoiding loops from circular referencing
1.989 -
1.990 - // Call the o related callback with the given arguments.
1.991 - function bindCallbacks(o, callbacks, args) {
1.992 - var prop = QUnit.objectType(o);
1.993 - if (prop) {
1.994 - if (QUnit.objectType(callbacks[prop]) === "function") {
1.995 - return callbacks[prop].apply(callbacks, args);
1.996 - } else {
1.997 - return callbacks[prop]; // or undefined
1.998 - }
1.999 - }
1.1000 - }
1.1001 -
1.1002 - var callbacks = function () {
1.1003 -
1.1004 - // for string, boolean, number and null
1.1005 - function useStrictEquality(b, a) {
1.1006 - if (b instanceof a.constructor || a instanceof b.constructor) {
1.1007 - // to catch short annotaion VS 'new' annotation of a
1.1008 - // declaration
1.1009 - // e.g. var i = 1;
1.1010 - // var j = new Number(1);
1.1011 - return a == b;
1.1012 - } else {
1.1013 - return a === b;
1.1014 - }
1.1015 - }
1.1016 -
1.1017 - return {
1.1018 - "string" : useStrictEquality,
1.1019 - "boolean" : useStrictEquality,
1.1020 - "number" : useStrictEquality,
1.1021 - "null" : useStrictEquality,
1.1022 - "undefined" : useStrictEquality,
1.1023 -
1.1024 - "nan" : function(b) {
1.1025 - return isNaN(b);
1.1026 - },
1.1027 -
1.1028 - "date" : function(b, a) {
1.1029 - return QUnit.objectType(b) === "date"
1.1030 - && a.valueOf() === b.valueOf();
1.1031 - },
1.1032 -
1.1033 - "regexp" : function(b, a) {
1.1034 - return QUnit.objectType(b) === "regexp"
1.1035 - && a.source === b.source && // the regex itself
1.1036 - a.global === b.global && // and its modifers
1.1037 - // (gmi) ...
1.1038 - a.ignoreCase === b.ignoreCase
1.1039 - && a.multiline === b.multiline;
1.1040 - },
1.1041 -
1.1042 - // - skip when the property is a method of an instance (OOP)
1.1043 - // - abort otherwise,
1.1044 - // initial === would have catch identical references anyway
1.1045 - "function" : function() {
1.1046 - var caller = callers[callers.length - 1];
1.1047 - return caller !== Object && typeof caller !== "undefined";
1.1048 - },
1.1049 -
1.1050 - "array" : function(b, a) {
1.1051 - var i, j, loop;
1.1052 - var len;
1.1053 -
1.1054 - // b could be an object literal here
1.1055 - if (!(QUnit.objectType(b) === "array")) {
1.1056 - return false;
1.1057 - }
1.1058 -
1.1059 - len = a.length;
1.1060 - if (len !== b.length) { // safe and faster
1.1061 - return false;
1.1062 - }
1.1063 -
1.1064 - // track reference to avoid circular references
1.1065 - parents.push(a);
1.1066 - for (i = 0; i < len; i++) {
1.1067 - loop = false;
1.1068 - for (j = 0; j < parents.length; j++) {
1.1069 - if (parents[j] === a[i]) {
1.1070 - loop = true;// dont rewalk array
1.1071 - }
1.1072 - }
1.1073 - if (!loop && !innerEquiv(a[i], b[i])) {
1.1074 - parents.pop();
1.1075 - return false;
1.1076 - }
1.1077 - }
1.1078 - parents.pop();
1.1079 - return true;
1.1080 - },
1.1081 -
1.1082 - "object" : function(b, a) {
1.1083 - var i, j, loop;
1.1084 - var eq = true; // unless we can proove it
1.1085 - var aProperties = [], bProperties = []; // collection of
1.1086 - // strings
1.1087 -
1.1088 - // comparing constructors is more strict than using
1.1089 - // instanceof
1.1090 - if (a.constructor !== b.constructor) {
1.1091 - return false;
1.1092 - }
1.1093 -
1.1094 - // stack constructor before traversing properties
1.1095 - callers.push(a.constructor);
1.1096 - // track reference to avoid circular references
1.1097 - parents.push(a);
1.1098 -
1.1099 - for (i in a) { // be strict: don't ensures hasOwnProperty
1.1100 - // and go deep
1.1101 - loop = false;
1.1102 - for (j = 0; j < parents.length; j++) {
1.1103 - if (parents[j] === a[i])
1.1104 - loop = true; // don't go down the same path
1.1105 - // twice
1.1106 - }
1.1107 - aProperties.push(i); // collect a's properties
1.1108 -
1.1109 - if (!loop && !innerEquiv(a[i], b[i])) {
1.1110 - eq = false;
1.1111 - break;
1.1112 - }
1.1113 - }
1.1114 -
1.1115 - callers.pop(); // unstack, we are done
1.1116 - parents.pop();
1.1117 -
1.1118 - for (i in b) {
1.1119 - bProperties.push(i); // collect b's properties
1.1120 - }
1.1121 -
1.1122 - // Ensures identical properties name
1.1123 - return eq
1.1124 - && innerEquiv(aProperties.sort(), bProperties
1.1125 - .sort());
1.1126 - }
1.1127 - };
1.1128 - }();
1.1129 -
1.1130 - innerEquiv = function() { // can take multiple arguments
1.1131 - var args = Array.prototype.slice.apply(arguments);
1.1132 - if (args.length < 2) {
1.1133 - return true; // end transition
1.1134 - }
1.1135 -
1.1136 - return (function(a, b) {
1.1137 - if (a === b) {
1.1138 - return true; // catch the most you can
1.1139 - } else if (a === null || b === null || typeof a === "undefined"
1.1140 - || typeof b === "undefined"
1.1141 - || QUnit.objectType(a) !== QUnit.objectType(b)) {
1.1142 - return false; // don't lose time with error prone cases
1.1143 - } else {
1.1144 - return bindCallbacks(a, callbacks, [ b, a ]);
1.1145 - }
1.1146 -
1.1147 - // apply transition with (1..n) arguments
1.1148 - })(args[0], args[1])
1.1149 - && arguments.callee.apply(this, args.splice(1,
1.1150 - args.length - 1));
1.1151 - };
1.1152 -
1.1153 - return innerEquiv;
1.1154 -
1.1155 -}();
1.1156 -
1.1157 -/**
1.1158 - * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
1.1159 - * http://flesler.blogspot.com Licensed under BSD
1.1160 - * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
1.1161 - *
1.1162 - * @projectDescription Advanced and extensible data dumping for Javascript.
1.1163 - * @version 1.0.0
1.1164 - * @author Ariel Flesler
1.1165 - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
1.1166 - */
1.1167 -QUnit.jsDump = (function() {
1.1168 - function quote( str ) {
1.1169 - return '"' + str.toString().replace(/"/g, '\\"') + '"';
1.1170 - };
1.1171 - function literal( o ) {
1.1172 - return o + '';
1.1173 - };
1.1174 - function join( pre, arr, post ) {
1.1175 - var s = jsDump.separator(),
1.1176 - base = jsDump.indent(),
1.1177 - inner = jsDump.indent(1);
1.1178 - if ( arr.join )
1.1179 - arr = arr.join( ',' + s + inner );
1.1180 - if ( !arr )
1.1181 - return pre + post;
1.1182 - return [ pre, inner + arr, base + post ].join(s);
1.1183 - };
1.1184 - function array( arr, stack ) {
1.1185 - var i = arr.length, ret = Array(i);
1.1186 - this.up();
1.1187 - while ( i-- )
1.1188 - ret[i] = this.parse( arr[i] , undefined , stack);
1.1189 - this.down();
1.1190 - return join( '[', ret, ']' );
1.1191 - };
1.1192 -
1.1193 - var reName = /^function (\w+)/;
1.1194 -
1.1195 - var jsDump = {
1.1196 - parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
1.1197 - stack = stack || [ ];
1.1198 - var parser = this.parsers[ type || this.typeOf(obj) ];
1.1199 - type = typeof parser;
1.1200 - var inStack = inArray(obj, stack);
1.1201 - if (inStack != -1) {
1.1202 - return 'recursion('+(inStack - stack.length)+')';
1.1203 - }
1.1204 - //else
1.1205 - if (type == 'function') {
1.1206 - stack.push(obj);
1.1207 - var res = parser.call( this, obj, stack );
1.1208 - stack.pop();
1.1209 - return res;
1.1210 - }
1.1211 - // else
1.1212 - return (type == 'string') ? parser : this.parsers.error;
1.1213 - },
1.1214 - typeOf:function( obj ) {
1.1215 - var type;
1.1216 - if ( obj === null ) {
1.1217 - type = "null";
1.1218 - } else if (typeof obj === "undefined") {
1.1219 - type = "undefined";
1.1220 - } else if (QUnit.is("RegExp", obj)) {
1.1221 - type = "regexp";
1.1222 - } else if (QUnit.is("Date", obj)) {
1.1223 - type = "date";
1.1224 - } else if (QUnit.is("Function", obj)) {
1.1225 - type = "function";
1.1226 - } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
1.1227 - type = "window";
1.1228 - } else if (obj.nodeType === 9) {
1.1229 - type = "document";
1.1230 - } else if (obj.nodeType) {
1.1231 - type = "node";
1.1232 - } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
1.1233 - type = "array";
1.1234 - } else {
1.1235 - type = typeof obj;
1.1236 - }
1.1237 - return type;
1.1238 - },
1.1239 - separator:function() {
1.1240 - return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? ' ' : ' ';
1.1241 - },
1.1242 - indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1.1243 - if ( !this.multiline )
1.1244 - return '';
1.1245 - var chr = this.indentChar;
1.1246 - if ( this.HTML )
1.1247 - chr = chr.replace(/\t/g,' ').replace(/ /g,' ');
1.1248 - return Array( this._depth_ + (extra||0) ).join(chr);
1.1249 - },
1.1250 - up:function( a ) {
1.1251 - this._depth_ += a || 1;
1.1252 - },
1.1253 - down:function( a ) {
1.1254 - this._depth_ -= a || 1;
1.1255 - },
1.1256 - setParser:function( name, parser ) {
1.1257 - this.parsers[name] = parser;
1.1258 - },
1.1259 - // The next 3 are exposed so you can use them
1.1260 - quote:quote,
1.1261 - literal:literal,
1.1262 - join:join,
1.1263 - //
1.1264 - _depth_: 1,
1.1265 - // This is the list of parsers, to modify them, use jsDump.setParser
1.1266 - parsers:{
1.1267 - window: '[Window]',
1.1268 - document: '[Document]',
1.1269 - error:'[ERROR]', //when no parser is found, shouldn't happen
1.1270 - unknown: '[Unknown]',
1.1271 - 'null':'null',
1.1272 - 'undefined':'undefined',
1.1273 - 'function':function( fn ) {
1.1274 - var ret = 'function',
1.1275 - name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
1.1276 - if ( name )
1.1277 - ret += ' ' + name;
1.1278 - ret += '(';
1.1279 -
1.1280 - ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
1.1281 - return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
1.1282 - },
1.1283 - array: array,
1.1284 - nodelist: array,
1.1285 - arguments: array,
1.1286 - object:function( map, stack ) {
1.1287 - var ret = [ ];
1.1288 - QUnit.jsDump.up();
1.1289 - for ( var key in map ) {
1.1290 - var val = map[key];
1.1291 - ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
1.1292 - }
1.1293 - QUnit.jsDump.down();
1.1294 - return join( '{', ret, '}' );
1.1295 - },
1.1296 - node:function( node ) {
1.1297 - var open = QUnit.jsDump.HTML ? '<' : '<',
1.1298 - close = QUnit.jsDump.HTML ? '>' : '>';
1.1299 -
1.1300 - var tag = node.nodeName.toLowerCase(),
1.1301 - ret = open + tag;
1.1302 -
1.1303 - for ( var a in QUnit.jsDump.DOMAttrs ) {
1.1304 - var val = node[QUnit.jsDump.DOMAttrs[a]];
1.1305 - if ( val )
1.1306 - ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
1.1307 - }
1.1308 - return ret + close + open + '/' + tag + close;
1.1309 - },
1.1310 - functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
1.1311 - var l = fn.length;
1.1312 - if ( !l ) return '';
1.1313 -
1.1314 - var args = Array(l);
1.1315 - while ( l-- )
1.1316 - args[l] = String.fromCharCode(97+l);//97 is 'a'
1.1317 - return ' ' + args.join(', ') + ' ';
1.1318 - },
1.1319 - key:quote, //object calls it internally, the key part of an item in a map
1.1320 - functionCode:'[code]', //function calls it internally, it's the content of the function
1.1321 - attribute:quote, //node calls it internally, it's an html attribute value
1.1322 - string:quote,
1.1323 - date:quote,
1.1324 - regexp:literal, //regex
1.1325 - number:literal,
1.1326 - 'boolean':literal
1.1327 - },
1.1328 - DOMAttrs:{//attributes to dump from nodes, name=>realName
1.1329 - id:'id',
1.1330 - name:'name',
1.1331 - 'class':'className'
1.1332 - },
1.1333 - HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
1.1334 - indentChar:' ',//indentation unit
1.1335 - multiline:true //if true, items in a collection, are separated by a \n, else just a space.
1.1336 - };
1.1337 -
1.1338 - return jsDump;
1.1339 -})();
1.1340 -
1.1341 -// from Sizzle.js
1.1342 -function getText( elems ) {
1.1343 - var ret = "", elem;
1.1344 -
1.1345 - for ( var i = 0; elems[i]; i++ ) {
1.1346 - elem = elems[i];
1.1347 -
1.1348 - // Get the text from text nodes and CDATA nodes
1.1349 - if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
1.1350 - ret += elem.nodeValue;
1.1351 -
1.1352 - // Traverse everything else, except comment nodes
1.1353 - } else if ( elem.nodeType !== 8 ) {
1.1354 - ret += getText( elem.childNodes );
1.1355 - }
1.1356 - }
1.1357 -
1.1358 - return ret;
1.1359 -};
1.1360 -
1.1361 -//from jquery.js
1.1362 -function inArray( elem, array ) {
1.1363 - if ( array.indexOf ) {
1.1364 - return array.indexOf( elem );
1.1365 - }
1.1366 -
1.1367 - for ( var i = 0, length = array.length; i < length; i++ ) {
1.1368 - if ( array[ i ] === elem ) {
1.1369 - return i;
1.1370 - }
1.1371 - }
1.1372 -
1.1373 - return -1;
1.1374 -}
1.1375 -
1.1376 -/*
1.1377 - * Javascript Diff Algorithm
1.1378 - * By John Resig (http://ejohn.org/)
1.1379 - * Modified by Chu Alan "sprite"
1.1380 - *
1.1381 - * Released under the MIT license.
1.1382 - *
1.1383 - * More Info:
1.1384 - * http://ejohn.org/projects/javascript-diff-algorithm/
1.1385 - *
1.1386 - * Usage: QUnit.diff(expected, actual)
1.1387 - *
1.1388 - * 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"
1.1389 - */
1.1390 -QUnit.diff = (function() {
1.1391 - function diff(o, n) {
1.1392 - var ns = {};
1.1393 - var os = {};
1.1394 -
1.1395 - for (var i = 0; i < n.length; i++) {
1.1396 - if (ns[n[i]] == null)
1.1397 - ns[n[i]] = {
1.1398 - rows: [],
1.1399 - o: null
1.1400 - };
1.1401 - ns[n[i]].rows.push(i);
1.1402 - }
1.1403 -
1.1404 - for (var i = 0; i < o.length; i++) {
1.1405 - if (os[o[i]] == null)
1.1406 - os[o[i]] = {
1.1407 - rows: [],
1.1408 - n: null
1.1409 - };
1.1410 - os[o[i]].rows.push(i);
1.1411 - }
1.1412 -
1.1413 - for (var i in ns) {
1.1414 - if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
1.1415 - n[ns[i].rows[0]] = {
1.1416 - text: n[ns[i].rows[0]],
1.1417 - row: os[i].rows[0]
1.1418 - };
1.1419 - o[os[i].rows[0]] = {
1.1420 - text: o[os[i].rows[0]],
1.1421 - row: ns[i].rows[0]
1.1422 - };
1.1423 - }
1.1424 - }
1.1425 -
1.1426 - for (var i = 0; i < n.length - 1; i++) {
1.1427 - if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
1.1428 - n[i + 1] == o[n[i].row + 1]) {
1.1429 - n[i + 1] = {
1.1430 - text: n[i + 1],
1.1431 - row: n[i].row + 1
1.1432 - };
1.1433 - o[n[i].row + 1] = {
1.1434 - text: o[n[i].row + 1],
1.1435 - row: i + 1
1.1436 - };
1.1437 - }
1.1438 - }
1.1439 -
1.1440 - for (var i = n.length - 1; i > 0; i--) {
1.1441 - if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
1.1442 - n[i - 1] == o[n[i].row - 1]) {
1.1443 - n[i - 1] = {
1.1444 - text: n[i - 1],
1.1445 - row: n[i].row - 1
1.1446 - };
1.1447 - o[n[i].row - 1] = {
1.1448 - text: o[n[i].row - 1],
1.1449 - row: i - 1
1.1450 - };
1.1451 - }
1.1452 - }
1.1453 -
1.1454 - return {
1.1455 - o: o,
1.1456 - n: n
1.1457 - };
1.1458 - }
1.1459 -
1.1460 - return function(o, n) {
1.1461 - o = o.replace(/\s+$/, '');
1.1462 - n = n.replace(/\s+$/, '');
1.1463 - var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
1.1464 -
1.1465 - var str = "";
1.1466 -
1.1467 - var oSpace = o.match(/\s+/g);
1.1468 - if (oSpace == null) {
1.1469 - oSpace = [" "];
1.1470 - }
1.1471 - else {
1.1472 - oSpace.push(" ");
1.1473 - }
1.1474 - var nSpace = n.match(/\s+/g);
1.1475 - if (nSpace == null) {
1.1476 - nSpace = [" "];
1.1477 - }
1.1478 - else {
1.1479 - nSpace.push(" ");
1.1480 - }
1.1481 -
1.1482 - if (out.n.length == 0) {
1.1483 - for (var i = 0; i < out.o.length; i++) {
1.1484 - str += '<del>' + out.o[i] + oSpace[i] + "</del>";
1.1485 - }
1.1486 - }
1.1487 - else {
1.1488 - if (out.n[0].text == null) {
1.1489 - for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
1.1490 - str += '<del>' + out.o[n] + oSpace[n] + "</del>";
1.1491 - }
1.1492 - }
1.1493 -
1.1494 - for (var i = 0; i < out.n.length; i++) {
1.1495 - if (out.n[i].text == null) {
1.1496 - str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
1.1497 - }
1.1498 - else {
1.1499 - var pre = "";
1.1500 -
1.1501 - for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
1.1502 - pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
1.1503 - }
1.1504 - str += " " + out.n[i].text + nSpace[i] + pre;
1.1505 - }
1.1506 - }
1.1507 - }
1.1508 -
1.1509 - return str;
1.1510 - };
1.1511 -})();
1.1512 -
1.1513 -})(this);