UNPKG

adder-script

Version:

Python like language to execute untrusted codes in browsers and Node.js.

1,027 lines 244 kB
��/*! * QUnit 2.0.0 * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * https://jquery.org/license * * Date: 2016-06-16T17:09Z */ ( function( global ) { var QUnit = {}; var Date = global.Date; var now = Date.now || function() { return new Date().getTime(); }; var setTimeout = global.setTimeout; var clearTimeout = global.clearTimeout; // Store a local window from the global to allow direct references. var window = global.window; var defined = { document: window && window.document !== undefined, setTimeout: setTimeout !== undefined, sessionStorage: ( function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch ( e ) { return false; } }() ) }; var fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ); var globalStartCalled = false; var runStarted = false; var autorun = false; var toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty; // 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; } // 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; } /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ function objectValues ( obj ) { var key, val, vals = QUnit.is( "array", obj ) ? [] : {}; for ( key in obj ) { if ( hasOwn.call( obj, key ) ) { val = obj[ key ]; vals[ key ] = val === Object( val ) ? objectValues( val ) : val; } } return vals; } function extend( a, b, undefOnly ) { for ( var prop in b ) { if ( hasOwn.call( b, prop ) ) { if ( b[ prop ] === undefined ) { delete a[ prop ]; } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { a[ prop ] = b[ prop ]; } } } return a; } function objectType( obj ) { if ( typeof obj === "undefined" ) { return "undefined"; } // Consider: typeof null === object if ( obj === null ) { return "null"; } var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), type = match && match[ 1 ]; switch ( type ) { case "Number": if ( isNaN( obj ) ) { return "nan"; } return "number"; case "String": case "Boolean": case "Array": case "Set": case "Map": case "Date": case "RegExp": case "Function": case "Symbol": return type.toLowerCase(); } if ( typeof obj === "object" ) { return "object"; } } // Safe object type checking function is( type, obj ) { return QUnit.objectType( obj ) === type; } // Doesn't support IE9, it will return undefined on these browsers // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset === undefined ? 4 : offset; var stack, include, i; if ( e.stack ) { 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 ]; } } function sourceFromStacktrace( offset ) { var error = new Error(); // Support: Safari <=7 only, IE <=10 - 11 only // Not all browsers generate the `stack` property for `new Error()`, see also #636 if ( !error.stack ) { try { throw error; } catch ( err ) { error = err; } } return extractStacktrace( error, offset ); } /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ var config = { // The queue of tests to run queue: [], // Block until document ready blocking: true, // 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, // HTML Reporter: collapse every test except the first failing test // If false, all failing tests will be expanded collapse: true, // By default, scroll to top of the page when suite is done scrolltop: true, // Depth up-to which object will be dumped maxDepth: 5, // When enabled, all tests must call expect() requireExpects: false, // Placeholder for user-configurable form-exposed URL parameters urlConfig: [], // Set of all modules. modules: [], // Stack of nested modules moduleStack: [], // The first unnamed module currentModule: { name: "", tests: [] }, callbacks: {} }; // Push a loose unnamed module to the modules collection config.modules.push( config.currentModule ); // Register logging callbacks function registerLoggingCallbacks( obj ) { var i, l, key, callbackNames = [ "begin", "done", "log", "testStart", "testDone", "moduleStart", "moduleDone" ]; function registerLoggingCallback( key ) { var loggingCallback = function( callback ) { if ( objectType( callback ) !== "function" ) { throw new Error( "QUnit logging methods require a callback function as their first parameters." ); } config.callbacks[ key ].push( callback ); }; return loggingCallback; } for ( i = 0, l = callbackNames.length; i < l; i++ ) { key = callbackNames[ i ]; // Initialize key collection of logging callback if ( objectType( config.callbacks[ key ] ) === "undefined" ) { config.callbacks[ key ] = []; } obj[ key ] = registerLoggingCallback( key ); } } function runLoggingCallbacks( key, args ) { var i, l, callbacks; callbacks = config.callbacks[ key ]; for ( i = 0, l = callbacks.length; i < l; i++ ) { callbacks[ i ]( args ); } } ( function() { if ( !defined.document ) { return; } // `onErrorFnPrev` initialized at top of scope // Preserve other handlers var onErrorFnPrev = window.onerror; // Cover uncaught exceptions // Returning true will suppress 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 suppressed. if ( ret !== true ) { if ( QUnit.config.current ) { if ( QUnit.config.current.ignoreGlobalErrors ) { return true; } QUnit.pushFailure( error, filePath + ":" + linerNr ); } else { QUnit.test( "global failure", extend( function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); }, { validTest: true } ) ); } return false; } return ret; }; }() ); // Figure out if we're running the tests from a server or not QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" ); // Expose the current QUnit version QUnit.version = "2.0.0"; extend( QUnit, { // Call on start of module test to prepend name to all tests module: function( name, testEnvironment, executeNow ) { var module, moduleFns; var currentModule = config.currentModule; if ( arguments.length === 2 ) { if ( objectType( testEnvironment ) === "function" ) { executeNow = testEnvironment; testEnvironment = undefined; } } module = createModule(); if ( testEnvironment && ( testEnvironment.setup || testEnvironment.teardown ) ) { console.warn( "Module's `setup` and `teardown` are not hooks anymore on QUnit 2.0, use " + "`beforeEach` and `afterEach` instead\n" + "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/" ); } moduleFns = { before: setHook( module, "before" ), beforeEach: setHook( module, "beforeEach" ), afterEach: setHook( module, "afterEach" ), after: setHook( module, "after" ) }; if ( objectType( executeNow ) === "function" ) { config.moduleStack.push( module ); setCurrentModule( module ); executeNow.call( module.testEnvironment, moduleFns ); config.moduleStack.pop(); module = module.parentModule || currentModule; } setCurrentModule( module ); function createModule() { var parentModule = config.moduleStack.length ? config.moduleStack.slice( -1 )[ 0 ] : null; var moduleName = parentModule !== null ? [ parentModule.name, name ].join( " > " ) : name; var module = { name: moduleName, parentModule: parentModule, tests: [], moduleId: generateHash( moduleName ), testsRun: 0 }; var env = {}; if ( parentModule ) { parentModule.childModule = module; extend( env, parentModule.testEnvironment ); delete env.beforeEach; delete env.afterEach; } extend( env, testEnvironment ); module.testEnvironment = env; config.modules.push( module ); return module; } function setCurrentModule( module ) { config.currentModule = module; } }, test: test, skip: skip, only: only, start: function( count ) { var globalStartAlreadyCalled = globalStartCalled; if ( !config.current ) { globalStartCalled = true; if ( runStarted ) { throw new Error( "Called start() while test already started running" ); } else if ( globalStartAlreadyCalled || count > 1 ) { throw new Error( "Called start() outside of a test context too many times" ); } else if ( config.autostart ) { throw new Error( "Called start() outside of a test context when " + "QUnit.config.autostart was true" ); } else if ( !config.pageLoaded ) { // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it config.autostart = true; return; } } else { throw new Error( "QUnit.start cannot be called inside a test context. This feature is removed in " + "QUnit 2.0. For async tests, use QUnit.test() with assert.async() instead.\n" + "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/" ); } resumeProcessing(); }, config: config, is: is, objectType: objectType, extend: extend, load: function() { config.pageLoaded = true; // Initialize the configuration options extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: 0, updateRate: 1000, autostart: true, filter: "" }, true ); config.blocking = false; if ( config.autostart ) { resumeProcessing(); } }, stack: function( offset ) { offset = ( offset || 0 ) + 2; return sourceFromStacktrace( offset ); } } ); registerLoggingCallbacks( QUnit ); function begin() { var i, l, modulesLog = []; // If the test run hasn't officially begun yet if ( !config.started ) { // Record the time of the test run's beginning config.started = now(); // Delete the loose unnamed module if unused. if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { config.modules.shift(); } // Avoid unnecessary information by not logging modules' test environments for ( i = 0, l = config.modules.length; i < l; i++ ) { modulesLog.push( { name: config.modules[ i ].name, tests: config.modules[ i ].tests } ); } // The test run is officially beginning now runLoggingCallbacks( "begin", { totalTests: Test.count, modules: modulesLog } ); } config.blocking = false; process( true ); } function process( last ) { function next() { process( last ); } var start = now(); config.depth = ( config.depth || 0 ) + 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) { if ( config.current ) { // Reset async tracking for each phase of the Test lifecycle config.current.usedAsync = false; } config.queue.shift()(); } else { setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function pauseProcessing( test ) { config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); config.timeout = setTimeout( function() { test.semaphore = 0; QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); resumeProcessing( test ); }, config.testTimeout ); } } function resumeProcessing( test ) { runStarted = true; // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) if ( defined.setTimeout ) { setTimeout( function() { var current = test || config.current; if ( current && ( current.semaphore > 0 || current.resumed ) ) { return; } if ( config.timeout ) { clearTimeout( config.timeout ); } if ( current ) { current.resumed = true; } begin(); }, 13 ); } else { begin(); } } function done() { var runtime, passed; autorun = true; // Log the last module results if ( config.previousModule ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule.name, tests: config.previousModule.tests, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started } ); } delete config.previousModule; runtime = now() - config.started; passed = config.stats.all - config.stats.bad; runLoggingCallbacks( "done", { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime } ); } function setHook( module, hookName ) { if ( module.testEnvironment === undefined ) { module.testEnvironment = {}; } return function( callback ) { module.testEnvironment[ hookName ] = callback; }; } var unitSampler, focused = false, priorityCount = 0; function Test( settings ) { var i, l; ++Test.count; this.expected = null; extend( this, settings ); this.assertions = []; this.semaphore = 0; this.usedAsync = false; this.module = config.currentModule; this.stack = sourceFromStacktrace( 3 ); // Register unique strings for ( i = 0, l = this.module.tests; i < l.length; i++ ) { if ( this.module.tests[ i ].name === this.testName ) { this.testName += " "; } } this.testId = generateHash( this.module.name, this.testName ); this.module.tests.push( { name: this.testName, testId: this.testId } ); if ( settings.skip ) { // Skipped tests will fully ignore any sent callback this.callback = function() {}; this.async = false; this.expected = 0; } else { this.assert = new Assert( this ); } } Test.count = 0; Test.prototype = { before: function() { if ( // Emit moduleStart when we're switching from one module to another this.module !== config.previousModule || // They could be equal (both undefined) but if the previousModule property doesn't // yet exist it means this is the first test in a suite that isn't wrapped in a // module, in which case we'll just emit a moduleStart event for 'undefined'. // Without this, reporters can get testStart before moduleStart which is a problem. !hasOwn.call( config, "previousModule" ) ) { if ( hasOwn.call( config, "previousModule" ) ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule.name, tests: config.previousModule.tests, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started } ); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0, started: now() }; runLoggingCallbacks( "moduleStart", { name: this.module.name, tests: this.module.tests } ); } config.current = this; if ( this.module.testEnvironment ) { delete this.module.testEnvironment.before; delete this.module.testEnvironment.beforeEach; delete this.module.testEnvironment.afterEach; delete this.module.testEnvironment.after; } this.testEnvironment = extend( {}, this.module.testEnvironment ); this.started = now(); runLoggingCallbacks( "testStart", { name: this.testName, module: this.module.name, testId: this.testId } ); if ( !config.pollution ) { saveGlobal(); } }, run: function() { var promise; config.current = this; if ( this.async ) { internalStop( this ); } this.callbackStarted = now(); if ( config.notrycatch ) { runTest( this ); return; } try { runTest( this ); } catch ( e ) { this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); // Else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { internalStart( this ); } } function runTest( test ) { promise = test.callback.call( test.testEnvironment, test.assert ); test.resolvePromise( promise ); } }, after: function() { checkPollution(); }, queueHook: function( hook, hookName, hookOwner ) { var promise, test = this; return function runHook() { if ( hookName === "before" ) { if ( hookOwner.testsRun !== 0 ) { return; } test.preserveEnvironment = true; } if ( hookName === "after" && hookOwner.testsRun !== numberOfTests( hookOwner ) - 1 ) { return; } config.current = test; if ( config.notrycatch ) { callHook(); return; } try { callHook(); } catch ( error ) { test.pushFailure( hookName + " failed on " + test.testName + ": " + ( error.message || error ), extractStacktrace( error, 0 ) ); } function callHook() { promise = hook.call( test.testEnvironment, test.assert ); test.resolvePromise( promise, hookName ); } }; }, // Currently only used for module level hooks, can be used to add global level ones hooks: function( handler ) { var hooks = []; function processHooks( test, module ) { if ( module.parentModule ) { processHooks( test, module.parentModule ); } if ( module.testEnvironment && QUnit.objectType( module.testEnvironment[ handler ] ) === "function" ) { hooks.push( test.queueHook( module.testEnvironment[ handler ], handler, module ) ); } } // Hooks are ignored on skipped tests if ( !this.skip ) { processHooks( this, this.module ); } return hooks; }, finish: function() { config.current = this; if ( config.requireExpects && this.expected === null ) { this.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 ) { this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); } else if ( this.expected === null && !this.assertions.length ) { this.pushFailure( "Expected at least one assertion, but none were run - call " + "expect(0) to accept zero assertions.", this.stack ); } var i, bad = 0; this.runtime = now() - this.started; config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[ i ].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } notifyTestsRan( this.module ); runLoggingCallbacks( "testDone", { name: this.testName, module: this.module.name, skipped: !!this.skip, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, runtime: this.runtime, // HTML Reporter use assertions: this.assertions, testId: this.testId, // Source of Test source: this.stack } ); config.current = undefined; }, preserveTestEnvironment: function() { if ( this.preserveEnvironment ) { this.module.testEnvironment = this.testEnvironment; this.testEnvironment = extend( {}, this.module.testEnvironment ); } }, queue: function() { var priority, test = this; if ( !this.valid() ) { return; } function run() { // Each of these can by async synchronize( [ function() { test.before(); }, test.hooks( "before" ), function() { test.preserveTestEnvironment(); }, test.hooks( "beforeEach" ), function() { test.run(); }, test.hooks( "afterEach" ).reverse(), test.hooks( "after" ).reverse(), function() { test.after(); }, function() { test.finish(); } ] ); } // Prioritize previously failed tests, detected from sessionStorage priority = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); return synchronize( run, priority, config.seed ); }, pushResult: function( resultInfo ) { // Destructure of resultInfo = { result, actual, expected, message, negative } var source, details = { module: this.module.name, name: this.testName, result: resultInfo.result, message: resultInfo.message, actual: resultInfo.actual, expected: resultInfo.expected, testId: this.testId, negative: resultInfo.negative || false, runtime: now() - this.started }; if ( !resultInfo.result ) { source = sourceFromStacktrace(); if ( source ) { details.source = source; } } runLoggingCallbacks( "log", details ); this.assertions.push( { result: !!resultInfo.result, message: resultInfo.message } ); }, pushFailure: function( message, source, actual ) { if ( !( this instanceof Test ) ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) ); } var details = { module: this.module.name, name: this.testName, result: false, message: message || "error", actual: actual || null, testId: this.testId, runtime: now() - this.started }; if ( source ) { details.source = source; } runLoggingCallbacks( "log", details ); this.assertions.push( { result: false, message: message } ); }, resolvePromise: function( promise, phase ) { var then, message, test = this; if ( promise != null ) { then = promise.then; if ( QUnit.objectType( then ) === "function" ) { internalStop( test ); then.call( promise, function() { internalStart( test ); }, function( error ) { message = "Promise rejected " + ( !phase ? "during" : phase.replace( /Each$/, "" ) ) + " " + test.testName + ": " + ( error.message || error ); test.pushFailure( message, extractStacktrace( error, 0 ) ); // Else next test will carry the responsibility saveGlobal(); // Unblock internalStart( test ); } ); } } }, valid: function() { var filter = config.filter, regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec( filter ), module = config.module && config.module.toLowerCase(), fullName = ( this.module.name + ": " + this.testName ); function moduleChainNameMatch( testModule ) { var testModuleName = testModule.name ? testModule.name.toLowerCase() : null; if ( testModuleName === module ) { return true; } else if ( testModule.parentModule ) { return moduleChainNameMatch( testModule.parentModule ); } else { return false; } } function moduleChainIdMatch( testModule ) { return inArray(