| // cycle.js | ||
| // 2011-08-24 | ||
| /*jslint evil: true, regexp: true */ | ||
| /*members $ref, apply, call, decycle, hasOwnProperty, length, prototype, push, | ||
| retrocycle, stringify, test, toString | ||
| */ | ||
| if (typeof JSON.decycle !== 'function') { | ||
| JSON.decycle = function decycle(object) { | ||
| 'use strict'; | ||
| // Make a deep copy of an object or array, assuring that there is at most | ||
| // one instance of each object or array in the resulting structure. The | ||
| // duplicate references (which might be forming cycles) are replaced with | ||
| // an object of the form | ||
| // {$ref: PATH} | ||
| // where the PATH is a JSONPath string that locates the first occurance. | ||
| // So, | ||
| // var a = []; | ||
| // a[0] = a; | ||
| // return JSON.stringify(JSON.decycle(a)); | ||
| // produces the string '[{"$ref":"$"}]'. | ||
| // JSONPath is used to locate the unique object. $ indicates the top level of | ||
| // the object or array. [NUMBER] or [STRING] indicates a child member or | ||
| // property. | ||
| var objects = [], // Keep a reference to each unique object or array | ||
| paths = []; // Keep the path to each unique object or array | ||
| return (function derez(value, path) { | ||
| // The derez recurses through the object, producing the deep copy. | ||
| var i, // The loop counter | ||
| name, // Property name | ||
| nu; // The new object or array | ||
| switch (typeof value) { | ||
| case 'object': | ||
| // typeof null === 'object', so get out if this value is not really an object. | ||
| if (!value) { | ||
| return null; | ||
| } | ||
| // If the value is an object or array, look to see if we have already | ||
| // encountered it. If so, return a $ref/path object. This is a hard way, | ||
| // linear search that will get slower as the number of unique objects grows. | ||
| for (i = 0; i < objects.length; i += 1) { | ||
| if (objects[i] === value) { | ||
| return {$ref: paths[i]}; | ||
| } | ||
| } | ||
| // Otherwise, accumulate the unique value and its path. | ||
| objects.push(value); | ||
| paths.push(path); | ||
| // If it is an array, replicate the array. | ||
| if (Object.prototype.toString.apply(value) === '[object Array]') { | ||
| nu = []; | ||
| for (i = 0; i < value.length; i += 1) { | ||
| nu[i] = derez(value[i], path + '[' + i + ']'); | ||
| } | ||
| } else { | ||
| // If it is an object, replicate the object. | ||
| nu = {}; | ||
| for (name in value) { | ||
| if (Object.prototype.hasOwnProperty.call(value, name)) { | ||
| nu[name] = derez(value[name], | ||
| path + '[' + JSON.stringify(name) + ']'); | ||
| } | ||
| } | ||
| } | ||
| return nu; | ||
| case 'number': | ||
| case 'string': | ||
| case 'boolean': | ||
| return value; | ||
| } | ||
| }(object, '$')); | ||
| }; | ||
| } | ||
| if (typeof JSON.retrocycle !== 'function') { | ||
| JSON.retrocycle = function retrocycle($) { | ||
| 'use strict'; | ||
| // Restore an object that was reduced by decycle. Members whose values are | ||
| // objects of the form | ||
| // {$ref: PATH} | ||
| // are replaced with references to the value found by the PATH. This will | ||
| // restore cycles. The object will be mutated. | ||
| // The eval function is used to locate the values described by a PATH. The | ||
| // root object is kept in a $ variable. A regular expression is used to | ||
| // assure that the PATH is extremely well formed. The regexp contains nested | ||
| // * quantifiers. That has been known to have extremely bad performance | ||
| // problems on some browsers for very long strings. A PATH is expected to be | ||
| // reasonably short. A PATH is allowed to belong to a very restricted subset of | ||
| // Goessner's JSONPath. | ||
| // So, | ||
| // var s = '[{"$ref":"$"}]'; | ||
| // return JSON.retrocycle(JSON.parse(s)); | ||
| // produces an array containing a single element which is the array itself. | ||
| var px = | ||
| /^\$(?:\[(?:\d+|\"(?:[^\\\"\u0000-\u001f]|\\([\\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*\")\])*$/; | ||
| (function rez(value) { | ||
| // The rez function walks recursively through the object looking for $ref | ||
| // properties. When it finds one that has a value that is a path, then it | ||
| // replaces the $ref object with a reference to the value that is found by | ||
| // the path. | ||
| var i, item, name, path; | ||
| if (value && typeof value === 'object') { | ||
| if (Object.prototype.toString.apply(value) === '[object Array]') { | ||
| for (i = 0; i < value.length; i += 1) { | ||
| item = value[i]; | ||
| if (item && typeof item === 'object') { | ||
| path = item.$ref; | ||
| if (typeof path === 'string' && px.test(path)) { | ||
| value[i] = eval(path); | ||
| } else { | ||
| rez(item); | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| for (name in value) { | ||
| if (typeof value[name] === 'object') { | ||
| item = value[name]; | ||
| if (item) { | ||
| path = item.$ref; | ||
| if (typeof path === 'string' && px.test(path)) { | ||
| value[name] = eval(path); | ||
| } else { | ||
| rez(item); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }($)); | ||
| return $; | ||
| }; | ||
| } |
| /** | ||
| * QUnit v1.8.0 - A JavaScript Unit Testing Framework | ||
| * | ||
| * http://docs.jquery.com/QUnit | ||
| * | ||
| * Copyright (c) 2012 John Resig, Jörn Zaefferer | ||
| * Dual licensed under the MIT (MIT-LICENSE.txt) | ||
| * or GPL (GPL-LICENSE.txt) licenses. | ||
| */ | ||
| (function( window ) { | ||
| var QUnit, | ||
| config, | ||
| onErrorFnPrev, | ||
| testId = 0, | ||
| fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), | ||
| toString = Object.prototype.toString, | ||
| hasOwn = Object.prototype.hasOwnProperty, | ||
| defined = { | ||
| setTimeout: typeof window.setTimeout !== "undefined", | ||
| sessionStorage: (function() { | ||
| var x = "qunit-test-string"; | ||
| try { | ||
| sessionStorage.setItem( x, x ); | ||
| sessionStorage.removeItem( x ); | ||
| return true; | ||
| } catch( e ) { | ||
| return false; | ||
| } | ||
| }()) | ||
| }, | ||
| Date = window.Date; | ||
| function Test( settings ) { | ||
| extend( this, settings ); | ||
| this.assertions = []; | ||
| this.testNumber = ++Test.count; | ||
| } | ||
| Test.count = 0; | ||
| Test.prototype = { | ||
| init: function() { | ||
| var a, b, li, | ||
| tests = id( "qunit-tests" ); | ||
| if ( tests ) { | ||
| b = document.createElement( "strong" ); | ||
| b.innerHTML = this.name; | ||
| // `a` initialized at top of scope | ||
| a = document.createElement( "a" ); | ||
| a.innerHTML = "Rerun"; | ||
| a.href = QUnit.url({ testNumber: this.testNumber }); | ||
| li = document.createElement( "li" ); | ||
| li.appendChild( b ); | ||
| li.appendChild( a ); | ||
| li.className = "running"; | ||
| li.id = this.id = "qunit-test-output" + testId++; | ||
| tests.appendChild( li ); | ||
| } | ||
| }, | ||
| setup: function() { | ||
| if ( this.module !== config.previousModule ) { | ||
| if ( config.previousModule ) { | ||
| runLoggingCallbacks( "moduleDone", QUnit, { | ||
| name: config.previousModule, | ||
| failed: config.moduleStats.bad, | ||
| passed: config.moduleStats.all - config.moduleStats.bad, | ||
| total: config.moduleStats.all | ||
| }); | ||
| } | ||
| config.previousModule = this.module; | ||
| config.moduleStats = { all: 0, bad: 0 }; | ||
| runLoggingCallbacks( "moduleStart", QUnit, { | ||
| name: this.module | ||
| }); | ||
| } else if ( config.autorun ) { | ||
| runLoggingCallbacks( "moduleStart", QUnit, { | ||
| name: this.module | ||
| }); | ||
| } | ||
| config.current = this; | ||
| this.testEnvironment = extend({ | ||
| setup: function() {}, | ||
| teardown: function() {} | ||
| }, this.moduleTestEnvironment ); | ||
| runLoggingCallbacks( "testStart", QUnit, { | ||
| name: this.testName, | ||
| module: this.module | ||
| }); | ||
| // allow utility functions to access the current test environment | ||
| // TODO why?? | ||
| QUnit.current_testEnvironment = this.testEnvironment; | ||
| if ( !config.pollution ) { | ||
| saveGlobal(); | ||
| } | ||
| if ( config.notrycatch ) { | ||
| this.testEnvironment.setup.call( this.testEnvironment ); | ||
| return; | ||
| } | ||
| try { | ||
| this.testEnvironment.setup.call( this.testEnvironment ); | ||
| } catch( e ) { | ||
| QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); | ||
| } | ||
| }, | ||
| run: function() { | ||
| config.current = this; | ||
| var running = id( "qunit-testresult" ); | ||
| if ( running ) { | ||
| running.innerHTML = "Running: <br/>" + this.name; | ||
| } | ||
| if ( this.async ) { | ||
| QUnit.stop(); | ||
| } | ||
| if ( config.notrycatch ) { | ||
| this.callback.call( this.testEnvironment, QUnit.assert ); | ||
| return; | ||
| } | ||
| try { | ||
| this.callback.call( this.testEnvironment, QUnit.assert ); | ||
| } catch( e ) { | ||
| QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); | ||
| // else next test will carry the responsibility | ||
| saveGlobal(); | ||
| // Restart the tests if they're blocking | ||
| if ( config.blocking ) { | ||
| QUnit.start(); | ||
| } | ||
| } | ||
| }, | ||
| teardown: function() { | ||
| config.current = this; | ||
| if ( config.notrycatch ) { | ||
| this.testEnvironment.teardown.call( this.testEnvironment ); | ||
| return; | ||
| } else { | ||
| try { | ||
| this.testEnvironment.teardown.call( this.testEnvironment ); | ||
| } catch( e ) { | ||
| QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); | ||
| } | ||
| } | ||
| checkPollution(); | ||
| }, | ||
| finish: function() { | ||
| config.current = this; | ||
| if ( config.requireExpects && this.expected == null ) { | ||
| QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); | ||
| } else if ( this.expected != null && this.expected != this.assertions.length ) { | ||
| QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); | ||
| } else if ( this.expected == null && !this.assertions.length ) { | ||
| QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); | ||
| } | ||
| var assertion, a, b, i, li, ol, | ||
| test = this, | ||
| good = 0, | ||
| bad = 0, | ||
| tests = id( "qunit-tests" ); | ||
| config.stats.all += this.assertions.length; | ||
| config.moduleStats.all += this.assertions.length; | ||
| if ( tests ) { | ||
| ol = document.createElement( "ol" ); | ||
| for ( i = 0; i < this.assertions.length; i++ ) { | ||
| assertion = this.assertions[i]; | ||
| li = document.createElement( "li" ); | ||
| li.className = assertion.result ? "pass" : "fail"; | ||
| li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); | ||
| ol.appendChild( li ); | ||
| if ( assertion.result ) { | ||
| good++; | ||
| } else { | ||
| bad++; | ||
| config.stats.bad++; | ||
| config.moduleStats.bad++; | ||
| } | ||
| } | ||
| // store result when possible | ||
| if ( QUnit.config.reorder && defined.sessionStorage ) { | ||
| if ( bad ) { | ||
| sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); | ||
| } else { | ||
| sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); | ||
| } | ||
| } | ||
| if ( bad === 0 ) { | ||
| ol.style.display = "none"; | ||
| } | ||
| // `b` initialized at top of scope | ||
| b = document.createElement( "strong" ); | ||
| b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; | ||
| addEvent(b, "click", function() { | ||
| var next = b.nextSibling.nextSibling, | ||
| display = next.style.display; | ||
| next.style.display = display === "none" ? "block" : "none"; | ||
| }); | ||
| addEvent(b, "dblclick", function( e ) { | ||
| var target = e && e.target ? e.target : window.event.srcElement; | ||
| if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { | ||
| target = target.parentNode; | ||
| } | ||
| if ( window.location && target.nodeName.toLowerCase() === "strong" ) { | ||
| window.location = QUnit.url({ testNumber: test.testNumber }); | ||
| } | ||
| }); | ||
| // `li` initialized at top of scope | ||
| li = id( this.id ); | ||
| li.className = bad ? "fail" : "pass"; | ||
| li.removeChild( li.firstChild ); | ||
| a = li.firstChild; | ||
| li.appendChild( b ); | ||
| li.appendChild ( a ); | ||
| li.appendChild( ol ); | ||
| } else { | ||
| for ( i = 0; i < this.assertions.length; i++ ) { | ||
| if ( !this.assertions[i].result ) { | ||
| bad++; | ||
| config.stats.bad++; | ||
| config.moduleStats.bad++; | ||
| } | ||
| } | ||
| } | ||
| runLoggingCallbacks( "testDone", QUnit, { | ||
| name: this.testName, | ||
| module: this.module, | ||
| failed: bad, | ||
| passed: this.assertions.length - bad, | ||
| total: this.assertions.length | ||
| }); | ||
| QUnit.reset(); | ||
| config.current = undefined; | ||
| }, | ||
| queue: function() { | ||
| var bad, | ||
| test = this; | ||
| synchronize(function() { | ||
| test.init(); | ||
| }); | ||
| function run() { | ||
| // each of these can by async | ||
| synchronize(function() { | ||
| test.setup(); | ||
| }); | ||
| synchronize(function() { | ||
| test.run(); | ||
| }); | ||
| synchronize(function() { | ||
| test.teardown(); | ||
| }); | ||
| synchronize(function() { | ||
| test.finish(); | ||
| }); | ||
| } | ||
| // `bad` initialized at top of scope | ||
| // defer when previous test run passed, if storage is available | ||
| bad = QUnit.config.reorder && defined.sessionStorage && | ||
| +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); | ||
| if ( bad ) { | ||
| run(); | ||
| } else { | ||
| synchronize( run, true ); | ||
| } | ||
| } | ||
| }; | ||
| // Root QUnit object. | ||
| // `QUnit` initialized at top of scope | ||
| QUnit = { | ||
| // call on start of module test to prepend name to all tests | ||
| module: function( name, testEnvironment ) { | ||
| config.currentModule = name; | ||
| config.currentModuleTestEnviroment = testEnvironment; | ||
| }, | ||
| asyncTest: function( testName, expected, callback ) { | ||
| if ( arguments.length === 2 ) { | ||
| callback = expected; | ||
| expected = null; | ||
| } | ||
| QUnit.test( testName, expected, callback, true ); | ||
| }, | ||
| test: function( testName, expected, callback, async ) { | ||
| var test, | ||
| name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>"; | ||
| if ( arguments.length === 2 ) { | ||
| callback = expected; | ||
| expected = null; | ||
| } | ||
| if ( config.currentModule ) { | ||
| name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; | ||
| } | ||
| test = new Test({ | ||
| name: name, | ||
| testName: testName, | ||
| expected: expected, | ||
| async: async, | ||
| callback: callback, | ||
| module: config.currentModule, | ||
| moduleTestEnvironment: config.currentModuleTestEnviroment, | ||
| stack: sourceFromStacktrace( 2 ) | ||
| }); | ||
| if ( !validTest( test ) ) { | ||
| return; | ||
| } | ||
| test.queue(); | ||
| }, | ||
| // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. | ||
| expect: function( asserts ) { | ||
| config.current.expected = asserts; | ||
| }, | ||
| start: function( count ) { | ||
| config.semaphore -= count || 1; | ||
| // don't start until equal number of stop-calls | ||
| if ( config.semaphore > 0 ) { | ||
| return; | ||
| } | ||
| // ignore if start is called more often then stop | ||
| if ( config.semaphore < 0 ) { | ||
| config.semaphore = 0; | ||
| } | ||
| // A slight delay, to avoid any current callbacks | ||
| if ( defined.setTimeout ) { | ||
| window.setTimeout(function() { | ||
| if ( config.semaphore > 0 ) { | ||
| return; | ||
| } | ||
| if ( config.timeout ) { | ||
| clearTimeout( config.timeout ); | ||
| } | ||
| config.blocking = false; | ||
| process( true ); | ||
| }, 13); | ||
| } else { | ||
| config.blocking = false; | ||
| process( true ); | ||
| } | ||
| }, | ||
| stop: function( count ) { | ||
| config.semaphore += count || 1; | ||
| config.blocking = true; | ||
| if ( config.testTimeout && defined.setTimeout ) { | ||
| clearTimeout( config.timeout ); | ||
| config.timeout = window.setTimeout(function() { | ||
| QUnit.ok( false, "Test timed out" ); | ||
| config.semaphore = 1; | ||
| QUnit.start(); | ||
| }, config.testTimeout ); | ||
| } | ||
| } | ||
| }; | ||
| // Asssert helpers | ||
| // All of these must call either QUnit.push() or manually do: | ||
| // - runLoggingCallbacks( "log", .. ); | ||
| // - config.current.assertions.push({ .. }); | ||
| QUnit.assert = { | ||
| /** | ||
| * Asserts rough true-ish result. | ||
| * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); | ||
| */ | ||
| ok: function( result, msg ) { | ||
| if ( !config.current ) { | ||
| throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); | ||
| } | ||
| result = !!result; | ||
| var source, | ||
| details = { | ||
| result: result, | ||
| message: msg | ||
| }; | ||
| msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); | ||
| msg = "<span class='test-message'>" + msg + "</span>"; | ||
| if ( !result ) { | ||
| source = sourceFromStacktrace( 2 ); | ||
| if ( source ) { | ||
| details.source = source; | ||
| msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; | ||
| } | ||
| } | ||
| runLoggingCallbacks( "log", QUnit, details ); | ||
| config.current.assertions.push({ | ||
| result: result, | ||
| message: msg | ||
| }); | ||
| }, | ||
| /** | ||
| * Assert that the first two arguments are equal, with an optional message. | ||
| * Prints out both actual and expected values. | ||
| * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); | ||
| */ | ||
| equal: function( actual, expected, message ) { | ||
| QUnit.push( expected == actual, actual, expected, message ); | ||
| }, | ||
| notEqual: function( actual, expected, message ) { | ||
| QUnit.push( expected != actual, actual, expected, message ); | ||
| }, | ||
| deepEqual: function( actual, expected, message ) { | ||
| QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); | ||
| }, | ||
| notDeepEqual: function( actual, expected, message ) { | ||
| QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); | ||
| }, | ||
| strictEqual: function( actual, expected, message ) { | ||
| QUnit.push( expected === actual, actual, expected, message ); | ||
| }, | ||
| notStrictEqual: function( actual, expected, message ) { | ||
| QUnit.push( expected !== actual, actual, expected, message ); | ||
| }, | ||
| raises: function( block, expected, message ) { | ||
| var actual, | ||
| ok = false; | ||
| if ( typeof expected === "string" ) { | ||
| message = expected; | ||
| expected = null; | ||
| } | ||
| config.current.ignoreGlobalErrors = true; | ||
| try { | ||
| block.call( config.current.testEnvironment ); | ||
| } catch (e) { | ||
| actual = e; | ||
| } | ||
| config.current.ignoreGlobalErrors = false; | ||
| if ( actual ) { | ||
| // we don't want to validate thrown error | ||
| if ( !expected ) { | ||
| ok = true; | ||
| // expected is a regexp | ||
| } else if ( QUnit.objectType( expected ) === "regexp" ) { | ||
| ok = expected.test( actual ); | ||
| // expected is a constructor | ||
| } else if ( actual instanceof expected ) { | ||
| ok = true; | ||
| // expected is a validation function which returns true is validation passed | ||
| } else if ( expected.call( {}, actual ) === true ) { | ||
| ok = true; | ||
| } | ||
| } | ||
| QUnit.push( ok, actual, null, message ); | ||
| } | ||
| }; | ||
| // @deprecated: Kept assertion helpers in root for backwards compatibility | ||
| extend( QUnit, QUnit.assert ); | ||
| /** | ||
| * @deprecated: Kept for backwards compatibility | ||
| * next step: remove entirely | ||
| */ | ||
| QUnit.equals = function() { | ||
| QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); | ||
| }; | ||
| QUnit.same = function() { | ||
| QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); | ||
| }; | ||
| // We want access to the constructor's prototype | ||
| (function() { | ||
| function F() {} | ||
| F.prototype = QUnit; | ||
| QUnit = new F(); | ||
| // Make F QUnit's constructor so that we can add to the prototype later | ||
| QUnit.constructor = F; | ||
| }()); | ||
| /** | ||
| * Config object: Maintain internal state | ||
| * Later exposed as QUnit.config | ||
| * `config` initialized at top of scope | ||
| */ | ||
| config = { | ||
| // The queue of tests to run | ||
| queue: [], | ||
| // block until document ready | ||
| blocking: true, | ||
| // when enabled, show only failing tests | ||
| // gets persisted through sessionStorage and can be changed in UI via checkbox | ||
| hidepassed: false, | ||
| // by default, run previously failed tests first | ||
| // very useful in combination with "Hide passed tests" checked | ||
| reorder: true, | ||
| // by default, modify document.title when suite is done | ||
| altertitle: true, | ||
| // when enabled, all tests must call expect() | ||
| requireExpects: false, | ||
| urlConfig: [ "noglobals", "notrycatch" ], | ||
| // logging callback queues | ||
| begin: [], | ||
| done: [], | ||
| log: [], | ||
| testStart: [], | ||
| testDone: [], | ||
| moduleStart: [], | ||
| moduleDone: [] | ||
| }; | ||
| // Initialize more QUnit.config and QUnit.urlParams | ||
| (function() { | ||
| var i, | ||
| location = window.location || { search: "", protocol: "file:" }, | ||
| params = location.search.slice( 1 ).split( "&" ), | ||
| length = params.length, | ||
| urlParams = {}, | ||
| current; | ||
| if ( params[ 0 ] ) { | ||
| for ( i = 0; i < length; i++ ) { | ||
| current = params[ i ].split( "=" ); | ||
| current[ 0 ] = decodeURIComponent( current[ 0 ] ); | ||
| // allow just a key to turn on a flag, e.g., test.html?noglobals | ||
| current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; | ||
| urlParams[ current[ 0 ] ] = current[ 1 ]; | ||
| } | ||
| } | ||
| QUnit.urlParams = urlParams; | ||
| // String search anywhere in moduleName+testName | ||
| config.filter = urlParams.filter; | ||
| // Exact match of the module name | ||
| config.module = urlParams.module; | ||
| config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; | ||
| // Figure out if we're running the tests from a server or not | ||
| QUnit.isLocal = location.protocol === "file:"; | ||
| }()); | ||
| // Export global variables, unless an 'exports' object exists, | ||
| // in that case we assume we're in CommonJS (dealt with on the bottom of the script) | ||
| if ( typeof exports === "undefined" ) { | ||
| extend( window, QUnit ); | ||
| // Expose QUnit object | ||
| window.QUnit = QUnit; | ||
| } | ||
| // Extend QUnit object, | ||
| // these after set here because they should not be exposed as global functions | ||
| extend( QUnit, { | ||
| config: config, | ||
| // Initialize the configuration options | ||
| init: function() { | ||
| extend( config, { | ||
| stats: { all: 0, bad: 0 }, | ||
| moduleStats: { all: 0, bad: 0 }, | ||
| started: +new Date(), | ||
| updateRate: 1000, | ||
| blocking: false, | ||
| autostart: true, | ||
| autorun: false, | ||
| filter: "", | ||
| queue: [], | ||
| semaphore: 0 | ||
| }); | ||
| var tests, banner, result, | ||
| qunit = id( "qunit" ); | ||
| if ( qunit ) { | ||
| qunit.innerHTML = | ||
| "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" + | ||
| "<h2 id='qunit-banner'></h2>" + | ||
| "<div id='qunit-testrunner-toolbar'></div>" + | ||
| "<h2 id='qunit-userAgent'></h2>" + | ||
| "<ol id='qunit-tests'></ol>"; | ||
| } | ||
| tests = id( "qunit-tests" ); | ||
| banner = id( "qunit-banner" ); | ||
| result = id( "qunit-testresult" ); | ||
| if ( tests ) { | ||
| tests.innerHTML = ""; | ||
| } | ||
| if ( banner ) { | ||
| banner.className = ""; | ||
| } | ||
| if ( result ) { | ||
| result.parentNode.removeChild( result ); | ||
| } | ||
| if ( tests ) { | ||
| result = document.createElement( "p" ); | ||
| result.id = "qunit-testresult"; | ||
| result.className = "result"; | ||
| tests.parentNode.insertBefore( result, tests ); | ||
| result.innerHTML = "Running...<br/> "; | ||
| } | ||
| }, | ||
| // Resets the test setup. Useful for tests that modify the DOM. | ||
| // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. | ||
| reset: function() { | ||
| var fixture; | ||
| if ( window.jQuery ) { | ||
| jQuery( "#qunit-fixture" ).html( config.fixture ); | ||
| } else { | ||
| fixture = id( "qunit-fixture" ); | ||
| if ( fixture ) { | ||
| fixture.innerHTML = config.fixture; | ||
| } | ||
| } | ||
| }, | ||
| // Trigger an event on an element. | ||
| // @example triggerEvent( document.body, "click" ); | ||
| triggerEvent: function( elem, type, event ) { | ||
| if ( document.createEvent ) { | ||
| event = document.createEvent( "MouseEvents" ); | ||
| event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, | ||
| 0, 0, 0, 0, 0, false, false, false, false, 0, null); | ||
| elem.dispatchEvent( event ); | ||
| } else if ( elem.fireEvent ) { | ||
| elem.fireEvent( "on" + type ); | ||
| } | ||
| }, | ||
| // Safe object type checking | ||
| is: function( type, obj ) { | ||
| return QUnit.objectType( obj ) == type; | ||
| }, | ||
| objectType: function( obj ) { | ||
| if ( typeof obj === "undefined" ) { | ||
| return "undefined"; | ||
| // consider: typeof null === object | ||
| } | ||
| if ( obj === null ) { | ||
| return "null"; | ||
| } | ||
| var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; | ||
| switch ( type ) { | ||
| case "Number": | ||
| if ( isNaN(obj) ) { | ||
| return "nan"; | ||
| } | ||
| return "number"; | ||
| case "String": | ||
| case "Boolean": | ||
| case "Array": | ||
| case "Date": | ||
| case "RegExp": | ||
| case "Function": | ||
| return type.toLowerCase(); | ||
| } | ||
| if ( typeof obj === "object" ) { | ||
| return "object"; | ||
| } | ||
| return undefined; | ||
| }, | ||
| push: function( result, actual, expected, message ) { | ||
| if ( !config.current ) { | ||
| throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); | ||
| } | ||
| var output, source, | ||
| details = { | ||
| result: result, | ||
| message: message, | ||
| actual: actual, | ||
| expected: expected | ||
| }; | ||
| message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); | ||
| message = "<span class='test-message'>" + message + "</span>"; | ||
| output = message; | ||
| if ( !result ) { | ||
| expected = escapeInnerText( QUnit.jsDump.parse(expected) ); | ||
| actual = escapeInnerText( QUnit.jsDump.parse(actual) ); | ||
| output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>"; | ||
| if ( actual != expected ) { | ||
| output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>"; | ||
| output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>"; | ||
| } | ||
| source = sourceFromStacktrace(); | ||
| if ( source ) { | ||
| details.source = source; | ||
| output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; | ||
| } | ||
| output += "</table>"; | ||
| } | ||
| runLoggingCallbacks( "log", QUnit, details ); | ||
| config.current.assertions.push({ | ||
| result: !!result, | ||
| message: output | ||
| }); | ||
| }, | ||
| pushFailure: function( message, source ) { | ||
| if ( !config.current ) { | ||
| throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); | ||
| } | ||
| var output, | ||
| details = { | ||
| result: false, | ||
| message: message | ||
| }; | ||
| message = escapeInnerText(message ) || "error"; | ||
| message = "<span class='test-message'>" + message + "</span>"; | ||
| output = message; | ||
| if ( source ) { | ||
| details.source = source; | ||
| output += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; | ||
| } | ||
| runLoggingCallbacks( "log", QUnit, details ); | ||
| config.current.assertions.push({ | ||
| result: false, | ||
| message: output | ||
| }); | ||
| }, | ||
| url: function( params ) { | ||
| params = extend( extend( {}, QUnit.urlParams ), params ); | ||
| var key, | ||
| querystring = "?"; | ||
| for ( key in params ) { | ||
| if ( !hasOwn.call( params, key ) ) { | ||
| continue; | ||
| } | ||
| querystring += encodeURIComponent( key ) + "=" + | ||
| encodeURIComponent( params[ key ] ) + "&"; | ||
| } | ||
| return window.location.pathname + querystring.slice( 0, -1 ); | ||
| }, | ||
| extend: extend, | ||
| id: id, | ||
| addEvent: addEvent | ||
| // load, equiv, jsDump, diff: Attached later | ||
| }); | ||
| /** | ||
| * @deprecated: Created for backwards compatibility with test runner that set the hook function | ||
| * into QUnit.{hook}, instead of invoking it and passing the hook function. | ||
| * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. | ||
| * Doing this allows us to tell if the following methods have been overwritten on the actual | ||
| * QUnit object. | ||
| */ | ||
| extend( QUnit.constructor.prototype, { | ||
| // Logging callbacks; all receive a single argument with the listed properties | ||
| // run test/logs.html for any related changes | ||
| begin: registerLoggingCallback( "begin" ), | ||
| // done: { failed, passed, total, runtime } | ||
| done: registerLoggingCallback( "done" ), | ||
| // log: { result, actual, expected, message } | ||
| log: registerLoggingCallback( "log" ), | ||
| // testStart: { name } | ||
| testStart: registerLoggingCallback( "testStart" ), | ||
| // testDone: { name, failed, passed, total } | ||
| testDone: registerLoggingCallback( "testDone" ), | ||
| // moduleStart: { name } | ||
| moduleStart: registerLoggingCallback( "moduleStart" ), | ||
| // moduleDone: { name, failed, passed, total } | ||
| moduleDone: registerLoggingCallback( "moduleDone" ) | ||
| }); | ||
| if ( typeof document === "undefined" || document.readyState === "complete" ) { | ||
| config.autorun = true; | ||
| } | ||
| QUnit.load = function() { | ||
| runLoggingCallbacks( "begin", QUnit, {} ); | ||
| // Initialize the config, saving the execution queue | ||
| var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, | ||
| urlConfigHtml = "", | ||
| oldconfig = extend( {}, config ); | ||
| QUnit.init(); | ||
| extend(config, oldconfig); | ||
| config.blocking = false; | ||
| len = config.urlConfig.length; | ||
| for ( i = 0; i < len; i++ ) { | ||
| val = config.urlConfig[i]; | ||
| config[val] = QUnit.urlParams[val]; | ||
| urlConfigHtml += "<label><input name='" + val + "' type='checkbox'" + ( config[val] ? " checked='checked'" : "" ) + ">" + val + "</label>"; | ||
| } | ||
| // `userAgent` initialized at top of scope | ||
| userAgent = id( "qunit-userAgent" ); | ||
| if ( userAgent ) { | ||
| userAgent.innerHTML = navigator.userAgent; | ||
| } | ||
| // `banner` initialized at top of scope | ||
| banner = id( "qunit-header" ); | ||
| if ( banner ) { | ||
| banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined }) + "'>" + banner.innerHTML + "</a> " + urlConfigHtml; | ||
| addEvent( banner, "change", function( event ) { | ||
| var params = {}; | ||
| params[ event.target.name ] = event.target.checked ? true : undefined; | ||
| window.location = QUnit.url( params ); | ||
| }); | ||
| } | ||
| // `toolbar` initialized at top of scope | ||
| toolbar = id( "qunit-testrunner-toolbar" ); | ||
| if ( toolbar ) { | ||
| // `filter` initialized at top of scope | ||
| filter = document.createElement( "input" ); | ||
| filter.type = "checkbox"; | ||
| filter.id = "qunit-filter-pass"; | ||
| addEvent( filter, "click", function() { | ||
| var tmp, | ||
| ol = document.getElementById( "qunit-tests" ); | ||
| if ( filter.checked ) { | ||
| ol.className = ol.className + " hidepass"; | ||
| } else { | ||
| tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; | ||
| ol.className = tmp.replace( / hidepass /, " " ); | ||
| } | ||
| if ( defined.sessionStorage ) { | ||
| if (filter.checked) { | ||
| sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); | ||
| } else { | ||
| sessionStorage.removeItem( "qunit-filter-passed-tests" ); | ||
| } | ||
| } | ||
| }); | ||
| if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { | ||
| filter.checked = true; | ||
| // `ol` initialized at top of scope | ||
| ol = document.getElementById( "qunit-tests" ); | ||
| ol.className = ol.className + " hidepass"; | ||
| } | ||
| toolbar.appendChild( filter ); | ||
| // `label` initialized at top of scope | ||
| label = document.createElement( "label" ); | ||
| label.setAttribute( "for", "qunit-filter-pass" ); | ||
| label.innerHTML = "Hide passed tests"; | ||
| toolbar.appendChild( label ); | ||
| } | ||
| // `main` initialized at top of scope | ||
| main = id( "qunit-fixture" ); | ||
| if ( main ) { | ||
| config.fixture = main.innerHTML; | ||
| } | ||
| if ( config.autostart ) { | ||
| QUnit.start(); | ||
| } | ||
| }; | ||
| addEvent( window, "load", QUnit.load ); | ||
| // `onErrorFnPrev` initialized at top of scope | ||
| // Preserve other handlers | ||
| onErrorFnPrev = window.onerror; | ||
| // Cover uncaught exceptions | ||
| // Returning true will surpress the default browser handler, | ||
| // returning false will let it run. | ||
| window.onerror = function ( error, filePath, linerNr ) { | ||
| var ret = false; | ||
| if ( onErrorFnPrev ) { | ||
| ret = onErrorFnPrev( error, filePath, linerNr ); | ||
| } | ||
| // Treat return value as window.onerror itself does, | ||
| // Only do our handling if not surpressed. | ||
| if ( ret !== true ) { | ||
| if ( QUnit.config.current ) { | ||
| if ( QUnit.config.current.ignoreGlobalErrors ) { | ||
| return true; | ||
| } | ||
| QUnit.pushFailure( error, filePath + ":" + linerNr ); | ||
| } else { | ||
| QUnit.test( "global failure", function() { | ||
| QUnit.pushFailure( error, filePath + ":" + linerNr ); | ||
| }); | ||
| } | ||
| return false; | ||
| } | ||
| return ret; | ||
| }; | ||
| function done() { | ||
| config.autorun = true; | ||
| // Log the last module results | ||
| if ( config.currentModule ) { | ||
| runLoggingCallbacks( "moduleDone", QUnit, { | ||
| name: config.currentModule, | ||
| failed: config.moduleStats.bad, | ||
| passed: config.moduleStats.all - config.moduleStats.bad, | ||
| total: config.moduleStats.all | ||
| }); | ||
| } | ||
| var i, key, | ||
| banner = id( "qunit-banner" ), | ||
| tests = id( "qunit-tests" ), | ||
| runtime = +new Date() - config.started, | ||
| passed = config.stats.all - config.stats.bad, | ||
| html = [ | ||
| "Tests completed in ", | ||
| runtime, | ||
| " milliseconds.<br/>", | ||
| "<span class='passed'>", | ||
| passed, | ||
| "</span> tests of <span class='total'>", | ||
| config.stats.all, | ||
| "</span> passed, <span class='failed'>", | ||
| config.stats.bad, | ||
| "</span> failed." | ||
| ].join( "" ); | ||
| if ( banner ) { | ||
| banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); | ||
| } | ||
| if ( tests ) { | ||
| id( "qunit-testresult" ).innerHTML = html; | ||
| } | ||
| if ( config.altertitle && typeof document !== "undefined" && document.title ) { | ||
| // show ✖ for good, ✔ for bad suite result in title | ||
| // use escape sequences in case file gets loaded with non-utf-8-charset | ||
| document.title = [ | ||
| ( config.stats.bad ? "\u2716" : "\u2714" ), | ||
| document.title.replace( /^[\u2714\u2716] /i, "" ) | ||
| ].join( " " ); | ||
| } | ||
| // clear own sessionStorage items if all tests passed | ||
| if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { | ||
| // `key` & `i` initialized at top of scope | ||
| for ( i = 0; i < sessionStorage.length; i++ ) { | ||
| key = sessionStorage.key( i++ ); | ||
| if ( key.indexOf( "qunit-test-" ) === 0 ) { | ||
| sessionStorage.removeItem( key ); | ||
| } | ||
| } | ||
| } | ||
| runLoggingCallbacks( "done", QUnit, { | ||
| failed: config.stats.bad, | ||
| passed: passed, | ||
| total: config.stats.all, | ||
| runtime: runtime | ||
| }); | ||
| } | ||
| /** @return Boolean: true if this test should be ran */ | ||
| function validTest( test ) { | ||
| var include, | ||
| filter = config.filter && config.filter.toLowerCase(), | ||
| module = config.module, | ||
| fullName = (test.module + ": " + test.testName).toLowerCase(); | ||
| if ( config.testNumber ) { | ||
| return test.testNumber === config.testNumber; | ||
| } | ||
| if ( module && test.module !== module ) { | ||
| return false; | ||
| } | ||
| if ( !filter ) { | ||
| return true; | ||
| } | ||
| include = filter.charAt( 0 ) !== "!"; | ||
| if ( !include ) { | ||
| filter = filter.slice( 1 ); | ||
| } | ||
| // If the filter matches, we need to honour include | ||
| if ( fullName.indexOf( filter ) !== -1 ) { | ||
| return include; | ||
| } | ||
| // Otherwise, do the opposite | ||
| return !include; | ||
| } | ||
| // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) | ||
| // Later Safari and IE10 are supposed to support error.stack as well | ||
| // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack | ||
| function extractStacktrace( e, offset ) { | ||
| offset = offset === undefined ? 3 : offset; | ||
| var stack, include, i, regex; | ||
| if ( e.stacktrace ) { | ||
| // Opera | ||
| return e.stacktrace.split( "\n" )[ offset + 3 ]; | ||
| } else if ( e.stack ) { | ||
| // Firefox, Chrome | ||
| stack = e.stack.split( "\n" ); | ||
| if (/^error$/i.test( stack[0] ) ) { | ||
| stack.shift(); | ||
| } | ||
| if ( fileName ) { | ||
| include = []; | ||
| for ( i = offset; i < stack.length; i++ ) { | ||
| if ( stack[ i ].indexOf( fileName ) != -1 ) { | ||
| break; | ||
| } | ||
| include.push( stack[ i ] ); | ||
| } | ||
| if ( include.length ) { | ||
| return include.join( "\n" ); | ||
| } | ||
| } | ||
| return stack[ offset ]; | ||
| } else if ( e.sourceURL ) { | ||
| // Safari, PhantomJS | ||
| // hopefully one day Safari provides actual stacktraces | ||
| // exclude useless self-reference for generated Error objects | ||
| if ( /qunit.js$/.test( e.sourceURL ) ) { | ||
| return; | ||
| } | ||
| // for actual exceptions, this is useful | ||
| return e.sourceURL + ":" + e.line; | ||
| } | ||
| } | ||
| function sourceFromStacktrace( offset ) { | ||
| try { | ||
| throw new Error(); | ||
| } catch ( e ) { | ||
| return extractStacktrace( e, offset ); | ||
| } | ||
| } | ||
| function escapeInnerText( s ) { | ||
| if ( !s ) { | ||
| return ""; | ||
| } | ||
| s = s + ""; | ||
| return s.replace( /[\&<>]/g, function( s ) { | ||
| switch( s ) { | ||
| case "&": return "&"; | ||
| case "<": return "<"; | ||
| case ">": return ">"; | ||
| default: return s; | ||
| } | ||
| }); | ||
| } | ||
| function synchronize( callback, last ) { | ||
| config.queue.push( callback ); | ||
| if ( config.autorun && !config.blocking ) { | ||
| process( last ); | ||
| } | ||
| } | ||
| function process( last ) { | ||
| function next() { | ||
| process( last ); | ||
| } | ||
| var start = new Date().getTime(); | ||
| config.depth = config.depth ? config.depth + 1 : 1; | ||
| while ( config.queue.length && !config.blocking ) { | ||
| if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { | ||
| config.queue.shift()(); | ||
| } else { | ||
| window.setTimeout( next, 13 ); | ||
| break; | ||
| } | ||
| } | ||
| config.depth--; | ||
| if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { | ||
| done(); | ||
| } | ||
| } | ||
| function saveGlobal() { | ||
| config.pollution = []; | ||
| if ( config.noglobals ) { | ||
| for ( var key in window ) { | ||
| // in Opera sometimes DOM element ids show up here, ignore them | ||
| if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { | ||
| continue; | ||
| } | ||
| config.pollution.push( key ); | ||
| } | ||
| } | ||
| } | ||
| function checkPollution( name ) { | ||
| var newGlobals, | ||
| deletedGlobals, | ||
| old = config.pollution; | ||
| saveGlobal(); | ||
| newGlobals = diff( config.pollution, old ); | ||
| if ( newGlobals.length > 0 ) { | ||
| QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); | ||
| } | ||
| deletedGlobals = diff( old, config.pollution ); | ||
| if ( deletedGlobals.length > 0 ) { | ||
| QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); | ||
| } | ||
| } | ||
| // returns a new Array with the elements that are in a but not in b | ||
| function diff( a, b ) { | ||
| var i, j, | ||
| result = a.slice(); | ||
| for ( i = 0; i < result.length; i++ ) { | ||
| for ( j = 0; j < b.length; j++ ) { | ||
| if ( result[i] === b[j] ) { | ||
| result.splice( i, 1 ); | ||
| i--; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| function extend( a, b ) { | ||
| for ( var prop in b ) { | ||
| if ( b[ prop ] === undefined ) { | ||
| delete a[ prop ]; | ||
| // Avoid "Member not found" error in IE8 caused by setting window.constructor | ||
| } else if ( prop !== "constructor" || a !== window ) { | ||
| a[ prop ] = b[ prop ]; | ||
| } | ||
| } | ||
| return a; | ||
| } | ||
| function addEvent( elem, type, fn ) { | ||
| if ( elem.addEventListener ) { | ||
| elem.addEventListener( type, fn, false ); | ||
| } else if ( elem.attachEvent ) { | ||
| elem.attachEvent( "on" + type, fn ); | ||
| } else { | ||
| fn(); | ||
| } | ||
| } | ||
| function id( name ) { | ||
| return !!( typeof document !== "undefined" && document && document.getElementById ) && | ||
| document.getElementById( name ); | ||
| } | ||
| function registerLoggingCallback( key ) { | ||
| return function( callback ) { | ||
| config[key].push( callback ); | ||
| }; | ||
| } | ||
| // Supports deprecated method of completely overwriting logging callbacks | ||
| function runLoggingCallbacks( key, scope, args ) { | ||
| //debugger; | ||
| var i, callbacks; | ||
| if ( QUnit.hasOwnProperty( key ) ) { | ||
| QUnit[ key ].call(scope, args ); | ||
| } else { | ||
| callbacks = config[ key ]; | ||
| for ( i = 0; i < callbacks.length; i++ ) { | ||
| callbacks[ i ].call( scope, args ); | ||
| } | ||
| } | ||
| } | ||
| // Test for equality any JavaScript type. | ||
| // Author: Philippe Rathé <prathe@gmail.com> | ||
| QUnit.equiv = (function() { | ||
| // Call the o related callback with the given arguments. | ||
| function bindCallbacks( o, callbacks, args ) { | ||
| var prop = QUnit.objectType( o ); | ||
| if ( prop ) { | ||
| if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { | ||
| return callbacks[ prop ].apply( callbacks, args ); | ||
| } else { | ||
| return callbacks[ prop ]; // or undefined | ||
| } | ||
| } | ||
| } | ||
| // the real equiv function | ||
| var innerEquiv, | ||
| // stack to decide between skip/abort functions | ||
| callers = [], | ||
| // stack to avoiding loops from circular referencing | ||
| parents = [], | ||
| getProto = Object.getPrototypeOf || function ( obj ) { | ||
| return obj.__proto__; | ||
| }, | ||
| callbacks = (function () { | ||
| // for string, boolean, number and null | ||
| function useStrictEquality( b, a ) { | ||
| if ( b instanceof a.constructor || a instanceof b.constructor ) { | ||
| // to catch short annotaion VS 'new' annotation of a | ||
| // declaration | ||
| // e.g. var i = 1; | ||
| // var j = new Number(1); | ||
| return a == b; | ||
| } else { | ||
| return a === b; | ||
| } | ||
| } | ||
| return { | ||
| "string": useStrictEquality, | ||
| "boolean": useStrictEquality, | ||
| "number": useStrictEquality, | ||
| "null": useStrictEquality, | ||
| "undefined": useStrictEquality, | ||
| "nan": function( b ) { | ||
| return isNaN( b ); | ||
| }, | ||
| "date": function( b, a ) { | ||
| return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); | ||
| }, | ||
| "regexp": function( b, a ) { | ||
| return QUnit.objectType( b ) === "regexp" && | ||
| // the regex itself | ||
| a.source === b.source && | ||
| // and its modifers | ||
| a.global === b.global && | ||
| // (gmi) ... | ||
| a.ignoreCase === b.ignoreCase && | ||
| a.multiline === b.multiline; | ||
| }, | ||
| // - skip when the property is a method of an instance (OOP) | ||
| // - abort otherwise, | ||
| // initial === would have catch identical references anyway | ||
| "function": function() { | ||
| var caller = callers[callers.length - 1]; | ||
| return caller !== Object && typeof caller !== "undefined"; | ||
| }, | ||
| "array": function( b, a ) { | ||
| var i, j, len, loop; | ||
| // b could be an object literal here | ||
| if ( QUnit.objectType( b ) !== "array" ) { | ||
| return false; | ||
| } | ||
| len = a.length; | ||
| if ( len !== b.length ) { | ||
| // safe and faster | ||
| return false; | ||
| } | ||
| // track reference to avoid circular references | ||
| parents.push( a ); | ||
| for ( i = 0; i < len; i++ ) { | ||
| loop = false; | ||
| for ( j = 0; j < parents.length; j++ ) { | ||
| if ( parents[j] === a[i] ) { | ||
| loop = true;// dont rewalk array | ||
| } | ||
| } | ||
| if ( !loop && !innerEquiv(a[i], b[i]) ) { | ||
| parents.pop(); | ||
| return false; | ||
| } | ||
| } | ||
| parents.pop(); | ||
| return true; | ||
| }, | ||
| "object": function( b, a ) { | ||
| var i, j, loop, | ||
| // Default to true | ||
| eq = true, | ||
| aProperties = [], | ||
| bProperties = []; | ||
| // comparing constructors is more strict than using | ||
| // instanceof | ||
| if ( a.constructor !== b.constructor ) { | ||
| // Allow objects with no prototype to be equivalent to | ||
| // objects with Object as their constructor. | ||
| if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || | ||
| ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { | ||
| return false; | ||
| } | ||
| } | ||
| // stack constructor before traversing properties | ||
| callers.push( a.constructor ); | ||
| // track reference to avoid circular references | ||
| parents.push( a ); | ||
| for ( i in a ) { // be strict: don't ensures hasOwnProperty | ||
| // and go deep | ||
| loop = false; | ||
| for ( j = 0; j < parents.length; j++ ) { | ||
| if ( parents[j] === a[i] ) { | ||
| // don't go down the same path twice | ||
| loop = true; | ||
| } | ||
| } | ||
| aProperties.push(i); // collect a's properties | ||
| if (!loop && !innerEquiv( a[i], b[i] ) ) { | ||
| eq = false; | ||
| break; | ||
| } | ||
| } | ||
| callers.pop(); // unstack, we are done | ||
| parents.pop(); | ||
| for ( i in b ) { | ||
| bProperties.push( i ); // collect b's properties | ||
| } | ||
| // Ensures identical properties name | ||
| return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); | ||
| } | ||
| }; | ||
| }()); | ||
| innerEquiv = function() { // can take multiple arguments | ||
| var args = [].slice.apply( arguments ); | ||
| if ( args.length < 2 ) { | ||
| return true; // end transition | ||
| } | ||
| return (function( a, b ) { | ||
| if ( a === b ) { | ||
| return true; // catch the most you can | ||
| } else if ( a === null || b === null || typeof a === "undefined" || | ||
| typeof b === "undefined" || | ||
| QUnit.objectType(a) !== QUnit.objectType(b) ) { | ||
| return false; // don't lose time with error prone cases | ||
| } else { | ||
| return bindCallbacks(a, callbacks, [ b, a ]); | ||
| } | ||
| // apply transition with (1..n) arguments | ||
| }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); | ||
| }; | ||
| return innerEquiv; | ||
| }()); | ||
| /** | ||
| * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | | ||
| * http://flesler.blogspot.com Licensed under BSD | ||
| * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 | ||
| * | ||
| * @projectDescription Advanced and extensible data dumping for Javascript. | ||
| * @version 1.0.0 | ||
| * @author Ariel Flesler | ||
| * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} | ||
| */ | ||
| QUnit.jsDump = (function() { | ||
| function quote( str ) { | ||
| return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; | ||
| } | ||
| function literal( o ) { | ||
| return o + ""; | ||
| } | ||
| function join( pre, arr, post ) { | ||
| var s = jsDump.separator(), | ||
| base = jsDump.indent(), | ||
| inner = jsDump.indent(1); | ||
| if ( arr.join ) { | ||
| arr = arr.join( "," + s + inner ); | ||
| } | ||
| if ( !arr ) { | ||
| return pre + post; | ||
| } | ||
| return [ pre, inner + arr, base + post ].join(s); | ||
| } | ||
| function array( arr, stack ) { | ||
| var i = arr.length, ret = new Array(i); | ||
| this.up(); | ||
| while ( i-- ) { | ||
| ret[i] = this.parse( arr[i] , undefined , stack); | ||
| } | ||
| this.down(); | ||
| return join( "[", ret, "]" ); | ||
| } | ||
| var reName = /^function (\w+)/, | ||
| jsDump = { | ||
| parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance | ||
| stack = stack || [ ]; | ||
| var inStack, res, | ||
| parser = this.parsers[ type || this.typeOf(obj) ]; | ||
| type = typeof parser; | ||
| inStack = inArray( obj, stack ); | ||
| if ( inStack != -1 ) { | ||
| return "recursion(" + (inStack - stack.length) + ")"; | ||
| } | ||
| //else | ||
| if ( type == "function" ) { | ||
| stack.push( obj ); | ||
| res = parser.call( this, obj, stack ); | ||
| stack.pop(); | ||
| return res; | ||
| } | ||
| // else | ||
| return ( type == "string" ) ? parser : this.parsers.error; | ||
| }, | ||
| typeOf: function( obj ) { | ||
| var type; | ||
| if ( obj === null ) { | ||
| type = "null"; | ||
| } else if ( typeof obj === "undefined" ) { | ||
| type = "undefined"; | ||
| } else if ( QUnit.is( "regexp", obj) ) { | ||
| type = "regexp"; | ||
| } else if ( QUnit.is( "date", obj) ) { | ||
| type = "date"; | ||
| } else if ( QUnit.is( "function", obj) ) { | ||
| type = "function"; | ||
| } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { | ||
| type = "window"; | ||
| } else if ( obj.nodeType === 9 ) { | ||
| type = "document"; | ||
| } else if ( obj.nodeType ) { | ||
| type = "node"; | ||
| } else if ( | ||
| // native arrays | ||
| toString.call( obj ) === "[object Array]" || | ||
| // NodeList objects | ||
| ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) | ||
| ) { | ||
| type = "array"; | ||
| } else { | ||
| type = typeof obj; | ||
| } | ||
| return type; | ||
| }, | ||
| separator: function() { | ||
| return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; | ||
| }, | ||
| indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing | ||
| if ( !this.multiline ) { | ||
| return ""; | ||
| } | ||
| var chr = this.indentChar; | ||
| if ( this.HTML ) { | ||
| chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); | ||
| } | ||
| return new Array( this._depth_ + (extra||0) ).join(chr); | ||
| }, | ||
| up: function( a ) { | ||
| this._depth_ += a || 1; | ||
| }, | ||
| down: function( a ) { | ||
| this._depth_ -= a || 1; | ||
| }, | ||
| setParser: function( name, parser ) { | ||
| this.parsers[name] = parser; | ||
| }, | ||
| // The next 3 are exposed so you can use them | ||
| quote: quote, | ||
| literal: literal, | ||
| join: join, | ||
| // | ||
| _depth_: 1, | ||
| // This is the list of parsers, to modify them, use jsDump.setParser | ||
| parsers: { | ||
| window: "[Window]", | ||
| document: "[Document]", | ||
| error: "[ERROR]", //when no parser is found, shouldn"t happen | ||
| unknown: "[Unknown]", | ||
| "null": "null", | ||
| "undefined": "undefined", | ||
| "function": function( fn ) { | ||
| var ret = "function", | ||
| name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE | ||
| if ( name ) { | ||
| ret += " " + name; | ||
| } | ||
| ret += "( "; | ||
| ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); | ||
| return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); | ||
| }, | ||
| array: array, | ||
| nodelist: array, | ||
| "arguments": array, | ||
| object: function( map, stack ) { | ||
| var ret = [ ], keys, key, val, i; | ||
| QUnit.jsDump.up(); | ||
| if ( Object.keys ) { | ||
| keys = Object.keys( map ); | ||
| } else { | ||
| keys = []; | ||
| for ( key in map ) { | ||
| keys.push( key ); | ||
| } | ||
| } | ||
| keys.sort(); | ||
| for ( i = 0; i < keys.length; i++ ) { | ||
| key = keys[ i ]; | ||
| val = map[ key ]; | ||
| ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); | ||
| } | ||
| QUnit.jsDump.down(); | ||
| return join( "{", ret, "}" ); | ||
| }, | ||
| node: function( node ) { | ||
| var a, val, | ||
| open = QUnit.jsDump.HTML ? "<" : "<", | ||
| close = QUnit.jsDump.HTML ? ">" : ">", | ||
| tag = node.nodeName.toLowerCase(), | ||
| ret = open + tag; | ||
| for ( a in QUnit.jsDump.DOMAttrs ) { | ||
| val = node[ QUnit.jsDump.DOMAttrs[a] ]; | ||
| if ( val ) { | ||
| ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); | ||
| } | ||
| } | ||
| return ret + close + open + "/" + tag + close; | ||
| }, | ||
| functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function | ||
| var args, | ||
| l = fn.length; | ||
| if ( !l ) { | ||
| return ""; | ||
| } | ||
| args = new Array(l); | ||
| while ( l-- ) { | ||
| args[l] = String.fromCharCode(97+l);//97 is 'a' | ||
| } | ||
| return " " + args.join( ", " ) + " "; | ||
| }, | ||
| key: quote, //object calls it internally, the key part of an item in a map | ||
| functionCode: "[code]", //function calls it internally, it's the content of the function | ||
| attribute: quote, //node calls it internally, it's an html attribute value | ||
| string: quote, | ||
| date: quote, | ||
| regexp: literal, //regex | ||
| number: literal, | ||
| "boolean": literal | ||
| }, | ||
| DOMAttrs: { | ||
| //attributes to dump from nodes, name=>realName | ||
| id: "id", | ||
| name: "name", | ||
| "class": "className" | ||
| }, | ||
| HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) | ||
| indentChar: " ",//indentation unit | ||
| multiline: true //if true, items in a collection, are separated by a \n, else just a space. | ||
| }; | ||
| return jsDump; | ||
| }()); | ||
| // from Sizzle.js | ||
| function getText( elems ) { | ||
| var i, elem, | ||
| ret = ""; | ||
| for ( i = 0; elems[i]; i++ ) { | ||
| elem = elems[i]; | ||
| // Get the text from text nodes and CDATA nodes | ||
| if ( elem.nodeType === 3 || elem.nodeType === 4 ) { | ||
| ret += elem.nodeValue; | ||
| // Traverse everything else, except comment nodes | ||
| } else if ( elem.nodeType !== 8 ) { | ||
| ret += getText( elem.childNodes ); | ||
| } | ||
| } | ||
| return ret; | ||
| } | ||
| // from jquery.js | ||
| function inArray( elem, array ) { | ||
| if ( array.indexOf ) { | ||
| return array.indexOf( elem ); | ||
| } | ||
| for ( var i = 0, length = array.length; i < length; i++ ) { | ||
| if ( array[ i ] === elem ) { | ||
| return i; | ||
| } | ||
| } | ||
| return -1; | ||
| } | ||
| /* | ||
| * Javascript Diff Algorithm | ||
| * By John Resig (http://ejohn.org/) | ||
| * Modified by Chu Alan "sprite" | ||
| * | ||
| * Released under the MIT license. | ||
| * | ||
| * More Info: | ||
| * http://ejohn.org/projects/javascript-diff-algorithm/ | ||
| * | ||
| * Usage: QUnit.diff(expected, actual) | ||
| * | ||
| * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over" | ||
| */ | ||
| QUnit.diff = (function() { | ||
| function diff( o, n ) { | ||
| var i, | ||
| ns = {}, | ||
| os = {}; | ||
| for ( i = 0; i < n.length; i++ ) { | ||
| if ( ns[ n[i] ] == null ) { | ||
| ns[ n[i] ] = { | ||
| rows: [], | ||
| o: null | ||
| }; | ||
| } | ||
| ns[ n[i] ].rows.push( i ); | ||
| } | ||
| for ( i = 0; i < o.length; i++ ) { | ||
| if ( os[ o[i] ] == null ) { | ||
| os[ o[i] ] = { | ||
| rows: [], | ||
| n: null | ||
| }; | ||
| } | ||
| os[ o[i] ].rows.push( i ); | ||
| } | ||
| for ( i in ns ) { | ||
| if ( !hasOwn.call( ns, i ) ) { | ||
| continue; | ||
| } | ||
| if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { | ||
| n[ ns[i].rows[0] ] = { | ||
| text: n[ ns[i].rows[0] ], | ||
| row: os[i].rows[0] | ||
| }; | ||
| o[ os[i].rows[0] ] = { | ||
| text: o[ os[i].rows[0] ], | ||
| row: ns[i].rows[0] | ||
| }; | ||
| } | ||
| } | ||
| for ( i = 0; i < n.length - 1; i++ ) { | ||
| if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && | ||
| n[ i + 1 ] == o[ n[i].row + 1 ] ) { | ||
| n[ i + 1 ] = { | ||
| text: n[ i + 1 ], | ||
| row: n[i].row + 1 | ||
| }; | ||
| o[ n[i].row + 1 ] = { | ||
| text: o[ n[i].row + 1 ], | ||
| row: i + 1 | ||
| }; | ||
| } | ||
| } | ||
| for ( i = n.length - 1; i > 0; i-- ) { | ||
| if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && | ||
| n[ i - 1 ] == o[ n[i].row - 1 ]) { | ||
| n[ i - 1 ] = { | ||
| text: n[ i - 1 ], | ||
| row: n[i].row - 1 | ||
| }; | ||
| o[ n[i].row - 1 ] = { | ||
| text: o[ n[i].row - 1 ], | ||
| row: i - 1 | ||
| }; | ||
| } | ||
| } | ||
| return { | ||
| o: o, | ||
| n: n | ||
| }; | ||
| } | ||
| return function( o, n ) { | ||
| o = o.replace( /\s+$/, "" ); | ||
| n = n.replace( /\s+$/, "" ); | ||
| var i, pre, | ||
| str = "", | ||
| out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), | ||
| oSpace = o.match(/\s+/g), | ||
| nSpace = n.match(/\s+/g); | ||
| if ( oSpace == null ) { | ||
| oSpace = [ " " ]; | ||
| } | ||
| else { | ||
| oSpace.push( " " ); | ||
| } | ||
| if ( nSpace == null ) { | ||
| nSpace = [ " " ]; | ||
| } | ||
| else { | ||
| nSpace.push( " " ); | ||
| } | ||
| if ( out.n.length === 0 ) { | ||
| for ( i = 0; i < out.o.length; i++ ) { | ||
| str += "<del>" + out.o[i] + oSpace[i] + "</del>"; | ||
| } | ||
| } | ||
| else { | ||
| if ( out.n[0].text == null ) { | ||
| for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { | ||
| str += "<del>" + out.o[n] + oSpace[n] + "</del>"; | ||
| } | ||
| } | ||
| for ( i = 0; i < out.n.length; i++ ) { | ||
| if (out.n[i].text == null) { | ||
| str += "<ins>" + out.n[i] + nSpace[i] + "</ins>"; | ||
| } | ||
| else { | ||
| // `pre` initialized at top of scope | ||
| pre = ""; | ||
| for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { | ||
| pre += "<del>" + out.o[n] + oSpace[n] + "</del>"; | ||
| } | ||
| str += " " + out.n[i].text + nSpace[i] + pre; | ||
| } | ||
| } | ||
| } | ||
| return str; | ||
| }; | ||
| }()); | ||
| // for CommonJS enviroments, export everything | ||
| if ( typeof exports !== "undefined" ) { | ||
| extend(exports, QUnit); | ||
| } | ||
| // get at whatever the global object is, like window in browsers | ||
| }( (function() {return this;}.call()) )); |
+23
-13
@@ -1,2 +0,2 @@ | ||
| var QUnit = require('qunit/qunit/qunit'), | ||
| var QUnit = require('../support/qunit/qunit'), | ||
| path = require('path'), | ||
@@ -6,2 +6,8 @@ _ = require('underscore'), | ||
| // cycle.js: This file contains two functions, JSON.decycle and JSON.retrocycle, | ||
| // which make it possible to encode cyclical structures and dags in JSON, and to | ||
| // then recover them. JSONPath is used to represent the links. | ||
| // http://GOESSNER.net/articles/JsonPath/ | ||
| require('../support/json/cycle'); | ||
| var options = JSON.parse(process.argv[2]), | ||
@@ -21,11 +27,14 @@ currentModule = path.basename(options.code.path, '.js'), | ||
| */ | ||
| function load(res) { | ||
| var requirePath = res.path.replace(/\.js$/, ''); | ||
| function _require(res, addToGlobal) { | ||
| var exports = require(res.path.replace(/\.js$/, '')); | ||
| // test resource can define'namespace'to expose its exports as a named object | ||
| if (res.namespace) { | ||
| global[res.namespace] = require(requirePath); | ||
| } else { | ||
| _.extend(global, require(requirePath)); | ||
| if (addToGlobal) { | ||
| // resource can define 'namespace' to expose its exports as a named object | ||
| if (res.namespace) { | ||
| global[res.namespace] = exports; | ||
| } else { | ||
| _.extend(global, exports); | ||
| } | ||
| } | ||
| QUnit.start(); | ||
@@ -62,3 +71,3 @@ } | ||
| event: 'assertionDone', | ||
| data: data | ||
| data: JSON.decycle(data) | ||
| }); | ||
@@ -74,3 +83,2 @@ }); | ||
| data.module = data.module || currentModule; | ||
| process.send({ | ||
@@ -111,8 +119,10 @@ event: 'testDone', | ||
| // require deps | ||
| options.deps.forEach(load); | ||
| options.deps.forEach(_require, true); | ||
| // require code | ||
| load(options.code); | ||
| _require(options.code, true); | ||
| // require tests | ||
| options.tests.forEach(load); | ||
| options.tests.forEach(function(res) { | ||
| _require(res, false); | ||
| }); |
+4
-4
| { | ||
| "name": "qunit", | ||
| "description": "QUnit testing framework for nodejs", | ||
| "version": "0.5.3", | ||
| "version": "0.5.5", | ||
| "author": "Oleg Slobodskoi <oleg008@gmail.com>", | ||
@@ -24,7 +24,7 @@ "contributors": [ | ||
| "cli-table": "0.0.2", | ||
| "tracejs": "0.1.4", | ||
| "qunit": "https://github.com/jquery/qunit/tarball/v1.8.0" | ||
| "tracejs": "0.1.4" | ||
| }, | ||
| "devDependencies": { | ||
| "chainer": "0.0.5" | ||
| "chainer": "0.0.5", | ||
| "timekeeper": "0.0.2" | ||
| }, | ||
@@ -31,0 +31,0 @@ "optionalDependencies": { |
@@ -9,2 +9,2 @@ exports.myMethod = function() { | ||
| }, 100); | ||
| } | ||
| }; |
@@ -8,3 +8,5 @@ test('myMethod test', function() { | ||
| ok(true, 'myAsyncMethod started'); | ||
| stop(); | ||
| expect(3); | ||
@@ -16,2 +18,14 @@ myAsyncMethod(function(data) { | ||
| }); | ||
| }) | ||
| }) | ||
| test('circular reference', function() { | ||
| equal(global, global, 'test global'); | ||
| }); | ||
| test('use original Date', function() { | ||
| var timekeeper = require('timekeeper'); | ||
| timekeeper.travel(Date.now() - 1000000); | ||
| ok(true, 'date modified'); | ||
| }); |
@@ -15,3 +15,3 @@ var a = require('assert'), | ||
| // log expected and actual values for failed tests | ||
| //errors: true, | ||
| // errors: true, | ||
| // log tests overview | ||
@@ -40,7 +40,9 @@ // tests: true, | ||
| files: 1, | ||
| tests: 2, | ||
| assertions: 5, | ||
| tests: 4, | ||
| assertions: 7, | ||
| failed: 2, | ||
| passed: 3 | ||
| passed: 5 | ||
| }; | ||
| a.ok(res.runtime > 0, 'Date was modified'); | ||
| delete res.runtime; | ||
@@ -47,0 +49,0 @@ a.deepEqual(stat, res, 'base testrunner test'); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
HTTP dependency
Supply chain riskContains a dependency which resolves to a remote HTTP URL which could be used to inject untrusted code and reduce overall package reliability.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
94656
241.21%5
-16.67%21
10.53%2425
263.02%0
-100%2
100%15
114.29%5
66.67%