[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 /** 2 * QUnit v1.6.0 - A JavaScript Unit Testing Framework 3 * 4 * http://docs.jquery.com/QUnit 5 * 6 * Copyright (c) 2012 John Resig, Jörn Zaefferer 7 * Dual licensed under the MIT (MIT-LICENSE.txt) 8 * or GPL (GPL-LICENSE.txt) licenses. 9 */ 10 11 (function( window ) { 12 13 var QUnit, 14 config, 15 testId = 0, 16 toString = Object.prototype.toString, 17 hasOwn = Object.prototype.hasOwnProperty, 18 defined = { 19 setTimeout: typeof window.setTimeout !== "undefined", 20 sessionStorage: (function() { 21 var x = "qunit-test-string"; 22 try { 23 sessionStorage.setItem( x, x ); 24 sessionStorage.removeItem( x ); 25 return true; 26 } catch( e ) { 27 return false; 28 } 29 }()) 30 }; 31 32 function Test( name, testName, expected, async, callback ) { 33 this.name = name; 34 this.testName = testName; 35 this.expected = expected; 36 this.async = async; 37 this.callback = callback; 38 this.assertions = []; 39 } 40 41 Test.prototype = { 42 init: function() { 43 var b, li, 44 tests = id( "qunit-tests" ); 45 46 if ( tests ) { 47 b = document.createElement( "strong" ); 48 b.innerHTML = "Running " + this.name; 49 50 li = document.createElement( "li" ); 51 li.appendChild( b ); 52 li.className = "running"; 53 li.id = this.id = "qunit-test-output" + testId++; 54 55 tests.appendChild( li ); 56 } 57 }, 58 setup: function() { 59 if ( this.module !== config.previousModule ) { 60 if ( config.previousModule ) { 61 runLoggingCallbacks( "moduleDone", QUnit, { 62 name: config.previousModule, 63 failed: config.moduleStats.bad, 64 passed: config.moduleStats.all - config.moduleStats.bad, 65 total: config.moduleStats.all 66 }); 67 } 68 config.previousModule = this.module; 69 config.moduleStats = { all: 0, bad: 0 }; 70 runLoggingCallbacks( "moduleStart", QUnit, { 71 name: this.module 72 }); 73 } else if ( config.autorun ) { 74 runLoggingCallbacks( "moduleStart", QUnit, { 75 name: this.module 76 }); 77 } 78 79 config.current = this; 80 81 this.testEnvironment = extend({ 82 setup: function() {}, 83 teardown: function() {} 84 }, this.moduleTestEnvironment ); 85 86 runLoggingCallbacks( "testStart", QUnit, { 87 name: this.testName, 88 module: this.module 89 }); 90 91 // allow utility functions to access the current test environment 92 // TODO why?? 93 QUnit.current_testEnvironment = this.testEnvironment; 94 95 if ( !config.pollution ) { 96 saveGlobal(); 97 } 98 if ( config.notrycatch ) { 99 this.testEnvironment.setup.call( this.testEnvironment ); 100 return; 101 } 102 try { 103 this.testEnvironment.setup.call( this.testEnvironment ); 104 } catch( e ) { 105 QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); 106 } 107 }, 108 run: function() { 109 config.current = this; 110 111 var running = id( "qunit-testresult" ); 112 113 if ( running ) { 114 running.innerHTML = "Running: <br/>" + this.name; 115 } 116 117 if ( this.async ) { 118 QUnit.stop(); 119 } 120 121 if ( config.notrycatch ) { 122 this.callback.call( this.testEnvironment ); 123 return; 124 } 125 126 try { 127 this.callback.call( this.testEnvironment ); 128 } catch( e ) { 129 QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) ); 130 // else next test will carry the responsibility 131 saveGlobal(); 132 133 // Restart the tests if they're blocking 134 if ( config.blocking ) { 135 QUnit.start(); 136 } 137 } 138 }, 139 teardown: function() { 140 config.current = this; 141 if ( config.notrycatch ) { 142 this.testEnvironment.teardown.call( this.testEnvironment ); 143 return; 144 } else { 145 try { 146 this.testEnvironment.teardown.call( this.testEnvironment ); 147 } catch( e ) { 148 QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); 149 } 150 } 151 checkPollution(); 152 }, 153 finish: function() { 154 config.current = this; 155 if ( this.expected != null && this.expected != this.assertions.length ) { 156 QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); 157 } else if ( this.expected == null && !this.assertions.length ) { 158 QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); 159 } 160 161 var assertion, a, b, i, li, ol, 162 good = 0, 163 bad = 0, 164 tests = id( "qunit-tests" ); 165 166 config.stats.all += this.assertions.length; 167 config.moduleStats.all += this.assertions.length; 168 169 if ( tests ) { 170 ol = document.createElement( "ol" ); 171 172 for ( i = 0; i < this.assertions.length; i++ ) { 173 assertion = this.assertions[i]; 174 175 li = document.createElement( "li" ); 176 li.className = assertion.result ? "pass" : "fail"; 177 li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); 178 ol.appendChild( li ); 179 180 if ( assertion.result ) { 181 good++; 182 } else { 183 bad++; 184 config.stats.bad++; 185 config.moduleStats.bad++; 186 } 187 } 188 189 // store result when possible 190 if ( QUnit.config.reorder && defined.sessionStorage ) { 191 if ( bad ) { 192 sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); 193 } else { 194 sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); 195 } 196 } 197 198 if ( bad === 0 ) { 199 ol.style.display = "none"; 200 } 201 202 // `b` initialized at top of scope 203 b = document.createElement( "strong" ); 204 b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; 205 206 // `a` initialized at top of scope 207 a = document.createElement( "a" ); 208 a.innerHTML = "Rerun"; 209 a.href = QUnit.url({ filter: getText([b]).replace( /\([^)]+\)$/, "" ).replace( /(^\s*|\s*$)/g, "" ) }); 210 211 addEvent(b, "click", function() { 212 var next = b.nextSibling.nextSibling, 213 display = next.style.display; 214 next.style.display = display === "none" ? "block" : "none"; 215 }); 216 217 addEvent(b, "dblclick", function( e ) { 218 var target = e && e.target ? e.target : window.event.srcElement; 219 if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 220 target = target.parentNode; 221 } 222 if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 223 window.location = QUnit.url({ 224 filter: getText([target]).replace( /\([^)]+\)$/, "" ).replace( /(^\s*|\s*$)/g, "" ) 225 }); 226 } 227 }); 228 229 // `li` initialized at top of scope 230 li = id( this.id ); 231 li.className = bad ? "fail" : "pass"; 232 li.removeChild( li.firstChild ); 233 li.appendChild( b ); 234 li.appendChild( a ); 235 li.appendChild( ol ); 236 237 } else { 238 for ( i = 0; i < this.assertions.length; i++ ) { 239 if ( !this.assertions[i].result ) { 240 bad++; 241 config.stats.bad++; 242 config.moduleStats.bad++; 243 } 244 } 245 } 246 247 runLoggingCallbacks( "testDone", QUnit, { 248 name: this.testName, 249 module: this.module, 250 failed: bad, 251 passed: this.assertions.length - bad, 252 total: this.assertions.length 253 }); 254 255 QUnit.reset(); 256 }, 257 258 queue: function() { 259 var bad, 260 test = this; 261 262 synchronize(function() { 263 test.init(); 264 }); 265 function run() { 266 // each of these can by async 267 synchronize(function() { 268 test.setup(); 269 }); 270 synchronize(function() { 271 test.run(); 272 }); 273 synchronize(function() { 274 test.teardown(); 275 }); 276 synchronize(function() { 277 test.finish(); 278 }); 279 } 280 281 // `bad` initialized at top of scope 282 // defer when previous test run passed, if storage is available 283 bad = QUnit.config.reorder && defined.sessionStorage && 284 +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); 285 286 if ( bad ) { 287 run(); 288 } else { 289 synchronize( run, true ); 290 } 291 } 292 }; 293 294 // `QUnit` initialized at top of scope 295 QUnit = { 296 297 // call on start of module test to prepend name to all tests 298 module: function( name, testEnvironment ) { 299 config.currentModule = name; 300 config.currentModuleTestEnviroment = testEnvironment; 301 }, 302 303 asyncTest: function( testName, expected, callback ) { 304 if ( arguments.length === 2 ) { 305 callback = expected; 306 expected = null; 307 } 308 309 QUnit.test( testName, expected, callback, true ); 310 }, 311 312 test: function( testName, expected, callback, async ) { 313 var test, 314 name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>"; 315 316 if ( arguments.length === 2 ) { 317 callback = expected; 318 expected = null; 319 } 320 321 if ( config.currentModule ) { 322 name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; 323 } 324 325 if ( !validTest(config.currentModule + ": " + testName) ) { 326 return; 327 } 328 329 test = new Test( name, testName, expected, async, callback ); 330 test.module = config.currentModule; 331 test.moduleTestEnvironment = config.currentModuleTestEnviroment; 332 test.stack = sourceFromStacktrace( 2 ); 333 test.queue(); 334 }, 335 336 // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 337 expect: function( asserts ) { 338 config.current.expected = asserts; 339 }, 340 341 // Asserts true. 342 // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 343 ok: function( result, msg ) { 344 if ( !config.current ) { 345 throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); 346 } 347 result = !!result; 348 349 var source, 350 details = { 351 result: result, 352 message: msg 353 }; 354 355 msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); 356 msg = "<span class='test-message'>" + msg + "</span>"; 357 358 if ( !result ) { 359 source = sourceFromStacktrace( 2 ); 360 if ( source ) { 361 details.source = source; 362 msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; 363 } 364 } 365 runLoggingCallbacks( "log", QUnit, details ); 366 config.current.assertions.push({ 367 result: result, 368 message: msg 369 }); 370 }, 371 372 // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values. 373 // @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes." ); 374 equal: function( actual, expected, message ) { 375 QUnit.push( expected == actual, actual, expected, message ); 376 }, 377 378 notEqual: function( actual, expected, message ) { 379 QUnit.push( expected != actual, actual, expected, message ); 380 }, 381 382 deepEqual: function( actual, expected, message ) { 383 QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); 384 }, 385 386 notDeepEqual: function( actual, expected, message ) { 387 QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); 388 }, 389 390 strictEqual: function( actual, expected, message ) { 391 QUnit.push( expected === actual, actual, expected, message ); 392 }, 393 394 notStrictEqual: function( actual, expected, message ) { 395 QUnit.push( expected !== actual, actual, expected, message ); 396 }, 397 398 raises: function( block, expected, message ) { 399 var actual, 400 ok = false; 401 402 if ( typeof expected === "string" ) { 403 message = expected; 404 expected = null; 405 } 406 407 try { 408 block.call( config.current.testEnvironment ); 409 } catch (e) { 410 actual = e; 411 } 412 413 if ( actual ) { 414 // we don't want to validate thrown error 415 if ( !expected ) { 416 ok = true; 417 // expected is a regexp 418 } else if ( QUnit.objectType( expected ) === "regexp" ) { 419 ok = expected.test( actual ); 420 // expected is a constructor 421 } else if ( actual instanceof expected ) { 422 ok = true; 423 // expected is a validation function which returns true is validation passed 424 } else if ( expected.call( {}, actual ) === true ) { 425 ok = true; 426 } 427 } 428 429 QUnit.ok( ok, message ); 430 }, 431 432 start: function( count ) { 433 config.semaphore -= count || 1; 434 // don't start until equal number of stop-calls 435 if ( config.semaphore > 0 ) { 436 return; 437 } 438 // ignore if start is called more often then stop 439 if ( config.semaphore < 0 ) { 440 config.semaphore = 0; 441 } 442 // A slight delay, to avoid any current callbacks 443 if ( defined.setTimeout ) { 444 window.setTimeout(function() { 445 if ( config.semaphore > 0 ) { 446 return; 447 } 448 if ( config.timeout ) { 449 clearTimeout( config.timeout ); 450 } 451 452 config.blocking = false; 453 process( true ); 454 }, 13); 455 } else { 456 config.blocking = false; 457 process( true ); 458 } 459 }, 460 461 stop: function( count ) { 462 config.semaphore += count || 1; 463 config.blocking = true; 464 465 if ( config.testTimeout && defined.setTimeout ) { 466 clearTimeout( config.timeout ); 467 config.timeout = window.setTimeout(function() { 468 QUnit.ok( false, "Test timed out" ); 469 config.semaphore = 1; 470 QUnit.start(); 471 }, config.testTimeout ); 472 } 473 } 474 }; 475 476 // We want access to the constructor's prototype 477 (function() { 478 function F() {} 479 F.prototype = QUnit; 480 QUnit = new F(); 481 // Make F QUnit's constructor so that we can add to the prototype later 482 QUnit.constructor = F; 483 }()); 484 485 // deprecated; still export them to window to provide clear error messages 486 // next step: remove entirely 487 QUnit.equals = function() { 488 QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); 489 }; 490 QUnit.same = function() { 491 QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); 492 }; 493 494 // Maintain internal state 495 // `config` initialized at top of scope 496 config = { 497 // The queue of tests to run 498 queue: [], 499 500 // block until document ready 501 blocking: true, 502 503 // when enabled, show only failing tests 504 // gets persisted through sessionStorage and can be changed in UI via checkbox 505 hidepassed: false, 506 507 // by default, run previously failed tests first 508 // very useful in combination with "Hide passed tests" checked 509 reorder: true, 510 511 // by default, modify document.title when suite is done 512 altertitle: true, 513 514 urlConfig: [ "noglobals", "notrycatch" ], 515 516 // logging callback queues 517 begin: [], 518 done: [], 519 log: [], 520 testStart: [], 521 testDone: [], 522 moduleStart: [], 523 moduleDone: [] 524 }; 525 526 // Load paramaters 527 (function() { 528 var i, 529 location = window.location || { search: "", protocol: "file:" }, 530 params = location.search.slice( 1 ).split( "&" ), 531 length = params.length, 532 urlParams = {}, 533 current; 534 535 if ( params[ 0 ] ) { 536 for ( i = 0; i < length; i++ ) { 537 current = params[ i ].split( "=" ); 538 current[ 0 ] = decodeURIComponent( current[ 0 ] ); 539 // allow just a key to turn on a flag, e.g., test.html?noglobals 540 current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; 541 urlParams[ current[ 0 ] ] = current[ 1 ]; 542 } 543 } 544 545 QUnit.urlParams = urlParams; 546 config.filter = urlParams.filter; 547 548 // Figure out if we're running the tests from a server or not 549 QUnit.isLocal = location.protocol === "file:"; 550 }()); 551 552 // Expose the API as global variables, unless an 'exports' object exists, 553 // in that case we assume we're in CommonJS - export everything at the end 554 if ( typeof exports === "undefined" ) { 555 extend( window, QUnit ); 556 window.QUnit = QUnit; 557 } 558 559 // define these after exposing globals to keep them in these QUnit namespace only 560 extend( QUnit, { 561 config: config, 562 563 // Initialize the configuration options 564 init: function() { 565 extend( config, { 566 stats: { all: 0, bad: 0 }, 567 moduleStats: { all: 0, bad: 0 }, 568 started: +new Date(), 569 updateRate: 1000, 570 blocking: false, 571 autostart: true, 572 autorun: false, 573 filter: "", 574 queue: [], 575 semaphore: 0 576 }); 577 578 var tests, banner, result, 579 qunit = id( "qunit" ); 580 581 if ( qunit ) { 582 qunit.innerHTML = 583 "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" + 584 "<h2 id='qunit-banner'></h2>" + 585 "<div id='qunit-testrunner-toolbar'></div>" + 586 "<h2 id='qunit-userAgent'></h2>" + 587 "<ol id='qunit-tests'></ol>"; 588 } 589 590 tests = id( "qunit-tests" ); 591 banner = id( "qunit-banner" ); 592 result = id( "qunit-testresult" ); 593 594 if ( tests ) { 595 tests.innerHTML = ""; 596 } 597 598 if ( banner ) { 599 banner.className = ""; 600 } 601 602 if ( result ) { 603 result.parentNode.removeChild( result ); 604 } 605 606 if ( tests ) { 607 result = document.createElement( "p" ); 608 result.id = "qunit-testresult"; 609 result.className = "result"; 610 tests.parentNode.insertBefore( result, tests ); 611 result.innerHTML = "Running...<br/> "; 612 } 613 }, 614 615 // Resets the test setup. Useful for tests that modify the DOM. 616 // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. 617 reset: function() { 618 var fixture; 619 620 if ( window.jQuery ) { 621 jQuery( "#qunit-fixture" ).html( config.fixture ); 622 } else { 623 fixture = id( "qunit-fixture" ); 624 if ( fixture ) { 625 fixture.innerHTML = config.fixture; 626 } 627 } 628 }, 629 630 // Trigger an event on an element. 631 // @example triggerEvent( document.body, "click" ); 632 triggerEvent: function( elem, type, event ) { 633 if ( document.createEvent ) { 634 event = document.createEvent( "MouseEvents" ); 635 event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 636 0, 0, 0, 0, 0, false, false, false, false, 0, null); 637 638 elem.dispatchEvent( event ); 639 } else if ( elem.fireEvent ) { 640 elem.fireEvent( "on" + type ); 641 } 642 }, 643 644 // Safe object type checking 645 is: function( type, obj ) { 646 return QUnit.objectType( obj ) == type; 647 }, 648 649 objectType: function( obj ) { 650 if ( typeof obj === "undefined" ) { 651 return "undefined"; 652 // consider: typeof null === object 653 } 654 if ( obj === null ) { 655 return "null"; 656 } 657 658 var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; 659 660 switch ( type ) { 661 case "Number": 662 if ( isNaN(obj) ) { 663 return "nan"; 664 } 665 return "number"; 666 case "String": 667 case "Boolean": 668 case "Array": 669 case "Date": 670 case "RegExp": 671 case "Function": 672 return type.toLowerCase(); 673 } 674 if ( typeof obj === "object" ) { 675 return "object"; 676 } 677 return undefined; 678 }, 679 680 push: function( result, actual, expected, message ) { 681 if ( !config.current ) { 682 throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); 683 } 684 685 var output, source, 686 details = { 687 result: result, 688 message: message, 689 actual: actual, 690 expected: expected 691 }; 692 693 message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); 694 message = "<span class='test-message'>" + message + "</span>"; 695 output = message; 696 697 if ( !result ) { 698 expected = escapeInnerText( QUnit.jsDump.parse(expected) ); 699 actual = escapeInnerText( QUnit.jsDump.parse(actual) ); 700 output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>"; 701 702 if ( actual != expected ) { 703 output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>"; 704 output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>"; 705 } 706 707 source = sourceFromStacktrace(); 708 709 if ( source ) { 710 details.source = source; 711 output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; 712 } 713 714 output += "</table>"; 715 } 716 717 runLoggingCallbacks( "log", QUnit, details ); 718 719 config.current.assertions.push({ 720 result: !!result, 721 message: output 722 }); 723 }, 724 725 pushFailure: function( message, source ) { 726 var output, 727 details = { 728 result: false, 729 message: message 730 }; 731 732 message = escapeInnerText(message ) || "error"; 733 message = "<span class='test-message'>" + message + "</span>"; 734 output = message; 735 736 if ( source ) { 737 details.source = source; 738 output += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; 739 } 740 741 runLoggingCallbacks( "log", QUnit, details ); 742 743 config.current.assertions.push({ 744 result: false, 745 message: output 746 }); 747 }, 748 749 url: function( params ) { 750 params = extend( extend( {}, QUnit.urlParams ), params ); 751 var key, 752 querystring = "?"; 753 754 for ( key in params ) { 755 if ( !hasOwn.call( params, key ) ) { 756 continue; 757 } 758 querystring += encodeURIComponent( key ) + "=" + 759 encodeURIComponent( params[ key ] ) + "&"; 760 } 761 return window.location.pathname + querystring.slice( 0, -1 ); 762 }, 763 764 extend: extend, 765 id: id, 766 addEvent: addEvent 767 }); 768 769 // QUnit.constructor is set to the empty F() above so that we can add to it's prototype later 770 // Doing this allows us to tell if the following methods have been overwritten on the actual 771 // QUnit object, which is a deprecated way of using the callbacks. 772 extend( QUnit.constructor.prototype, { 773 // Logging callbacks; all receive a single argument with the listed properties 774 // run test/logs.html for any related changes 775 begin: registerLoggingCallback( "begin" ), 776 // done: { failed, passed, total, runtime } 777 done: registerLoggingCallback( "done" ), 778 // log: { result, actual, expected, message } 779 log: registerLoggingCallback( "log" ), 780 // testStart: { name } 781 testStart: registerLoggingCallback( "testStart" ), 782 // testDone: { name, failed, passed, total } 783 testDone: registerLoggingCallback( "testDone" ), 784 // moduleStart: { name } 785 moduleStart: registerLoggingCallback( "moduleStart" ), 786 // moduleDone: { name, failed, passed, total } 787 moduleDone: registerLoggingCallback( "moduleDone" ) 788 }); 789 790 if ( typeof document === "undefined" || document.readyState === "complete" ) { 791 config.autorun = true; 792 } 793 794 QUnit.load = function() { 795 runLoggingCallbacks( "begin", QUnit, {} ); 796 797 // Initialize the config, saving the execution queue 798 var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, 799 urlConfigHtml = "", 800 oldconfig = extend( {}, config ); 801 802 QUnit.init(); 803 extend(config, oldconfig); 804 805 config.blocking = false; 806 807 len = config.urlConfig.length; 808 809 for ( i = 0; i < len; i++ ) { 810 val = config.urlConfig[i]; 811 config[val] = QUnit.urlParams[val]; 812 urlConfigHtml += "<label><input name='" + val + "' type='checkbox'" + ( config[val] ? " checked='checked'" : "" ) + ">" + val + "</label>"; 813 } 814 815 // `userAgent` initialized at top of scope 816 userAgent = id( "qunit-userAgent" ); 817 if ( userAgent ) { 818 userAgent.innerHTML = navigator.userAgent; 819 } 820 821 // `banner` initialized at top of scope 822 banner = id( "qunit-header" ); 823 if ( banner ) { 824 banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined }) + "'>" + banner.innerHTML + "</a> " + urlConfigHtml; 825 addEvent( banner, "change", function( event ) { 826 var params = {}; 827 params[ event.target.name ] = event.target.checked ? true : undefined; 828 window.location = QUnit.url( params ); 829 }); 830 } 831 832 // `toolbar` initialized at top of scope 833 toolbar = id( "qunit-testrunner-toolbar" ); 834 if ( toolbar ) { 835 // `filter` initialized at top of scope 836 filter = document.createElement( "input" ); 837 filter.type = "checkbox"; 838 filter.id = "qunit-filter-pass"; 839 840 addEvent( filter, "click", function() { 841 var tmp, 842 ol = document.getElementById( "qunit-tests" ); 843 844 if ( filter.checked ) { 845 ol.className = ol.className + " hidepass"; 846 } else { 847 tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; 848 ol.className = tmp.replace( / hidepass /, " " ); 849 } 850 if ( defined.sessionStorage ) { 851 if (filter.checked) { 852 sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); 853 } else { 854 sessionStorage.removeItem( "qunit-filter-passed-tests" ); 855 } 856 } 857 }); 858 859 if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { 860 filter.checked = true; 861 // `ol` initialized at top of scope 862 ol = document.getElementById( "qunit-tests" ); 863 ol.className = ol.className + " hidepass"; 864 } 865 toolbar.appendChild( filter ); 866 867 // `label` initialized at top of scope 868 label = document.createElement( "label" ); 869 label.setAttribute( "for", "qunit-filter-pass" ); 870 label.innerHTML = "Hide passed tests"; 871 toolbar.appendChild( label ); 872 } 873 874 // `main` initialized at top of scope 875 main = id( "qunit-fixture" ); 876 if ( main ) { 877 config.fixture = main.innerHTML; 878 } 879 880 if ( config.autostart ) { 881 QUnit.start(); 882 } 883 }; 884 885 addEvent( window, "load", QUnit.load ); 886 887 // addEvent(window, "error" ) gives us a useless event object 888 window.onerror = function( message, file, line ) { 889 if ( QUnit.config.current ) { 890 QUnit.pushFailure( message, file + ":" + line ); 891 } else { 892 QUnit.test( "global failure", function() { 893 QUnit.pushFailure( message, file + ":" + line ); 894 }); 895 } 896 }; 897 898 function done() { 899 config.autorun = true; 900 901 // Log the last module results 902 if ( config.currentModule ) { 903 runLoggingCallbacks( "moduleDone", QUnit, { 904 name: config.currentModule, 905 failed: config.moduleStats.bad, 906 passed: config.moduleStats.all - config.moduleStats.bad, 907 total: config.moduleStats.all 908 }); 909 } 910 911 var i, key, 912 banner = id( "qunit-banner" ), 913 tests = id( "qunit-tests" ), 914 runtime = +new Date() - config.started, 915 passed = config.stats.all - config.stats.bad, 916 html = [ 917 "Tests completed in ", 918 runtime, 919 " milliseconds.<br/>", 920 "<span class='passed'>", 921 passed, 922 "</span> tests of <span class='total'>", 923 config.stats.all, 924 "</span> passed, <span class='failed'>", 925 config.stats.bad, 926 "</span> failed." 927 ].join( "" ); 928 929 if ( banner ) { 930 banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); 931 } 932 933 if ( tests ) { 934 id( "qunit-testresult" ).innerHTML = html; 935 } 936 937 if ( config.altertitle && typeof document !== "undefined" && document.title ) { 938 // show ✖ for good, ✔ for bad suite result in title 939 // use escape sequences in case file gets loaded with non-utf-8-charset 940 document.title = [ 941 ( config.stats.bad ? "\u2716" : "\u2714" ), 942 document.title.replace( /^[\u2714\u2716] /i, "" ) 943 ].join( " " ); 944 } 945 946 // clear own sessionStorage items if all tests passed 947 if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { 948 // `key` & `i` initialized at top of scope 949 for ( i = 0; i < sessionStorage.length; i++ ) { 950 key = sessionStorage.key( i++ ); 951 if ( key.indexOf( "qunit-test-" ) === 0 ) { 952 sessionStorage.removeItem( key ); 953 } 954 } 955 } 956 957 runLoggingCallbacks( "done", QUnit, { 958 failed: config.stats.bad, 959 passed: passed, 960 total: config.stats.all, 961 runtime: runtime 962 }); 963 } 964 965 function validTest( name ) { 966 var not, 967 filter = config.filter, 968 run = false; 969 970 if ( !filter ) { 971 return true; 972 } 973 974 not = filter.charAt( 0 ) === "!"; 975 976 if ( not ) { 977 filter = filter.slice( 1 ); 978 } 979 980 if ( name.indexOf( filter ) !== -1 ) { 981 return !not; 982 } 983 984 if ( not ) { 985 run = true; 986 } 987 988 return run; 989 } 990 991 // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) 992 // Later Safari and IE10 are supposed to support error.stack as well 993 // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack 994 function extractStacktrace( e, offset ) { 995 offset = offset || 3; 996 997 var stack; 998 999 if ( e.stacktrace ) { 1000 // Opera 1001 return e.stacktrace.split( "\n" )[ offset + 3 ]; 1002 } else if ( e.stack ) { 1003 // Firefox, Chrome 1004 stack = e.stack.split( "\n" ); 1005 if (/^error$/i.test( stack[0] ) ) { 1006 stack.shift(); 1007 } 1008 return stack[ offset ]; 1009 } else if ( e.sourceURL ) { 1010 // Safari, PhantomJS 1011 // hopefully one day Safari provides actual stacktraces 1012 // exclude useless self-reference for generated Error objects 1013 if ( /qunit.js$/.test( e.sourceURL ) ) { 1014 return; 1015 } 1016 // for actual exceptions, this is useful 1017 return e.sourceURL + ":" + e.line; 1018 } 1019 } 1020 function sourceFromStacktrace( offset ) { 1021 try { 1022 throw new Error(); 1023 } catch ( e ) { 1024 return extractStacktrace( e, offset ); 1025 } 1026 } 1027 1028 function escapeInnerText( s ) { 1029 if ( !s ) { 1030 return ""; 1031 } 1032 s = s + ""; 1033 return s.replace( /[\&<>]/g, function( s ) { 1034 switch( s ) { 1035 case "&": return "&"; 1036 case "<": return "<"; 1037 case ">": return ">"; 1038 default: return s; 1039 } 1040 }); 1041 } 1042 1043 function synchronize( callback, last ) { 1044 config.queue.push( callback ); 1045 1046 if ( config.autorun && !config.blocking ) { 1047 process( last ); 1048 } 1049 } 1050 1051 function process( last ) { 1052 function next() { 1053 process( last ); 1054 } 1055 var start = new Date().getTime(); 1056 config.depth = config.depth ? config.depth + 1 : 1; 1057 1058 while ( config.queue.length && !config.blocking ) { 1059 if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { 1060 config.queue.shift()(); 1061 } else { 1062 window.setTimeout( next, 13 ); 1063 break; 1064 } 1065 } 1066 config.depth--; 1067 if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { 1068 done(); 1069 } 1070 } 1071 1072 function saveGlobal() { 1073 config.pollution = []; 1074 1075 if ( config.noglobals ) { 1076 for ( var key in window ) { 1077 // in Opera sometimes DOM element ids show up here, ignore them 1078 if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { 1079 continue; 1080 } 1081 config.pollution.push( key ); 1082 } 1083 } 1084 } 1085 1086 function checkPollution( name ) { 1087 var newGlobals, 1088 deletedGlobals, 1089 old = config.pollution; 1090 1091 saveGlobal(); 1092 1093 newGlobals = diff( config.pollution, old ); 1094 if ( newGlobals.length > 0 ) { 1095 QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); 1096 } 1097 1098 deletedGlobals = diff( old, config.pollution ); 1099 if ( deletedGlobals.length > 0 ) { 1100 QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); 1101 } 1102 } 1103 1104 // returns a new Array with the elements that are in a but not in b 1105 function diff( a, b ) { 1106 var i, j, 1107 result = a.slice(); 1108 1109 for ( i = 0; i < result.length; i++ ) { 1110 for ( j = 0; j < b.length; j++ ) { 1111 if ( result[i] === b[j] ) { 1112 result.splice( i, 1 ); 1113 i--; 1114 break; 1115 } 1116 } 1117 } 1118 return result; 1119 } 1120 1121 function extend( a, b ) { 1122 for ( var prop in b ) { 1123 if ( b[ prop ] === undefined ) { 1124 delete a[ prop ]; 1125 1126 // Avoid "Member not found" error in IE8 caused by setting window.constructor 1127 } else if ( prop !== "constructor" || a !== window ) { 1128 a[ prop ] = b[ prop ]; 1129 } 1130 } 1131 1132 return a; 1133 } 1134 1135 function addEvent( elem, type, fn ) { 1136 if ( elem.addEventListener ) { 1137 elem.addEventListener( type, fn, false ); 1138 } else if ( elem.attachEvent ) { 1139 elem.attachEvent( "on" + type, fn ); 1140 } else { 1141 fn(); 1142 } 1143 } 1144 1145 function id( name ) { 1146 return !!( typeof document !== "undefined" && document && document.getElementById ) && 1147 document.getElementById( name ); 1148 } 1149 1150 function registerLoggingCallback( key ) { 1151 return function( callback ) { 1152 config[key].push( callback ); 1153 }; 1154 } 1155 1156 // Supports deprecated method of completely overwriting logging callbacks 1157 function runLoggingCallbacks( key, scope, args ) { 1158 //debugger; 1159 var i, callbacks; 1160 if ( QUnit.hasOwnProperty( key ) ) { 1161 QUnit[ key ].call(scope, args ); 1162 } else { 1163 callbacks = config[ key ]; 1164 for ( i = 0; i < callbacks.length; i++ ) { 1165 callbacks[ i ].call( scope, args ); 1166 } 1167 } 1168 } 1169 1170 // Test for equality any JavaScript type. 1171 // Author: Philippe Rathé <[email protected]> 1172 QUnit.equiv = (function() { 1173 1174 // Call the o related callback with the given arguments. 1175 function bindCallbacks( o, callbacks, args ) { 1176 var prop = QUnit.objectType( o ); 1177 if ( prop ) { 1178 if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { 1179 return callbacks[ prop ].apply( callbacks, args ); 1180 } else { 1181 return callbacks[ prop ]; // or undefined 1182 } 1183 } 1184 } 1185 1186 // the real equiv function 1187 var innerEquiv, 1188 // stack to decide between skip/abort functions 1189 callers = [], 1190 // stack to avoiding loops from circular referencing 1191 parents = [], 1192 1193 getProto = Object.getPrototypeOf || function ( obj ) { 1194 return obj.__proto__; 1195 }, 1196 callbacks = (function () { 1197 1198 // for string, boolean, number and null 1199 function useStrictEquality( b, a ) { 1200 if ( b instanceof a.constructor || a instanceof b.constructor ) { 1201 // to catch short annotaion VS 'new' annotation of a 1202 // declaration 1203 // e.g. var i = 1; 1204 // var j = new Number(1); 1205 return a == b; 1206 } else { 1207 return a === b; 1208 } 1209 } 1210 1211 return { 1212 "string": useStrictEquality, 1213 "boolean": useStrictEquality, 1214 "number": useStrictEquality, 1215 "null": useStrictEquality, 1216 "undefined": useStrictEquality, 1217 1218 "nan": function( b ) { 1219 return isNaN( b ); 1220 }, 1221 1222 "date": function( b, a ) { 1223 return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); 1224 }, 1225 1226 "regexp": function( b, a ) { 1227 return QUnit.objectType( b ) === "regexp" && 1228 // the regex itself 1229 a.source === b.source && 1230 // and its modifers 1231 a.global === b.global && 1232 // (gmi) ... 1233 a.ignoreCase === b.ignoreCase && 1234 a.multiline === b.multiline; 1235 }, 1236 1237 // - skip when the property is a method of an instance (OOP) 1238 // - abort otherwise, 1239 // initial === would have catch identical references anyway 1240 "function": function() { 1241 var caller = callers[callers.length - 1]; 1242 return caller !== Object && typeof caller !== "undefined"; 1243 }, 1244 1245 "array": function( b, a ) { 1246 var i, j, len, loop; 1247 1248 // b could be an object literal here 1249 if ( QUnit.objectType( b ) !== "array" ) { 1250 return false; 1251 } 1252 1253 len = a.length; 1254 if ( len !== b.length ) { 1255 // safe and faster 1256 return false; 1257 } 1258 1259 // track reference to avoid circular references 1260 parents.push( a ); 1261 for ( i = 0; i < len; i++ ) { 1262 loop = false; 1263 for ( j = 0; j < parents.length; j++ ) { 1264 if ( parents[j] === a[i] ) { 1265 loop = true;// dont rewalk array 1266 } 1267 } 1268 if ( !loop && !innerEquiv(a[i], b[i]) ) { 1269 parents.pop(); 1270 return false; 1271 } 1272 } 1273 parents.pop(); 1274 return true; 1275 }, 1276 1277 "object": function( b, a ) { 1278 var i, j, loop, 1279 // Default to true 1280 eq = true, 1281 aProperties = [], 1282 bProperties = []; 1283 1284 // comparing constructors is more strict than using 1285 // instanceof 1286 if ( a.constructor !== b.constructor ) { 1287 // Allow objects with no prototype to be equivalent to 1288 // objects with Object as their constructor. 1289 if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || 1290 ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { 1291 return false; 1292 } 1293 } 1294 1295 // stack constructor before traversing properties 1296 callers.push( a.constructor ); 1297 // track reference to avoid circular references 1298 parents.push( a ); 1299 1300 for ( i in a ) { // be strict: don't ensures hasOwnProperty 1301 // and go deep 1302 loop = false; 1303 for ( j = 0; j < parents.length; j++ ) { 1304 if ( parents[j] === a[i] ) { 1305 // don't go down the same path twice 1306 loop = true; 1307 } 1308 } 1309 aProperties.push(i); // collect a's properties 1310 1311 if (!loop && !innerEquiv( a[i], b[i] ) ) { 1312 eq = false; 1313 break; 1314 } 1315 } 1316 1317 callers.pop(); // unstack, we are done 1318 parents.pop(); 1319 1320 for ( i in b ) { 1321 bProperties.push( i ); // collect b's properties 1322 } 1323 1324 // Ensures identical properties name 1325 return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); 1326 } 1327 }; 1328 }()); 1329 1330 innerEquiv = function() { // can take multiple arguments 1331 var args = [].slice.apply( arguments ); 1332 if ( args.length < 2 ) { 1333 return true; // end transition 1334 } 1335 1336 return (function( a, b ) { 1337 if ( a === b ) { 1338 return true; // catch the most you can 1339 } else if ( a === null || b === null || typeof a === "undefined" || 1340 typeof b === "undefined" || 1341 QUnit.objectType(a) !== QUnit.objectType(b) ) { 1342 return false; // don't lose time with error prone cases 1343 } else { 1344 return bindCallbacks(a, callbacks, [ b, a ]); 1345 } 1346 1347 // apply transition with (1..n) arguments 1348 }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); 1349 }; 1350 1351 return innerEquiv; 1352 }()); 1353 1354 /** 1355 * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | 1356 * http://flesler.blogspot.com Licensed under BSD 1357 * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 1358 * 1359 * @projectDescription Advanced and extensible data dumping for Javascript. 1360 * @version 1.0.0 1361 * @author Ariel Flesler 1362 * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} 1363 */ 1364 QUnit.jsDump = (function() { 1365 function quote( str ) { 1366 return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; 1367 } 1368 function literal( o ) { 1369 return o + ""; 1370 } 1371 function join( pre, arr, post ) { 1372 var s = jsDump.separator(), 1373 base = jsDump.indent(), 1374 inner = jsDump.indent(1); 1375 if ( arr.join ) { 1376 arr = arr.join( "," + s + inner ); 1377 } 1378 if ( !arr ) { 1379 return pre + post; 1380 } 1381 return [ pre, inner + arr, base + post ].join(s); 1382 } 1383 function array( arr, stack ) { 1384 var i = arr.length, ret = new Array(i); 1385 this.up(); 1386 while ( i-- ) { 1387 ret[i] = this.parse( arr[i] , undefined , stack); 1388 } 1389 this.down(); 1390 return join( "[", ret, "]" ); 1391 } 1392 1393 var reName = /^function (\w+)/, 1394 jsDump = { 1395 parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance 1396 stack = stack || [ ]; 1397 var inStack, res, 1398 parser = this.parsers[ type || this.typeOf(obj) ]; 1399 1400 type = typeof parser; 1401 inStack = inArray( obj, stack ); 1402 1403 if ( inStack != -1 ) { 1404 return "recursion(" + (inStack - stack.length) + ")"; 1405 } 1406 //else 1407 if ( type == "function" ) { 1408 stack.push( obj ); 1409 res = parser.call( this, obj, stack ); 1410 stack.pop(); 1411 return res; 1412 } 1413 // else 1414 return ( type == "string" ) ? parser : this.parsers.error; 1415 }, 1416 typeOf: function( obj ) { 1417 var type; 1418 if ( obj === null ) { 1419 type = "null"; 1420 } else if ( typeof obj === "undefined" ) { 1421 type = "undefined"; 1422 } else if ( QUnit.is( "RegExp", obj) ) { 1423 type = "regexp"; 1424 } else if ( QUnit.is( "Date", obj) ) { 1425 type = "date"; 1426 } else if ( QUnit.is( "Function", obj) ) { 1427 type = "function"; 1428 } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { 1429 type = "window"; 1430 } else if ( obj.nodeType === 9 ) { 1431 type = "document"; 1432 } else if ( obj.nodeType ) { 1433 type = "node"; 1434 } else if ( 1435 // native arrays 1436 toString.call( obj ) === "[object Array]" || 1437 // NodeList objects 1438 ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) 1439 ) { 1440 type = "array"; 1441 } else { 1442 type = typeof obj; 1443 } 1444 return type; 1445 }, 1446 separator: function() { 1447 return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; 1448 }, 1449 indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1450 if ( !this.multiline ) { 1451 return ""; 1452 } 1453 var chr = this.indentChar; 1454 if ( this.HTML ) { 1455 chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); 1456 } 1457 return new Array( this._depth_ + (extra||0) ).join(chr); 1458 }, 1459 up: function( a ) { 1460 this._depth_ += a || 1; 1461 }, 1462 down: function( a ) { 1463 this._depth_ -= a || 1; 1464 }, 1465 setParser: function( name, parser ) { 1466 this.parsers[name] = parser; 1467 }, 1468 // The next 3 are exposed so you can use them 1469 quote: quote, 1470 literal: literal, 1471 join: join, 1472 // 1473 _depth_: 1, 1474 // This is the list of parsers, to modify them, use jsDump.setParser 1475 parsers: { 1476 window: "[Window]", 1477 document: "[Document]", 1478 error: "[ERROR]", //when no parser is found, shouldn"t happen 1479 unknown: "[Unknown]", 1480 "null": "null", 1481 "undefined": "undefined", 1482 "function": function( fn ) { 1483 var ret = "function", 1484 name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE 1485 1486 if ( name ) { 1487 ret += " " + name; 1488 } 1489 ret += "( "; 1490 1491 ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); 1492 return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); 1493 }, 1494 array: array, 1495 nodelist: array, 1496 "arguments": array, 1497 object: function( map, stack ) { 1498 var ret = [ ], keys, key, val, i; 1499 QUnit.jsDump.up(); 1500 if ( Object.keys ) { 1501 keys = Object.keys( map ); 1502 } else { 1503 keys = []; 1504 for ( key in map ) { 1505 keys.push( key ); 1506 } 1507 } 1508 keys.sort(); 1509 for ( i = 0; i < keys.length; i++ ) { 1510 key = keys[ i ]; 1511 val = map[ key ]; 1512 ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); 1513 } 1514 QUnit.jsDump.down(); 1515 return join( "{", ret, "}" ); 1516 }, 1517 node: function( node ) { 1518 var a, val, 1519 open = QUnit.jsDump.HTML ? "<" : "<", 1520 close = QUnit.jsDump.HTML ? ">" : ">", 1521 tag = node.nodeName.toLowerCase(), 1522 ret = open + tag; 1523 1524 for ( a in QUnit.jsDump.DOMAttrs ) { 1525 val = node[ QUnit.jsDump.DOMAttrs[a] ]; 1526 if ( val ) { 1527 ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); 1528 } 1529 } 1530 return ret + close + open + "/" + tag + close; 1531 }, 1532 functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function 1533 var args, 1534 l = fn.length; 1535 1536 if ( !l ) { 1537 return ""; 1538 } 1539 1540 args = new Array(l); 1541 while ( l-- ) { 1542 args[l] = String.fromCharCode(97+l);//97 is 'a' 1543 } 1544 return " " + args.join( ", " ) + " "; 1545 }, 1546 key: quote, //object calls it internally, the key part of an item in a map 1547 functionCode: "[code]", //function calls it internally, it's the content of the function 1548 attribute: quote, //node calls it internally, it's an html attribute value 1549 string: quote, 1550 date: quote, 1551 regexp: literal, //regex 1552 number: literal, 1553 "boolean": literal 1554 }, 1555 DOMAttrs: { 1556 //attributes to dump from nodes, name=>realName 1557 id: "id", 1558 name: "name", 1559 "class": "className" 1560 }, 1561 HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) 1562 indentChar: " ",//indentation unit 1563 multiline: true //if true, items in a collection, are separated by a \n, else just a space. 1564 }; 1565 1566 return jsDump; 1567 }()); 1568 1569 // from Sizzle.js 1570 function getText( elems ) { 1571 var i, elem, 1572 ret = ""; 1573 1574 for ( i = 0; elems[i]; i++ ) { 1575 elem = elems[i]; 1576 1577 // Get the text from text nodes and CDATA nodes 1578 if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1579 ret += elem.nodeValue; 1580 1581 // Traverse everything else, except comment nodes 1582 } else if ( elem.nodeType !== 8 ) { 1583 ret += getText( elem.childNodes ); 1584 } 1585 } 1586 1587 return ret; 1588 } 1589 1590 // from jquery.js 1591 function inArray( elem, array ) { 1592 if ( array.indexOf ) { 1593 return array.indexOf( elem ); 1594 } 1595 1596 for ( var i = 0, length = array.length; i < length; i++ ) { 1597 if ( array[ i ] === elem ) { 1598 return i; 1599 } 1600 } 1601 1602 return -1; 1603 } 1604 1605 /* 1606 * Javascript Diff Algorithm 1607 * By John Resig (http://ejohn.org/) 1608 * Modified by Chu Alan "sprite" 1609 * 1610 * Released under the MIT license. 1611 * 1612 * More Info: 1613 * http://ejohn.org/projects/javascript-diff-algorithm/ 1614 * 1615 * Usage: QUnit.diff(expected, actual) 1616 * 1617 * 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" 1618 */ 1619 QUnit.diff = (function() { 1620 function diff( o, n ) { 1621 var i, 1622 ns = {}, 1623 os = {}; 1624 1625 for ( i = 0; i < n.length; i++ ) { 1626 if ( ns[ n[i] ] == null ) { 1627 ns[ n[i] ] = { 1628 rows: [], 1629 o: null 1630 }; 1631 } 1632 ns[ n[i] ].rows.push( i ); 1633 } 1634 1635 for ( i = 0; i < o.length; i++ ) { 1636 if ( os[ o[i] ] == null ) { 1637 os[ o[i] ] = { 1638 rows: [], 1639 n: null 1640 }; 1641 } 1642 os[ o[i] ].rows.push( i ); 1643 } 1644 1645 for ( i in ns ) { 1646 if ( !hasOwn.call( ns, i ) ) { 1647 continue; 1648 } 1649 if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { 1650 n[ ns[i].rows[0] ] = { 1651 text: n[ ns[i].rows[0] ], 1652 row: os[i].rows[0] 1653 }; 1654 o[ os[i].rows[0] ] = { 1655 text: o[ os[i].rows[0] ], 1656 row: ns[i].rows[0] 1657 }; 1658 } 1659 } 1660 1661 for ( i = 0; i < n.length - 1; i++ ) { 1662 if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && 1663 n[ i + 1 ] == o[ n[i].row + 1 ] ) { 1664 1665 n[ i + 1 ] = { 1666 text: n[ i + 1 ], 1667 row: n[i].row + 1 1668 }; 1669 o[ n[i].row + 1 ] = { 1670 text: o[ n[i].row + 1 ], 1671 row: i + 1 1672 }; 1673 } 1674 } 1675 1676 for ( i = n.length - 1; i > 0; i-- ) { 1677 if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && 1678 n[ i - 1 ] == o[ n[i].row - 1 ]) { 1679 1680 n[ i - 1 ] = { 1681 text: n[ i - 1 ], 1682 row: n[i].row - 1 1683 }; 1684 o[ n[i].row - 1 ] = { 1685 text: o[ n[i].row - 1 ], 1686 row: i - 1 1687 }; 1688 } 1689 } 1690 1691 return { 1692 o: o, 1693 n: n 1694 }; 1695 } 1696 1697 return function( o, n ) { 1698 o = o.replace( /\s+$/, "" ); 1699 n = n.replace( /\s+$/, "" ); 1700 1701 var i, pre, 1702 str = "", 1703 out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), 1704 oSpace = o.match(/\s+/g), 1705 nSpace = n.match(/\s+/g); 1706 1707 if ( oSpace == null ) { 1708 oSpace = [ " " ]; 1709 } 1710 else { 1711 oSpace.push( " " ); 1712 } 1713 1714 if ( nSpace == null ) { 1715 nSpace = [ " " ]; 1716 } 1717 else { 1718 nSpace.push( " " ); 1719 } 1720 1721 if ( out.n.length === 0 ) { 1722 for ( i = 0; i < out.o.length; i++ ) { 1723 str += "<del>" + out.o[i] + oSpace[i] + "</del>"; 1724 } 1725 } 1726 else { 1727 if ( out.n[0].text == null ) { 1728 for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { 1729 str += "<del>" + out.o[n] + oSpace[n] + "</del>"; 1730 } 1731 } 1732 1733 for ( i = 0; i < out.n.length; i++ ) { 1734 if (out.n[i].text == null) { 1735 str += "<ins>" + out.n[i] + nSpace[i] + "</ins>"; 1736 } 1737 else { 1738 // `pre` initialized at top of scope 1739 pre = ""; 1740 1741 for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { 1742 pre += "<del>" + out.o[n] + oSpace[n] + "</del>"; 1743 } 1744 str += " " + out.n[i].text + nSpace[i] + pre; 1745 } 1746 } 1747 } 1748 1749 return str; 1750 }; 1751 }()); 1752 1753 // for CommonJS enviroments, export everything 1754 if ( typeof exports !== "undefined" ) { 1755 extend(exports, QUnit); 1756 } 1757 1758 // get at whatever the global object is, like window in browsers 1759 }( (function() {return this;}.call()) ));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |