UNPKG

@tensorflow/tfjs-core

Version:

Hardware-accelerated JavaScript library for machine intelligence

266 lines 31.6 kB
/** * @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 programmatically 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 excluded. */ // 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+IHR5cGVvZiAoV29ya2VyKSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiAoQmxvYikgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiAoVVJMKSAhPT0gJ3VuZGVmaW5lZCdcbn07XG5cbmV4cG9ydCBjb25zdCBIQVNfTk9ERV9XT1JLRVIgPSB7XG4gIHByZWRpY2F0ZTogKCkgPT4ge1xuICAgIGxldCBoYXNXb3JrZXIgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICByZXF1aXJlLnJlc29sdmUoJ3dvcmtlcl90aHJlYWRzJyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBoYXNXb3JrZXIgPSBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHR5cGVvZiAocHJvY2VzcykgIT09ICd1bmRlZmluZWQnICYmIGhhc1dvcmtlcjtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IEFMTF9FTlZTOiBDb25zdHJhaW50cyA9IHt9O1xuXG4vLyBUZXN0cyB3aGV0aGVyIHRoZSBjdXJyZW50IGVudmlyb25tZW50IHNhdGlzZmllcyB0aGUgc2V0IG9mIGNvbnN0cmFpbnRzLlxuZXhwb3J0IGZ1bmN0aW9uIGVudlNhdGlzZmllc0NvbnN0cmFpbnRzKFxuICAgIGVudjogRW52aXJvbm1lbnQsIHRlc3RFbnY6IFRlc3RFbnYsIGNvbnN0cmFpbnRzOiBDb25zdHJhaW50cyk6IGJvb2xlYW4ge1xuICBpZiAoY29uc3RyYWludHMgPT0gbnVsbCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaWYgKGNvbnN0cmFpbnRzLmZsYWdzICE9IG51bGwpIHtcbiAgICBmb3IgKGNvbnN0IGZsYWdOYW1lIGluIGNvbnN0cmFpbnRzLmZsYWdzKSB7XG4gICAgICBjb25zdCBmbGFnVmFsdWUgPSBjb25zdHJhaW50cy5mbGFnc1tmbGFnTmFtZV07XG4gICAgICBpZiAoZW52LmdldChmbGFnTmFtZSkgIT09IGZsYWdWYWx1ZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGlmIChjb25zdHJhaW50cy5wcmVkaWNhdGUgIT0gbnVsbCAmJiAhY29uc3RyYWludHMucHJlZGljYXRlKHRlc3RFbnYpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRlc3RGaWx0ZXIge1xuICBpbmNsdWRlPzogc3RyaW5nO1xuICBzdGFydHNXaXRoPzogc3RyaW5nO1xuICBleGNsdWRlcz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEFkZCB0ZXN0IGZpbHRlcmluZyBsb2dpYyB0byBKYXNtaW5lJ3Mgc3BlY0ZpbHRlciBob29rLlxuICpcbiAqIEBwYXJhbSB0ZXN0RmlsdGVycyBVc2VkIGZvciBpbmNsdWRlIGEgdGVzdCBzdWl0ZSwgd2l0aCB0aGUgYWJpbGl0eVxuICogICAgIHRvIHNlbGVjdGl2ZWx5IGV4Y2x1ZGUgc29tZSBvZiB0aGUgdGVzdHMuXG4gKiAgICAgRWl0aGVyIGBpbmNsdWRlYCBvciBgc3RhcnRzV2l0aGAgbXVzdCBleGlzdCBmb3IgYSBgVGVzdEZpbHRlcmAuXG4gKiAgICAgVGVzdHMgdGhhdCBoYXZlIHRoZSBzdWJzdHJpbmdzIHNwZWNpZmllZCBieSB0aGUgaW5jbHVkZSBvciBzdGFydHNXaXRoXG4gKiAgICAgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgdGVzdCBydW4sIHVubGVzcyBvbmUgb2YgdGhlIHN1YnN0cmluZ3Mgc3BlY2lmaWVkXG4gKiAgICAgYnkgYGV4Y2x1ZGVzYCBhcHBlYXJzIGluIHRoZSBuYW1lLlxuICogQHBhcmFtIGN1c3RvbUluY2x1ZGUgRnVuY3Rpb24gdG8gcHJvZ3JhbW1hdGljYWxseSBpbmNsdWRlIGEgdGVzdC5cbiAqICAgICBJZiB0aGlzIGZ1bmN0aW9uIHJldHVybnMgdHJ1ZSwgYSB0ZXN0IHdpbGwgaW1tZWRpYXRlbHkgcnVuLiBPdGhlcndpc2UsXG4gKiAgICAgYHRlc3RGaWx0ZXJzYCBpcyB1c2VkIGZvciBmaW5lLWdyYWluZWQgZmlsdGVyaW5nLlxuICpcbiAqIElmIGEgdGVzdCBpcyBub3QgaGFuZGxlZCBieSBgdGVzdEZpbHRlcnNgIG9yIGBjdXN0b21JbmNsdWRlYCwgdGhlIHRlc3Qgd2lsbFxuICogYmUgZXhjbHVkZWQgaW4gdGhlIHRlc3QgcnVuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBUZXN0RmlsdGVycyhcbiAgICB0ZXN0RmlsdGVyczogVGVzdEZpbHRlcltdLCBjdXN0b21JbmNsdWRlOiAobmFtZTogc3RyaW5nKSA9PiBib29sZWFuKSB7XG4gIGNvbnN0IGVudiA9IGphc21pbmUuZ2V0RW52KCk7XG5cbiAgLy8gQWNjb3VudCBmb3IgLS1ncmVwIGZsYWcgcGFzc2VkIHRvIGthcm1hIGJ5IHNhdmluZyB0aGUgZXhpc3Rpbmcgc3BlY0ZpbHRlci5cbiAgY29uc3QgY29uZmlnID0gZW52LmNvbmZpZ3VyYXRpb24oKTtcbiAgY29uc3QgZ3JlcEZpbHRlciA9IGNvbmZpZy5zcGVjRmlsdGVyO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgbWV0aG9kIHRoYXQgcmV0dXJucyBib29sZWFuLCBpZiBhIGdpdmVuIHRlc3Qgc2hvdWxkIHJ1biBvciBiZVxuICAgKiBpZ25vcmVkIGJhc2VkIG9uIGl0cyBuYW1lLiBUaGUgZXhjbHVkZSBsaXN0IGhhcyBwcmlvcml0eSBvdmVyIHRoZVxuICAgKiBpbmNsdWRlIGxpc3QuIFRodXMsIGlmIGEgdGVzdCBtYXRjaGVzIGJvdGggdGhlIGV4Y2x1ZGUgYW5kIHRoZSBpbmNsdWRlXG4gICAqIGxpc3QsIGl0IHdpbGwgYmUgZXhjbHVkZWQuXG4gICAqL1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6IG5vLWFueVxuICBjb25zdCBzcGVjRmlsdGVyID0gKHNwZWM6IGFueSkgPT4ge1xuICAgIC8vIEZpbHRlciBvdXQgdGVzdHMgaWYgdGhlIC0tZ3JlcCBmbGFnIGlzIHBhc3NlZC5cbiAgICBpZiAoIWdyZXBGaWx0ZXIoc3BlYykpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBuYW1lID0gc3BlYy5nZXRGdWxsTmFtZSgpO1xuXG4gICAgaWYgKGN1c3RvbUluY2x1ZGUobmFtZSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIEluY2x1ZGUgdGVzdHMgb2YgYSB0ZXN0IHN1aXRlIHVubGVzcyB0ZXN0cyBhcmUgaW4gZXhjbHVkZXMgbGlzdC5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRlc3RGaWx0ZXJzLmxlbmd0aDsgKytpKSB7XG4gICAgICBjb25zdCB0ZXN0RmlsdGVyID0gdGVzdEZpbHRlcnNbaV07XG4gICAgICBpZiAoKHRlc3RGaWx0ZXIuaW5jbHVkZSAhPSBudWxsICYmXG4gICAgICAgICAgIG5hbWUuaW5kZXhPZih0ZXN0RmlsdGVyLmluY2x1ZGUpID4gLTEpIHx8XG4gICAgICAgICAgKHRlc3RGaWx0ZXIuc3RhcnRzV2l0aCAhPSBudWxsICYmXG4gICAgICAgICAgIG5hbWUuc3RhcnRzV2l0aCh0ZXN0RmlsdGVyLnN0YXJ0c1dpdGgpKSkge1xuICAgICAgICBpZiAodGVzdEZpbHRlci5leGNsdWRlcyAhPSBudWxsKSB7XG4gICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0ZXN0RmlsdGVyLmV4Y2x1ZGVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBpZiAobmFtZS5pbmRleE9mKHRlc3RGaWx0ZXIuZXhjbHVkZXNbal0pID4gLTEpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBPdGhlcndpc2UgaWdub3JlIHRoZSB0ZXN0LlxuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcblxuICBlbnYuY29uZmlndXJlKHsuLi5jb25maWcsIHNwZWNGaWx0ZXJ9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVGVzdEVudkZyb21LYXJtYUZsYWdzKFxuICAgIGFyZ3M6IHN0cmluZ1tdLCByZWdpc3RlcmVkVGVzdEVudnM6IFRlc3RFbnZbXSk6IFRlc3RFbnYge1xuICBsZXQgZmxhZ3M6IEZsYWdzO1xuICBsZXQgdGVzdEVudk5hbWU6IHN0cmluZztcblxuICBhcmdzLmZvckVhY2goKGFyZywgaSkgPT4ge1xuICAgIGlmIChhcmcgPT09ICctLWZsYWdzJykge1xuICAgICAgZmxhZ3MgPSBKU09OLnBhcnNlKGFyZ3NbaSArIDFdKTtcbiAgICB9IGVsc2UgaWYgKGFyZyA9PT0gJy0tdGVzdEVudicpIHtcbiAgICAgIHRlc3RFbnZOYW1lID0gYXJnc1tpICsgMV07XG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZXN0RW52TmFtZXMgPSByZWdpc3RlcmVkVGVzdEVudnMubWFwKGVudiA9PiBlbnYubmFtZSkuam9pbignLCAnKTtcbiAgaWYgKGZsYWdzICE9IG51bGwgJiYgdGVzdEVudk5hbWUgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJy0tdGVzdEVudiBmbGFnIGlzIHJlcXVpcmVkIHdoZW4gLS1mbGFncyBpcyBwcmVzZW50LiAnICtcbiAgICAgICAgYEF2YWlsYWJsZSB2YWx1ZXMgYXJlIFske3Rlc3RFbnZOYW1lc31dLmApO1xuICB9XG4gIGlmICh0ZXN0RW52TmFtZSA9PSBudWxsKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBsZXQgdGVzdEVudjogVGVzdEVudjtcbiAgcmVnaXN0ZXJlZFRlc3RFbnZzLmZvckVhY2goZW52ID0+IHtcbiAgICBpZiAoZW52Lm5hbWUgPT09IHRlc3RFbnZOYW1lKSB7XG4gICAgICB0ZXN0RW52ID0gZW52O1xuICAgIH1cbiAgfSk7XG4gIGlmICh0ZXN0RW52ID09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBUZXN0IGVudmlyb25tZW50IHdpdGggbmFtZSAke3Rlc3RFbnZOYW1lfSBub3QgYCArXG4gICAgICAgIGBmb3VuZC4gQXZhaWxhYmxlIHRlc3QgZW52aXJvbm1lbnQgbmFtZXMgYXJlIGAgK1xuICAgICAgICBgJHt0ZXN0RW52TmFtZXN9YCk7XG4gIH1cbiAgaWYgKGZsYWdzICE9IG51bGwpIHtcbiAgICB0ZXN0RW52LmZsYWdzID0gZmxhZ3M7XG4gIH1cblxuICByZXR1cm4gdGVzdEVudjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlc2NyaWJlV2l0aEZsYWdzKFxuICAgIG5hbWU6IHN0cmluZywgY29uc3RyYWludHM6IENvbnN0cmFpbnRzLCB0ZXN0czogKGVudjogVGVzdEVudikgPT4gdm9pZCkge1xuICBpZiAoVEVTVF9FTlZTLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZvdW5kIG5vIHRlc3QgZW52aXJvbm1lbnRzLiBUaGlzIGlzIGxpa2VseSBkdWUgdG8gdGVzdCBlbnZpcm9ubWVudCBgICtcbiAgICAgICAgYHJlZ2lzdHJpZXMgbmV2ZXIgYmVpbmcgaW1wb3J0ZWQgb3IgdGVzdCBlbnZpcm9ubWVudCByZWdpc3RyaWVzIGAgK1xuICAgICAgICBgYmVpbmcgcmVnaXN0ZXJlZCB0b28gbGF0ZS5gKTtcbiAgfVxuXG4gIFRFU1RfRU5WUy5mb3JFYWNoKHRlc3RFbnYgPT4ge1xuICAgIGVudigpLnNldEZsYWdzKHRlc3RFbnYuZmxhZ3MpO1xuICAgIGVudigpLnNldCgnSVNfVEVTVCcsIHRydWUpO1xuICAgIGlmIChlbnZTYXRpc2ZpZXNDb25zdHJhaW50cyhlbnYoKSwgdGVzdEVudiwgY29uc3RyYWludHMpKSB7XG4gICAgICBjb25zdCB0ZXN0TmFtZSA9XG4gICAgICAgICAgbmFtZSArICcgJyArIHRlc3RFbnYubmFtZSArICcgJyArIEpTT04uc3RyaW5naWZ5KHRlc3RFbnYuZmxhZ3MgfHwge30pO1xuICAgICAgZXhlY3V0ZVRlc3RzKHRlc3ROYW1lLCB0ZXN0cywgdGVzdEVudik7XG4gICAgfVxuICB9KTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUZXN0RW52IHtcbiAgbmFtZTogc3RyaW5nO1xuICBiYWNrZW5kTmFtZTogc3RyaW5nO1xuICBmbGFncz86IEZsYWdzO1xuICBpc0RhdGFTeW5jPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNvbnN0IFRFU1RfRU5WUzogVGVzdEVudltdID0gW107XG5cbi8vIFdoZXRoZXIgYSBjYWxsIHRvIHNldFRlc3RFbnZzIGhhcyBiZWVuIGNhbGxlZCBzbyB3ZSB0dXJuIG9mZlxuLy8gcmVnaXN0cmF0aW9uLiBUaGlzIGFsbG93cyBjb21tYW5kIGxpbmUgb3ZlcnJpZGluZyBvciBwcm9ncmFtbWF0aWNcbi8vIG92ZXJyaWRpbmcgb2YgdGhlIGRlZmF1bHQgcmVnaXN0cmF0aW9ucy5cbmxldCB0ZXN0RW52U2V0ID0gZmFsc2U7XG5leHBvcnQgZnVuY3Rpb24gc2V0VGVzdEVudnModGVzdEVudnM6IFRlc3RFbnZbXSkge1xuICB0ZXN0RW52U2V0ID0gdHJ1ZTtcbiAgVEVTVF9FTlZTLmxlbmd0aCA9IDA7XG4gIFRFU1RfRU5WUy5wdXNoKC4uLnRlc3RFbnZzKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyVGVzdEVudih0ZXN0RW52OiBUZXN0RW52KSB7XG4gIC8vIFdoZW4gdXNpbmcgYW4gZXhwbGljaXQgY2FsbCB0byBzZXRUZXN0RW52cywgdHVybiBvZmYgcmVnaXN0cmF0aW9uIG9mXG4gIC8vIHRlc3QgZW52aXJvbm1lbnRzIGJlY2F1c2UgdGhlIGV4cGxpY2l0IGNhbGwgd2lsbCBzZXQgdGhlIHRlc3RcbiAgLy8gZW52aXJvbm1lbnRzLlxuICBpZiAodGVzdEVudlNldCkge1xuICAgIHJldHVybjtcbiAgfVxuICBURVNUX0VOVlMucHVzaCh0ZXN0RW52KTtcbn1cblxuZnVuY3Rpb24gZXhlY3V0ZVRlc3RzKFxuICAgIHRlc3ROYW1lOiBzdHJpbmcsIHRlc3RzOiAoZW52OiBUZXN0RW52KSA9PiB2b2lkLCB0ZXN0RW52OiBUZXN0RW52KSB7XG4gIGRlc2NyaWJlKHRlc3ROYW1lLCAoKSA9PiB7XG4gICAgYmVmb3JlQWxsKGFzeW5jICgpID0+IHtcbiAgICAgIEVOR0lORS5yZXNldCgpO1xuICAgICAgaWYgKHRlc3RFbnYuZmxhZ3MgIT0gbnVsbCkge1xuICAgICAgICBlbnYoKS5zZXRGbGFncyh0ZXN0RW52LmZsYWdzKTtcbiAgICAgIH1cbiAgICAgIGVudigpLnNldCgnSVNfVEVTVCcsIHRydWUpO1xuICAgICAgLy8gQXdhaXQgc2V0dGluZyB0aGUgbmV3IGJhY2tlbmQgc2luY2UgaXQgY2FuIGhhdmUgYXN5bmMgaW5pdC5cbiAgICAgIGF3YWl0IEVOR0lORS5zZXRCYWNrZW5kKHRlc3RFbnYuYmFja2VuZE5hbWUpO1xuICAgIH0pO1xuXG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICBFTkdJTkUuc3RhcnRTY29wZSgpO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICAgIEVOR0lORS5lbmRTY29wZSgpO1xuICAgICAgRU5HSU5FLmRpc3Bvc2VWYXJpYWJsZXMoKTtcbiAgICB9KTtcblxuICAgIGFmdGVyQWxsKCgpID0+IHtcbiAgICAgIEVOR0lORS5yZXNldCgpO1xuICAgIH0pO1xuXG4gICAgdGVzdHModGVzdEVudik7XG4gIH0pO1xufVxuXG5leHBvcnQgY2xhc3MgVGVzdEtlcm5lbEJhY2tlbmQgZXh0ZW5kcyBLZXJuZWxCYWNrZW5kIHtcbiAgb3ZlcnJpZGUgZGlzcG9zZSgpOiB2b2lkIHt9XG59XG5cbmxldCBsb2NrID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbi8qKlxuICogV3JhcHMgYSBKYXNtaW5lIHNwZWMncyB0ZXN0IGZ1bmN0aW9uIHNvIGl0IGlzIHJ1biBleGNsdXNpdmVseSB0byBvdGhlcnMgdGhhdFxuICogdXNlIHJ1bldpdGhMb2NrLlxuICpcbiAqIEBwYXJhbSBzcGVjIFRoZSBmdW5jdGlvbiB0aGF0IHJ1bnMgdGhlIHNwZWMuIE11c3QgcmV0dXJuIGEgcHJvbWlzZSBvciBjYWxsXG4gKiAgICAgYGRvbmUoKWAuXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuV2l0aExvY2soc3BlYzogKGRvbmU/OiBEb25lRm4pID0+IFByb21pc2U8dm9pZD58IHZvaWQpIHtcbiAgcmV0dXJuICgpID0+IHtcbiAgICBsb2NrID0gbG9jay50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIGxldCBkb25lOiBEb25lRm47XG4gICAgICBjb25zdCBkb25lUHJvbWlzZSA9IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgZG9uZSA9ICgoKSA9PiB7XG4gICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgIH0pIGFzIERvbmVGbjtcbiAgICAgICAgZG9uZS5mYWlsID0gKG1lc3NhZ2U/KSA9PiB7XG4gICAgICAgICAgcmVqZWN0KG1lc3NhZ2UpO1xuICAgICAgICB9O1xuICAgICAgfSk7XG5cbiAgICAgIHB1cmdlTG9jYWxTdG9yYWdlQXJ0aWZhY3RzKCk7XG4gICAgICBjb25zdCByZXN1bHQgPSBzcGVjKGRvbmUpO1xuXG4gICAgICBpZiAoaXNQcm9taXNlKHJlc3VsdCkpIHtcbiAgICAgICAgYXdhaXQgcmVzdWx0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgZG9uZVByb21pc2U7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIGxvY2s7XG4gIH07XG59XG4iXX0=