/** * @license * Copyright 2017 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ // We use the pattern below (as opposed to require('jasmine') to create the // jasmine module in order to avoid loading node specific modules which may // be ignored in browser environments but cannot be ignored in react-native // due to the pre-bundling of dependencies that it must do. // tslint:disable-next-line:no-require-imports const jasmineRequire = require('jasmine-core/lib/jasmine-core/jasmine.js'); const jasmineCore = jasmineRequire.core(jasmineRequire); import { KernelBackend } from './backends/backend'; import { ENGINE } from './engine'; import { env } from './environment'; import { purgeLocalStorageArtifacts } from './io/local_storage'; import { isPromise } from './util_base'; Error.stackTraceLimit = Infinity; jasmineCore.DEFAULT_TIMEOUT_INTERVAL = 20000; export const NODE_ENVS = { predicate: () => env().platformName === 'node' }; export const CHROME_ENVS = { flags: { 'IS_CHROME': true } }; export const BROWSER_ENVS = { predicate: () => env().platformName === 'browser' }; export const SYNC_BACKEND_ENVS = { predicate: (testEnv) => testEnv.isDataSync === true }; export const HAS_WORKER = { predicate: () => typeof (Worker) !== 'undefined' && typeof (Blob) !== 'undefined' && typeof (URL) !== 'undefined' }; export const HAS_NODE_WORKER = { predicate: () => { let hasWorker = true; try { require.resolve('worker_threads'); } catch (_a) { hasWorker = false; } return typeof (process) !== 'undefined' && hasWorker; } }; export const ALL_ENVS = {}; // Tests whether the current environment satisfies the set of constraints. export function envSatisfiesConstraints(env, testEnv, constraints) { if (constraints == null) { return true; } if (constraints.flags != null) { for (const flagName in constraints.flags) { const flagValue = constraints.flags[flagName]; if (env.get(flagName) !== flagValue) { return false; } } } if (constraints.predicate != null && !constraints.predicate(testEnv)) { return false; } return true; } /** * Add test filtering logic to Jasmine's specFilter hook. * * @param testFilters Used for include a test suite, with the ability * to selectively exclude some of the tests. * Either `include` or `startsWith` must exist for a `TestFilter`. * Tests that have the substrings specified by the include or startsWith * will be included in the test run, unless one of the substrings specified * by `excludes` appears in the name. * @param customInclude Function to programatically include a test. * If this function returns true, a test will immediately run. Otherwise, * `testFilters` is used for fine-grained filtering. * * If a test is not handled by `testFilters` or `customInclude`, the test will * be excluded in the test run. */ export function setupTestFilters(testFilters, customInclude) { const env = jasmine.getEnv(); // Account for --grep flag passed to karma by saving the existing specFilter. const config = env.configuration(); const grepFilter = config.specFilter; /** * Filter method that returns boolean, if a given test should run or be * ignored based on its name. The exclude list has priority over the * include list. Thus, if a test matches both the exclude and the include * list, it will be exluded. */ // tslint:disable-next-line: no-any const specFilter = (spec) => { // Filter out tests if the --grep flag is passed. if (!grepFilter(spec)) { return false; } const name = spec.getFullName(); if (customInclude(name)) { return true; } // Include tests of a test suite unless tests are in excludes list. for (let i = 0; i < testFilters.length; ++i) { const testFilter = testFilters[i]; if ((testFilter.include != null && name.indexOf(testFilter.include) > -1) || (testFilter.startsWith != null && name.startsWith(testFilter.startsWith))) { if (testFilter.excludes != null) { for (let j = 0; j < testFilter.excludes.length; j++) { if (name.indexOf(testFilter.excludes[j]) > -1) { return false; } } } return true; } } // Otherwise ignore the test. return false; }; env.configure(Object.assign(Object.assign({}, config), { specFilter })); } export function parseTestEnvFromKarmaFlags(args, registeredTestEnvs) { let flags; let testEnvName; args.forEach((arg, i) => { if (arg === '--flags') { flags = JSON.parse(args[i + 1]); } else if (arg === '--testEnv') { testEnvName = args[i + 1]; } }); const testEnvNames = registeredTestEnvs.map(env => env.name).join(', '); if (flags != null && testEnvName == null) { throw new Error('--testEnv flag is required when --flags is present. ' + `Available values are [${testEnvNames}].`); } if (testEnvName == null) { return null; } let testEnv; registeredTestEnvs.forEach(env => { if (env.name === testEnvName) { testEnv = env; } }); if (testEnv == null) { throw new Error(`Test environment with name ${testEnvName} not ` + `found. Available test environment names are ` + `${testEnvNames}`); } if (flags != null) { testEnv.flags = flags; } return testEnv; } export function describeWithFlags(name, constraints, tests) { if (TEST_ENVS.length === 0) { throw new Error(`Found no test environments. This is likely due to test environment ` + `registries never being imported or test environment registries ` + `being registered too late.`); } TEST_ENVS.forEach(testEnv => { env().setFlags(testEnv.flags); env().set('IS_TEST', true); if (envSatisfiesConstraints(env(), testEnv, constraints)) { const testName = name + ' ' + testEnv.name + ' ' + JSON.stringify(testEnv.flags || {}); executeTests(testName, tests, testEnv); } }); } export const TEST_ENVS = []; // Whether a call to setTestEnvs has been called so we turn off // registration. This allows command line overriding or programmatic // overriding of the default registrations. let testEnvSet = false; export function setTestEnvs(testEnvs) { testEnvSet = true; TEST_ENVS.length = 0; TEST_ENVS.push(...testEnvs); } export function registerTestEnv(testEnv) { // When using an explicit call to setTestEnvs, turn off registration of // test environments because the explicit call will set the test // environments. if (testEnvSet) { return; } TEST_ENVS.push(testEnv); } function executeTests(testName, tests, testEnv) { describe(testName, () => { beforeAll(async () => { ENGINE.reset(); if (testEnv.flags != null) { env().setFlags(testEnv.flags); } env().set('IS_TEST', true); // Await setting the new backend since it can have async init. await ENGINE.setBackend(testEnv.backendName); }); beforeEach(() => { ENGINE.startScope(); }); afterEach(() => { ENGINE.endScope(); ENGINE.disposeVariables(); }); afterAll(() => { ENGINE.reset(); }); tests(testEnv); }); } export class TestKernelBackend extends KernelBackend { dispose() { } } let lock = Promise.resolve(); /** * Wraps a Jasmine spec's test function so it is run exclusively to others that * use runWithLock. * * @param spec The function that runs the spec. Must return a promise or call * `done()`. * */ export function runWithLock(spec) { return () => { lock = lock.then(async () => { let done; const donePromise = new Promise((resolve, reject) => { done = (() => { resolve(); }); done.fail = (message) => { reject(message); }; }); purgeLocalStorageArtifacts(); const result = spec(done); if (isPromise(result)) { await result; } else { await donePromise; } }); return lock; }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiamFzbWluZV91dGlsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdGZqcy1jb3JlL3NyYy9qYXNtaW5lX3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsMkVBQTJFO0FBQzNFLDJFQUEyRTtBQUMzRSwyRUFBMkU7QUFDM0UsMkRBQTJEO0FBQzNELDhDQUE4QztBQUM5QyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsMENBQTBDLENBQUMsQ0FBQztBQUMzRSxNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0FBQ3hELE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUNqRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sVUFBVSxDQUFDO0FBQ2hDLE9BQU8sRUFBQyxHQUFHLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBQ3RELE9BQU8sRUFBQywwQkFBMEIsRUFBQyxNQUFNLG9CQUFvQixDQUFDO0FBQzlELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFFdEMsS0FBSyxDQUFDLGVBQWUsR0FBRyxRQUFRLENBQUM7QUFDakMsV0FBVyxDQUFDLHdCQUF3QixHQUFHLEtBQUssQ0FBQztBQU83QyxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQWdCO0lBQ3BDLFNBQVMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLEtBQUssTUFBTTtDQUMvQyxDQUFDO0FBQ0YsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFnQjtJQUN0QyxLQUFLLEVBQUUsRUFBQyxXQUFXLEVBQUUsSUFBSSxFQUFDO0NBQzNCLENBQUM7QUFDRixNQUFNLENBQUMsTUFBTSxZQUFZLEdBQWdCO0lBQ3ZDLFNBQVMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLEtBQUssU0FBUztDQUNsRCxD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Q0FBQyxHQUFHLEVBQUU7b0JBQ0osT0FBTyxFQUFFLENBQUM7Z0JBQ1osQ0FBQyxDQUFXLENBQUM7Z0JBQ3BCLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxPQUFRLEVBQUUsRUFBRTtvQkFDdkIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNsQixDQUFDLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUVILDBCQUEwQixFQUFFLENBQUM7WUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTFCLElBQUksU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUNyQixNQUFNLE1BQU0sQ0FBQzthQUNkO2lCQUFNO2dCQUNMLE1BQU0sV0FBVyxDQUFDO2FBQ25CO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxNyBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbi8vIFdlIHVzZSB0aGUgcGF0dGVybiBiZWxvdyAoYXMgb3Bwb3NlZCB0byByZXF1aXJlKCdqYXNtaW5lJykgdG8gY3JlYXRlIHRoZVxuLy8gamFzbWluZSBtb2R1bGUgaW4gb3JkZXIgdG8gYXZvaWQgbG9hZGluZyBub2RlIHNwZWNpZmljIG1vZHVsZXMgd2hpY2ggbWF5XG4vLyBiZSBpZ25vcmVkIGluIGJyb3dzZXIgZW52aXJvbm1lbnRzIGJ1dCBjYW5ub3QgYmUgaWdub3JlZCBpbiByZWFjdC1uYXRpdmVcbi8vIGR1ZSB0byB0aGUgcHJlLWJ1bmRsaW5nIG9mIGRlcGVuZGVuY2llcyB0aGF0IGl0IG11c3QgZG8uXG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tcmVxdWlyZS1pbXBvcnRzXG5jb25zdCBqYXNtaW5lUmVxdWlyZSA9IHJlcXVpcmUoJ2phc21pbmUtY29yZS9saWIvamFzbWluZS1jb3JlL2phc21pbmUuanMnKTtcbmNvbnN0IGphc21pbmVDb3JlID0gamFzbWluZVJlcXVpcmUuY29yZShqYXNtaW5lUmVxdWlyZSk7XG5pbXBvcnQge0tlcm5lbEJhY2tlbmR9IGZyb20gJy4vYmFja2VuZHMvYmFja2VuZCc7XG5pbXBvcnQge0VOR0lORX0gZnJvbSAnLi9lbmdpbmUnO1xuaW1wb3J0IHtlbnYsIEVudmlyb25tZW50LCBGbGFnc30gZnJvbSAnLi9lbnZpcm9ubWVudCc7XG5pbXBvcnQge3B1cmdlTG9jYWxTdG9yYWdlQXJ0aWZhY3RzfSBmcm9tICcuL2lvL2xvY2FsX3N0b3JhZ2UnO1xuaW1wb3J0IHtpc1Byb21pc2V9IGZyb20gJy4vdXRpbF9iYXNlJztcblxuRXJyb3Iuc3RhY2tUcmFjZUxpbWl0ID0gSW5maW5pdHk7XG5qYXNtaW5lQ29yZS5ERUZBVUxUX1RJTUVPVVRfSU5URVJWQUwgPSAyMDAwMDtcblxuZXhwb3J0IHR5cGUgQ29uc3RyYWludHMgPSB7XG4gIGZsYWdzPzogRmxhZ3MsXG4gIHByZWRpY2F0ZT86ICh0ZXN0RW52OiBUZXN0RW52KSA9PiBib29sZWFuLFxufTtcblxuZXhwb3J0IGNvbnN0IE5PREVfRU5WUzogQ29uc3RyYWludHMgPSB7XG4gIHByZWRpY2F0ZTogKCkgPT4gZW52KCkucGxhdGZvcm1OYW1lID09PSAnbm9kZSdcbn07XG5leHBvcnQgY29uc3QgQ0hST01FX0VOVlM6IENvbnN0cmFpbnRzID0ge1xuICBmbGFnczogeydJU19DSFJPTUUnOiB0cnVlfVxufTtcbmV4cG9ydCBjb25zdCBCUk9XU0VSX0VOVlM6IENvbnN0cmFpbnRzID0ge1xuICBwcmVkaWNhdGU6ICgpID0+IGVudigpLnBsYXRmb3JtTmFtZSA9PT0gJ2Jyb3dzZXInXG59O1xuXG5leHBvcnQgY29uc3QgU1lOQ19CQUNLRU5EX0VOVlM6IENvbnN0cmFpbnRzID0ge1xuICBwcmVkaWNhdGU6ICh0ZXN0RW52OiBUZXN0RW52KSA9PiB0ZXN0RW52LmlzRGF0YVN5bmMgPT09IHRydWVcbn07XG5cbmV4cG9ydCBjb25zdCBIQVNfV09SS0VSID0ge1xuICBwcmVkaWNhdGU6ICgpID0+IHR5cGVvZiAoV29ya2VyKSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiAoQmxvYikgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiAoVVJMKSAhPT0gJ3VuZGVmaW5lZCdcbn07XG5cbmV4cG9ydCBjb25zdCBIQVNfTk9ERV9XT1JLRVIgPSB7XG4gIHByZWRpY2F0ZTogKCkgPT4ge1xuICAgIGxldCBoYXNXb3JrZXIgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICByZXF1aXJlLnJlc29sdmUoJ3dvcmtlcl90aHJlYWRzJyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBoYXNXb3JrZXIgPSBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHR5cGVvZiAocHJvY2VzcykgIT09ICd1bmRlZmluZWQnICYmIGhhc1dvcmtlcjtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IEFMTF9FTlZTOiBDb25zdHJhaW50cyA9IHt9O1xuXG4vLyBUZXN0cyB3aGV0aGVyIHRoZSBjdXJyZW50IGVudmlyb25tZW50IHNhdGlzZmllcyB0aGUgc2V0IG9mIGNvbnN0cmFpbnRzLlxuZXhwb3J0IGZ1bmN0aW9uIGVudlNhdGlzZmllc0NvbnN0cmFpbnRzKFxuICAgIGVudjogRW52aXJvbm1lbnQsIHRlc3RFbnY6IFRlc3RFbnYsIGNvbnN0cmFpbnRzOiBDb25zdHJhaW50cyk6IGJvb2xlYW4ge1xuICBpZiAoY29uc3RyYWludHMgPT0gbnVsbCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaWYgKGNvbnN0cmFpbnRzLmZsYWdzICE9IG51bGwpIHtcbiAgICBmb3IgKGNvbnN0IGZsYWdOYW1lIGluIGNvbnN0cmFpbnRzLmZsYWdzKSB7XG4gICAgICBjb25zdCBmbGFnVmFsdWUgPSBjb25zdHJhaW50cy5mbGFnc1tmbGFnTmFtZV07XG4gICAgICBpZiAoZW52LmdldChmbGFnTmFtZSkgIT09IGZsYWdWYWx1ZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGlmIChjb25zdHJhaW50cy5wcmVkaWNhdGUgIT0gbnVsbCAmJiAhY29uc3RyYWludHMucHJlZGljYXRlKHRlc3RFbnYpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRlc3RGaWx0ZXIge1xuICBpbmNsdWRlPzogc3RyaW5nO1xuICBzdGFydHNXaXRoPzogc3RyaW5nO1xuICBleGNsdWRlcz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEFkZCB0ZXN0IGZpbHRlcmluZyBsb2dpYyB0byBKYXNtaW5lJ3Mgc3BlY0ZpbHRlciBob29rLlxuICpcbiAqIEBwYXJhbSB0ZXN0RmlsdGVycyBVc2VkIGZvciBpbmNsdWRlIGEgdGVzdCBzdWl0ZSwgd2l0aCB0aGUgYWJpbGl0eVxuICogICAgIHRvIHNlbGVjdGl2ZWx5IGV4Y2x1ZGUgc29tZSBvZiB0aGUgdGVzdHMuXG4gKiAgICAgRWl0aGVyIGBpbmNsdWRlYCBvciBgc3RhcnRzV2l0aGAgbXVzdCBleGlzdCBmb3IgYSBgVGVzdEZpbHRlcmAuXG4gKiAgICAgVGVzdHMgdGhhdCBoYXZlIHRoZSBzdWJzdHJpbmdzIHNwZWNpZmllZCBieSB0aGUgaW5jbHVkZSBvciBzdGFydHNXaXRoXG4gKiAgICAgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgdGVzdCBydW4sIHVubGVzcyBvbmUgb2YgdGhlIHN1YnN0cmluZ3Mgc3BlY2lmaWVkXG4gKiAgICAgYnkgYGV4Y2x1ZGVzYCBhcHBlYXJzIGluIHRoZSBuYW1lLlxuICogQHBhcmFtIGN1c3RvbUluY2x1ZGUgRnVuY3Rpb24gdG8gcHJvZ3JhbWF0aWNhbGx5IGluY2x1ZGUgYSB0ZXN0LlxuICogICAgIElmIHRoaXMgZnVuY3Rpb24gcmV0dXJucyB0cnVlLCBhIHRlc3Qgd2lsbCBpbW1lZGlhdGVseSBydW4uIE90aGVyd2lzZSxcbiAqICAgICBgdGVzdEZpbHRlcnNgIGlzIHVzZWQgZm9yIGZpbmUtZ3JhaW5lZCBmaWx0ZXJpbmcuXG4gKlxuICogSWYgYSB0ZXN0IGlzIG5vdCBoYW5kbGVkIGJ5IGB0ZXN0RmlsdGVyc2Agb3IgYGN1c3RvbUluY2x1ZGVgLCB0aGUgdGVzdCB3aWxsXG4gKiBiZSBleGNsdWRlZCBpbiB0aGUgdGVzdCBydW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cFRlc3RGaWx0ZXJzKFxuICAgIHRlc3RGaWx0ZXJzOiBUZXN0RmlsdGVyW10sIGN1c3RvbUluY2x1ZGU6IChuYW1lOiBzdHJpbmcpID0+IGJvb2xlYW4pIHtcbiAgY29uc3QgZW52ID0gamFzbWluZS5nZXRFbnYoKTtcblxuICAvLyBBY2NvdW50IGZvciAtLWdyZXAgZmxhZyBwYXNzZWQgdG8ga2FybWEgYnkgc2F2aW5nIHRoZSBleGlzdGluZyBzcGVjRmlsdGVyLlxuICBjb25zdCBjb25maWcgPSBlbnYuY29uZmlndXJhdGlvbigpO1xuICBjb25zdCBncmVwRmlsdGVyID0gY29uZmlnLnNwZWNGaWx0ZXI7XG5cbiAgLyoqXG4gICAqIEZpbHRlciBtZXRob2QgdGhhdCByZXR1cm5zIGJvb2xlYW4sIGlmIGEgZ2l2ZW4gdGVzdCBzaG91bGQgcnVuIG9yIGJlXG4gICAqIGlnbm9yZWQgYmFzZWQgb24gaXRzIG5hbWUuIFRoZSBleGNsdWRlIGxpc3QgaGFzIHByaW9yaXR5IG92ZXIgdGhlXG4gICAqIGluY2x1ZGUgbGlzdC4gVGh1cywgaWYgYSB0ZXN0IG1hdGNoZXMgYm90aCB0aGUgZXhjbHVkZSBhbmQgdGhlIGluY2x1ZGVcbiAgICogbGlzdCwgaXQgd2lsbCBiZSBleGx1ZGVkLlxuICAgKi9cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby1hbnlcbiAgY29uc3Qgc3BlY0ZpbHRlciA9IChzcGVjOiBhbnkpID0+IHtcbiAgICAvLyBGaWx0ZXIgb3V0IHRlc3RzIGlmIHRoZSAtLWdyZXAgZmxhZyBpcyBwYXNzZWQuXG4gICAgaWYgKCFncmVwRmlsdGVyKHNwZWMpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgY29uc3QgbmFtZSA9IHNwZWMuZ2V0RnVsbE5hbWUoKTtcblxuICAgIGlmIChjdXN0b21JbmNsdWRlKG5hbWUpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBJbmNsdWRlIHRlc3RzIG9mIGEgdGVzdCBzdWl0ZSB1bmxlc3MgdGVzdHMgYXJlIGluIGV4Y2x1ZGVzIGxpc3QuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0ZXN0RmlsdGVycy5sZW5ndGg7ICsraSkge1xuICAgICAgY29uc3QgdGVzdEZpbHRlciA9IHRlc3RGaWx0ZXJzW2ldO1xuICAgICAgaWYgKCh0ZXN0RmlsdGVyLmluY2x1ZGUgIT0gbnVsbCAmJlxuICAgICAgICAgICBuYW1lLmluZGV4T2YodGVzdEZpbHRlci5pbmNsdWRlKSA+IC0xKSB8fFxuICAgICAgICAgICh0ZXN0RmlsdGVyLnN0YXJ0c1dpdGggIT0gbnVsbCAmJlxuICAgICAgICAgICBuYW1lLnN0YXJ0c1dpdGgodGVzdEZpbHRlci5zdGFydHNXaXRoKSkpIHtcbiAgICAgICAgaWYgKHRlc3RGaWx0ZXIuZXhjbHVkZXMgIT0gbnVsbCkge1xuICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGVzdEZpbHRlci5leGNsdWRlcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgaWYgKG5hbWUuaW5kZXhPZih0ZXN0RmlsdGVyLmV4Y2x1ZGVzW2pdKSA+IC0xKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gT3RoZXJ3aXNlIGlnbm9yZSB0aGUgdGVzdC5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH07XG5cbiAgZW52LmNvbmZpZ3VyZSh7Li4uY29uZmlnLCBzcGVjRmlsdGVyfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVRlc3RFbnZGcm9tS2FybWFGbGFncyhcbiAgICBhcmdzOiBzdHJpbmdbXSwgcmVnaXN0ZXJlZFRlc3RFbnZzOiBUZXN0RW52W10pOiBUZXN0RW52IHtcbiAgbGV0IGZsYWdzOiBGbGFncztcbiAgbGV0IHRlc3RFbnZOYW1lOiBzdHJpbmc7XG5cbiAgYXJncy5mb3JFYWNoKChhcmcsIGkpID0+IHtcbiAgICBpZiAoYXJnID09PSAnLS1mbGFncycpIHtcbiAgICAgIGZsYWdzID0gSlNPTi5wYXJzZShhcmdzW2kgKyAxXSk7XG4gICAgfSBlbHNlIGlmIChhcmcgPT09ICctLXRlc3RFbnYnKSB7XG4gICAgICB0ZXN0RW52TmFtZSA9IGFyZ3NbaSArIDFdO1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVzdEVudk5hbWVzID0gcmVnaXN0ZXJlZFRlc3RFbnZzLm1hcChlbnYgPT4gZW52Lm5hbWUpLmpvaW4oJywgJyk7XG4gIGlmIChmbGFncyAhPSBudWxsICYmIHRlc3RFbnZOYW1lID09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICctLXRlc3RFbnYgZmxhZyBpcyByZXF1aXJlZCB3aGVuIC0tZmxhZ3MgaXMgcHJlc2VudC4gJyArXG4gICAgICAgIGBBdmFpbGFibGUgdmFsdWVzIGFyZSBbJHt0ZXN0RW52TmFtZXN9XS5gKTtcbiAgfVxuICBpZiAodGVzdEVudk5hbWUgPT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgbGV0IHRlc3RFbnY6IFRlc3RFbnY7XG4gIHJlZ2lzdGVyZWRUZXN0RW52cy5mb3JFYWNoKGVudiA9PiB7XG4gICAgaWYgKGVudi5uYW1lID09PSB0ZXN0RW52TmFtZSkge1xuICAgICAgdGVzdEVudiA9IGVudjtcbiAgICB9XG4gIH0pO1xuICBpZiAodGVzdEVudiA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgVGVzdCBlbnZpcm9ubWVudCB3aXRoIG5hbWUgJHt0ZXN0RW52TmFtZX0gbm90IGAgK1xuICAgICAgICBgZm91bmQuIEF2YWlsYWJsZSB0ZXN0IGVudmlyb25tZW50IG5hbWVzIGFyZSBgICtcbiAgICAgICAgYCR7dGVzdEVudk5hbWVzfWApO1xuICB9XG4gIGlmIChmbGFncyAhPSBudWxsKSB7XG4gICAgdGVzdEVudi5mbGFncyA9IGZsYWdzO1xuICB9XG5cbiAgcmV0dXJuIHRlc3RFbnY7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXNjcmliZVdpdGhGbGFncyhcbiAgICBuYW1lOiBzdHJpbmcsIGNvbnN0cmFpbnRzOiBDb25zdHJhaW50cywgdGVzdHM6IChlbnY6IFRlc3RFbnYpID0+IHZvaWQpIHtcbiAgaWYgKFRFU1RfRU5WUy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBGb3VuZCBubyB0ZXN0IGVudmlyb25tZW50cy4gVGhpcyBpcyBsaWtlbHkgZHVlIHRvIHRlc3QgZW52aXJvbm1lbnQgYCArXG4gICAgICAgIGByZWdpc3RyaWVzIG5ldmVyIGJlaW5nIGltcG9ydGVkIG9yIHRlc3QgZW52aXJvbm1lbnQgcmVnaXN0cmllcyBgICtcbiAgICAgICAgYGJlaW5nIHJlZ2lzdGVyZWQgdG9vIGxhdGUuYCk7XG4gIH1cblxuICBURVNUX0VOVlMuZm9yRWFjaCh0ZXN0RW52ID0+IHtcbiAgICBlbnYoKS5zZXRGbGFncyh0ZXN0RW52LmZsYWdzKTtcbiAgICBlbnYoKS5zZXQoJ0lTX1RFU1QnLCB0cnVlKTtcbiAgICBpZiAoZW52U2F0aXNmaWVzQ29uc3RyYWludHMoZW52KCksIHRlc3RFbnYsIGNvbnN0cmFpbnRzKSkge1xuICAgICAgY29uc3QgdGVzdE5hbWUgPVxuICAgICAgICAgIG5hbWUgKyAnICcgKyB0ZXN0RW52Lm5hbWUgKyAnICcgKyBKU09OLnN0cmluZ2lmeSh0ZXN0RW52LmZsYWdzIHx8IHt9KTtcbiAgICAgIGV4ZWN1dGVUZXN0cyh0ZXN0TmFtZSwgdGVzdHMsIHRlc3RFbnYpO1xuICAgIH1cbiAgfSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdEVudiB7XG4gIG5hbWU6IHN0cmluZztcbiAgYmFja2VuZE5hbWU6IHN0cmluZztcbiAgZmxhZ3M/OiBGbGFncztcbiAgaXNEYXRhU3luYz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjb25zdCBURVNUX0VOVlM6IFRlc3RFbnZbXSA9IFtdO1xuXG4vLyBXaGV0aGVyIGEgY2FsbCB0byBzZXRUZXN0RW52cyBoYXMgYmVlbiBjYWxsZWQgc28gd2UgdHVybiBvZmZcbi8vIHJlZ2lzdHJhdGlvbi4gVGhpcyBhbGxvd3MgY29tbWFuZCBsaW5lIG92ZXJyaWRpbmcgb3IgcHJvZ3JhbW1hdGljXG4vLyBvdmVycmlkaW5nIG9mIHRoZSBkZWZhdWx0IHJlZ2lzdHJhdGlvbnMuXG5sZXQgdGVzdEVudlNldCA9IGZhbHNlO1xuZXhwb3J0IGZ1bmN0aW9uIHNldFRlc3RFbnZzKHRlc3RFbnZzOiBUZXN0RW52W10pIHtcbiAgdGVzdEVudlNldCA9IHRydWU7XG4gIFRFU1RfRU5WUy5sZW5ndGggPSAwO1xuICBURVNUX0VOVlMucHVzaCguLi50ZXN0RW52cyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlclRlc3RFbnYodGVzdEVudjogVGVzdEVudikge1xuICAvLyBXaGVuIHVzaW5nIGFuIGV4cGxpY2l0IGNhbGwgdG8gc2V0VGVzdEVudnMsIHR1cm4gb2ZmIHJlZ2lzdHJhdGlvbiBvZlxuICAvLyB0ZXN0IGVudmlyb25tZW50cyBiZWNhdXNlIHRoZSBleHBsaWNpdCBjYWxsIHdpbGwgc2V0IHRoZSB0ZXN0XG4gIC8vIGVudmlyb25tZW50cy5cbiAgaWYgKHRlc3RFbnZTZXQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgVEVTVF9FTlZTLnB1c2godGVzdEVudik7XG59XG5cbmZ1bmN0aW9uIGV4ZWN1dGVUZXN0cyhcbiAgICB0ZXN0TmFtZTogc3RyaW5nLCB0ZXN0czogKGVudjogVGVzdEVudikgPT4gdm9pZCwgdGVzdEVudjogVGVzdEVudikge1xuICBkZXNjcmliZSh0ZXN0TmFtZSwgKCkgPT4ge1xuICAgIGJlZm9yZUFsbChhc3luYyAoKSA9PiB7XG4gICAgICBFTkdJTkUucmVzZXQoKTtcbiAgICAgIGlmICh0ZXN0RW52LmZsYWdzICE9IG51bGwpIHtcbiAgICAgICAgZW52KCkuc2V0RmxhZ3ModGVzdEVudi5mbGFncyk7XG4gICAgICB9XG4gICAgICBlbnYoKS5zZXQoJ0lTX1RFU1QnLCB0cnVlKTtcbiAgICAgIC8vIEF3YWl0IHNldHRpbmcgdGhlIG5ldyBiYWNrZW5kIHNpbmNlIGl0IGNhbiBoYXZlIGFzeW5jIGluaXQuXG4gICAgICBhd2FpdCBFTkdJTkUuc2V0QmFja2VuZCh0ZXN0RW52LmJhY2tlbmROYW1lKTtcbiAgICB9KTtcblxuICAgIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgICAgRU5HSU5FLnN0YXJ0U2NvcGUoKTtcbiAgICB9KTtcblxuICAgIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgICBFTkdJTkUuZW5kU2NvcGUoKTtcbiAgICAgIEVOR0lORS5kaXNwb3NlVmFyaWFibGVzKCk7XG4gICAgfSk7XG5cbiAgICBhZnRlckFsbCgoKSA9PiB7XG4gICAgICBFTkdJTkUucmVzZXQoKTtcbiAgICB9KTtcblxuICAgIHRlc3RzKHRlc3RFbnYpO1xuICB9KTtcbn1cblxuZXhwb3J0IGNsYXNzIFRlc3RLZXJuZWxCYWNrZW5kIGV4dGVuZHMgS2VybmVsQmFja2VuZCB7XG4gIG92ZXJyaWRlIGRpc3Bvc2UoKTogdm9pZCB7fVxufVxuXG5sZXQgbG9jayA9IFByb21pc2UucmVzb2x2ZSgpO1xuXG4vKipcbiAqIFdyYXBzIGEgSmFzbWluZSBzcGVjJ3MgdGVzdCBmdW5jdGlvbiBzbyBpdCBpcyBydW4gZXhjbHVzaXZlbHkgdG8gb3RoZXJzIHRoYXRcbiAqIHVzZSBydW5XaXRoTG9jay5cbiAqXG4gKiBAcGFyYW0gc3BlYyBUaGUgZnVuY3Rpb24gdGhhdCBydW5zIHRoZSBzcGVjLiBNdXN0IHJldHVybiBhIHByb21pc2Ugb3IgY2FsbFxuICogICAgIGBkb25lKClgLlxuICpcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1bldpdGhMb2NrKHNwZWM6IChkb25lPzogRG9uZUZuKSA9PiBQcm9taXNlPHZvaWQ+fCB2b2lkKSB7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgbG9jayA9IGxvY2sudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICBsZXQgZG9uZTogRG9uZUZuO1xuICAgICAgY29uc3QgZG9uZVByb21pc2UgPSBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGRvbmUgPSAoKCkgPT4ge1xuICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICB9KSBhcyBEb25lRm47XG4gICAgICAgIGRvbmUuZmFpbCA9IChtZXNzYWdlPykgPT4ge1xuICAgICAgICAgIHJlamVjdChtZXNzYWdlKTtcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuXG4gICAgICBwdXJnZUxvY2FsU3RvcmFnZUFydGlmYWN0cygpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gc3BlYyhkb25lKTtcblxuICAgICAgaWYgKGlzUHJvbWlzZShyZXN1bHQpKSB7XG4gICAgICAgIGF3YWl0IHJlc3VsdDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IGRvbmVQcm9taXNlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBsb2NrO1xuICB9O1xufVxuIl19