@decaf-ts/utils
Version:
module management utils for decaf-ts
222 lines • 30.5 kB
JavaScript
import path from "path";
import fs from "fs";
import { installIfNotAvailable } from "./fs";
export const JestReportersTempPathEnvKey = "JEST_HTML_REPORTERS_TEMP_DIR_PATH";
const dependencies = ["jest-html-reporters", "json2md", "chartjs-node-canvas"];
async function normalizeImport(importPromise) {
// CommonJS's `module.exports` is wrapped as `default` in ESModule.
return importPromise.then((m) => (m.default || m));
}
/**
* @description Test reporting utility class for managing test results and evidence
* @summary A comprehensive test reporter that handles various types of test artifacts including messages,
* attachments, data, images, tables, and graphs. It provides methods to report and store test evidence
* in different formats and manages dependencies for reporting functionality.
*
* @template T - Type of data being reported
* @param {string} [testCase="tests"] - Name of the test case
* @param {string} [basePath] - Base path for storing test reports
* @class
*
* @example
* ```typescript
* const reporter = new TestReporter('login-test');
*
* // Report test messages
* await reporter.reportMessage('Test Started', 'Login flow initiated');
*
* // Report test data
* await reporter.reportData('user-credentials', { username: 'test' }, 'json');
*
* // Report test results table
* await reporter.reportTable('test-results', {
* headers: ['Step', 'Status'],
* rows: [
* { Step: 'Login', Status: 'Pass' },
* { Step: 'Validation', Status: 'Pass' }
* ]
* });
*
* // Report test evidence
* await reporter.reportAttachment('Screenshot', screenshotBuffer);
* ```
*
* @mermaid
* sequenceDiagram
* participant Client
* participant TestReporter
* participant FileSystem
* participant Dependencies
*
* Client->>TestReporter: new TestReporter(testCase, basePath)
* TestReporter->>FileSystem: Create report directory
*
* alt Report Message
* Client->>TestReporter: reportMessage(title, message)
* TestReporter->>Dependencies: Import helpers
* TestReporter->>FileSystem: Store message
* else Report Data
* Client->>TestReporter: reportData(reference, data, type)
* TestReporter->>Dependencies: Process data
* TestReporter->>FileSystem: Store formatted data
* else Report Table
* Client->>TestReporter: reportTable(reference, tableDef)
* TestReporter->>Dependencies: Convert to MD format
* TestReporter->>FileSystem: Store table
* end
*/
export class TestReporter {
constructor(testCase = "tests", basePath = path.join(process.cwd(), "workdocs", "reports", "evidences")) {
this.testCase = testCase;
this.basePath = basePath;
this.basePath = path.join(basePath, this.testCase);
if (!fs.existsSync(this.basePath)) {
fs.mkdirSync(basePath, { recursive: true });
}
}
/**
* @description Imports required helper functions
* @summary Ensures all necessary dependencies are available and imports helper functions
* @return {Promise<void>} Promise that resolves when helpers are imported
*/
async importHelpers() {
this.deps = await installIfNotAvailable([dependencies[0]], this.deps);
// if (!process.env[JestReportersTempPathEnvKey])
// process.env[JestReportersTempPathEnvKey] = './workdocs/reports';
const { addMsg, addAttach } = await normalizeImport(import(`${dependencies[0]}/helper`));
TestReporter.addMsgFunction = addMsg;
TestReporter.addAttachFunction = addAttach;
}
/**
* @description Reports a message to the test report
* @summary Adds a formatted message to the test report with an optional title
* @param {string} title - Title of the message
* @param {string | object} message - Content of the message
* @return {Promise<void>} Promise that resolves when the message is reported
*/
async reportMessage(title, message) {
if (!TestReporter.addMsgFunction)
await this.importHelpers();
const msg = `${title}${message ? `\n${message}` : ""}`;
await TestReporter.addMsgFunction({ message: msg });
}
/**
* @description Reports an attachment to the test report
* @summary Adds a formatted message to the test report with an optional title
* @param {string} title - Title of the message
* @param {string | Buffer} attachment - Content of the message
* @return {Promise<void>} Promise that resolves when the message is reported
*/
async reportAttachment(title, attachment) {
if (!TestReporter.addAttachFunction)
await this.importHelpers();
await TestReporter.addAttachFunction({
attach: attachment,
description: title,
});
}
/**
* @description Reports data with specified type
* @summary Processes and stores data in the test report with formatting
* @param {string} reference - Reference identifier for the data
* @param {string | number | object} data - Data to be reported
* @param {PayloadType} type - Type of the payload
* @param {boolean} [trim=false] - Whether to trim the data
* @return {Promise<void>} Promise that resolves when data is reported
*/
async report(reference, data, type, trim = false) {
try {
let attachFunction = this.reportMessage.bind(this);
let extension = ".txt";
switch (type) {
case "image":
data = Buffer.from(data);
extension = ".png";
attachFunction = this.reportAttachment.bind(this);
break;
case "json":
if (trim) {
if (data.request)
delete data["request"];
if (data.config)
delete data["config"];
}
data = JSON.stringify(data, null, 2);
extension = ".json";
break;
case "md":
extension = ".md";
break;
case "text":
extension = ".txt";
break;
default:
console.log(`Unsupported type ${type}. assuming text`);
}
reference = reference.includes("\n")
? reference
: `${reference}${extension}`;
await attachFunction(reference, data);
}
catch (e) {
throw new Error(`Could not store attach artifact ${reference} under to test report ${this.testCase} - ${e}`);
}
}
async reportData(reference, data, type = "json", trim = false) {
return this.report(reference, data, type, trim);
}
async reportObject(reference, json, trim = false) {
return this.report(reference, json, "json", trim);
}
/**
* @description Reports a table in markdown format
* @summary Converts and stores a table definition in markdown format
* @param {string} reference - Reference identifier for the table
* @param {MdTableDefinition} tableDef - Table definition object
* @return {Promise<void>} Promise that resolves when table is reported
*/
async reportTable(reference, tableDef) {
this.deps = await installIfNotAvailable([dependencies[1]], this.deps);
let txt;
try {
const json2md = await normalizeImport(import(`${dependencies[1]}`));
txt = json2md(tableDef);
}
catch (e) {
throw new Error(`Could not convert JSON to Markdown - ${e}`);
}
return this.report(reference, txt, "md");
}
/**
* @description Reports a graph using Chart.js
* @summary Generates and stores a graph visualization
* @param {string} reference - Reference identifier for the graph
* @param {any} config - Chart.js configuration object
* @return {Promise<void>} Promise that resolves when graph is reported
*/
async reportGraph(reference, config) {
this.deps = await installIfNotAvailable([dependencies[2]], this.deps);
const { ChartJSNodeCanvas } = await normalizeImport(import(dependencies[2]));
const width = 600; //px
const height = 800; //px
const backgroundColour = "white"; // Uses https://www.w3schools.com/tags/canvas_fillstyle.asp
const chartJSNodeCanvas = new ChartJSNodeCanvas({
width,
height,
backgroundColour,
});
const image = await chartJSNodeCanvas.renderToBuffer(config);
return await this.reportImage(reference, image);
}
/**
* @description Reports an image to the test report
* @summary Stores an image buffer in the test report
* @param {string} reference - Reference identifier for the image
* @param {Buffer} buffer - Image data buffer
* @return {Promise<void>} Promise that resolves when image is reported
*/
async reportImage(reference, buffer) {
return this.report(reference, buffer, "image");
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvdGVzdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQztBQUVwQixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFtQzdDLE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixHQUFHLG1DQUFtQyxDQUFDO0FBRS9FLE1BQU0sWUFBWSxHQUFHLENBQUMscUJBQXFCLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixDQUFDLENBQUM7QUFFL0UsS0FBSyxVQUFVLGVBQWUsQ0FBSSxhQUF5QjtJQUN6RCxtRUFBbUU7SUFDbkUsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFNLENBQUMsQ0FBQztBQUMvRCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlERztBQUNILE1BQU0sT0FBTyxZQUFZO0lBd0J2QixZQUNZLFdBQW1CLE9BQU8sRUFDMUIsV0FBVyxJQUFJLENBQUMsSUFBSSxDQUM1QixPQUFPLENBQUMsR0FBRyxFQUFFLEVBQ2IsVUFBVSxFQUNWLFNBQVMsRUFDVCxXQUFXLENBQ1o7UUFOUyxhQUFRLEdBQVIsUUFBUSxDQUFrQjtRQUMxQixhQUFRLEdBQVIsUUFBUSxDQUtqQjtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2xDLEVBQUUsQ0FBQyxTQUFT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QWlCLEVBQUUsTUFBYztRQUNqRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNqRCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgTWRUYWJsZURlZmluaXRpb24gfSBmcm9tIFwiLi9tZFwiO1xuaW1wb3J0IHsgaW5zdGFsbElmTm90QXZhaWxhYmxlIH0gZnJvbSBcIi4vZnNcIjtcbmltcG9ydCB7IFNpbXBsZURlcGVuZGVuY3lNYXAgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgQWRkQXR0YWNoUGFyYW1zXG4gKiBAZGVzY3JpcHRpb24gUGFyYW1ldGVycyBmb3IgYWRkaW5nIGFuIGF0dGFjaG1lbnQgdG8gYSByZXBvcnRcbiAqIEBzdW1tYXJ5IEludGVyZmFjZSBmb3IgYXR0YWNobWVudCBwYXJhbWV0ZXJzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkBkZWNhZi10cy91dGlsc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIEFkZEF0dGFjaFBhcmFtcyB7XG4gIGF0dGFjaDogc3RyaW5nIHwgQnVmZmVyO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nIHwgb2JqZWN0O1xuICBjb250ZXh0PzogYW55O1xuICBidWZmZXJGb3JtYXQ/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQGludGVyZmFjZSBBZGRNc2dQYXJhbXNcbiAqIEBkZXNjcmlwdGlvbiBQYXJhbWV0ZXJzIGZvciBhZGRpbmcgYSBtZXNzYWdlIHRvIGEgcmVwb3J0XG4gKiBAc3VtbWFyeSBJbnRlcmZhY2UgZm9yIG1lc3NhZ2UgcGFyYW1ldGVyc1xuICogQG1lbWJlck9mIG1vZHVsZTpAZGVjYWYtdHMvdXRpbHNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBZGRNc2dQYXJhbXMge1xuICBtZXNzYWdlOiBzdHJpbmcgfCBvYmplY3Q7XG4gIGNvbnRleHQ/OiBhbnk7XG59XG5cbi8qKlxuICogQHR5cGVkZWYgeyhcImpzb25cInxcImltYWdlXCJ8XCJ0ZXh0XCJ8XCJtZFwiKX0gUGF5bG9hZFR5cGVcbiAqIEBkZXNjcmlwdGlvbiBUeXBlcyBvZiBwYXlsb2FkcyB0aGF0IGNhbiBiZSBoYW5kbGVkXG4gKiBAc3VtbWFyeSBVbmlvbiB0eXBlIGZvciBwYXlsb2FkIHR5cGVzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkBkZWNhZi10cy91dGlsc1xuICovXG5leHBvcnQgdHlwZSBQYXlsb2FkVHlwZSA9IFwianNvblwiIHwgXCJpbWFnZVwiIHwgXCJ0ZXh0XCIgfCBcIm1kXCI7XG5cbmV4cG9ydCBjb25zdCBKZXN0UmVwb3J0ZXJzVGVtcFBhdGhFbnZLZXkgPSBcIkpFU1RfSFRNTF9SRVBPUlRFUlNfVEVNUF9ESVJfUEFUSFwiO1xuXG5jb25zdCBkZXBlbmRlbmNpZXMgPSBbXCJqZXN0LWh0bWwtcmVwb3J0ZXJzXCIsIFwianNvbjJtZFwiLCBcImNoYXJ0anMtbm9kZS1jYW52YXNcIl07XG5cbmFzeW5jIGZ1bmN0aW9uIG5vcm1hbGl6ZUltcG9ydDxUPihpbXBvcnRQcm9taXNlOiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gIC8vIENvbW1vbkpTJ3MgYG1vZHVsZS5leHBvcnRzYCBpcyB3cmFwcGVkIGFzIGBkZWZhdWx0YCBpbiBFU01vZHVsZS5cbiAgcmV0dXJuIGltcG9ydFByb21pc2UudGhlbigobTogYW55KSA9PiAobS5kZWZhdWx0IHx8IG0pIGFzIFQpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBUZXN0IHJlcG9ydGluZyB1dGlsaXR5IGNsYXNzIGZvciBtYW5hZ2luZyB0ZXN0IHJlc3VsdHMgYW5kIGV2aWRlbmNlXG4gKiBAc3VtbWFyeSBBIGNvbXByZWhlbnNpdmUgdGVzdCByZXBvcnRlciB0aGF0IGhhbmRsZXMgdmFyaW91cyB0eXBlcyBvZiB0ZXN0IGFydGlmYWN0cyBpbmNsdWRpbmcgbWVzc2FnZXMsXG4gKiBhdHRhY2htZW50cywgZGF0YSwgaW1hZ2VzLCB0YWJsZXMsIGFuZCBncmFwaHMuIEl0IHByb3ZpZGVzIG1ldGhvZHMgdG8gcmVwb3J0IGFuZCBzdG9yZSB0ZXN0IGV2aWRlbmNlXG4gKiBpbiBkaWZmZXJlbnQgZm9ybWF0cyBhbmQgbWFuYWdlcyBkZXBlbmRlbmNpZXMgZm9yIHJlcG9ydGluZyBmdW5jdGlvbmFsaXR5LlxuICpcbiAqIEB0ZW1wbGF0ZSBUIC0gVHlwZSBvZiBkYXRhIGJlaW5nIHJlcG9ydGVkXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Rlc3RDYXNlPVwidGVzdHNcIl0gLSBOYW1lIG9mIHRoZSB0ZXN0IGNhc2VcbiAqIEBwYXJhbSB7c3RyaW5nfSBbYmFzZVBhdGhdIC0gQmFzZSBwYXRoIGZvciBzdG9yaW5nIHRlc3QgcmVwb3J0c1xuICogQGNsYXNzXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHJlcG9ydGVyID0gbmV3IFRlc3RSZXBvcnRlcignbG9naW4tdGVzdCcpO1xuICpcbiAqIC8vIFJlcG9ydCB0ZXN0IG1lc3NhZ2VzXG4gKiBhd2FpdCByZXBvcnRlci5yZXBvcnRNZXNzYWdlKCdUZXN0IFN0YXJ0ZWQnLCAnTG9naW4gZmxvdyBpbml0aWF0ZWQnKTtcbiAqXG4gKiAvLyBSZXBvcnQgdGVzdCBkYXRhXG4gKiBhd2FpdCByZXBvcnRlci5yZXBvcnREYXRhKCd1c2VyLWNyZWRlbnRpYWxzJywgeyB1c2VybmFtZTogJ3Rlc3QnIH0sICdqc29uJyk7XG4gKlxuICogLy8gUmVwb3J0IHRlc3QgcmVzdWx0cyB0YWJsZVxuICogYXdhaXQgcmVwb3J0ZXIucmVwb3J0VGFibGUoJ3Rlc3QtcmVzdWx0cycsIHtcbiAqICAgaGVhZGVyczogWydTdGVwJywgJ1N0YXR1cyddLFxuICogICByb3dzOiBbXG4gKiAgICAgeyBTdGVwOiAnTG9naW4nLCBTdGF0dXM6ICdQYXNzJyB9LFxuICogICAgIHsgU3RlcDogJ1ZhbGlkYXRpb24nLCBTdGF0dXM6ICdQYXNzJyB9XG4gKiAgIF1cbiAqIH0pO1xuICpcbiAqIC8vIFJlcG9ydCB0ZXN0IGV2aWRlbmNlXG4gKiBhd2FpdCByZXBvcnRlci5yZXBvcnRBdHRhY2htZW50KCdTY3JlZW5zaG90Jywgc2NyZWVuc2hvdEJ1ZmZlcik7XG4gKiBgYGBcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBUZXN0UmVwb3J0ZXJcbiAqICAgcGFydGljaXBhbnQgRmlsZVN5c3RlbVxuICogICBwYXJ0aWNpcGFudCBEZXBlbmRlbmNpZXNcbiAqXG4gKiAgIENsaWVudC0+PlRlc3RSZXBvcnRlcjogbmV3IFRlc3RSZXBvcnRlcih0ZXN0Q2FzZSwgYmFzZVBhdGgpXG4gKiAgIFRlc3RSZXBvcnRlci0+PkZpbGVTeXN0ZW06IENyZWF0ZSByZXBvcnQgZGlyZWN0b3J5XG4gKlxuICogICBhbHQgUmVwb3J0IE1lc3NhZ2VcbiAqICAgICBDbGllbnQtPj5UZXN0UmVwb3J0ZXI6IHJlcG9ydE1lc3NhZ2UodGl0bGUsIG1lc3NhZ2UpXG4gKiAgICAgVGVzdFJlcG9ydGVyLT4+RGVwZW5kZW5jaWVzOiBJbXBvcnQgaGVscGVyc1xuICogICAgIFRlc3RSZXBvcnRlci0+PkZpbGVTeXN0ZW06IFN0b3JlIG1lc3NhZ2VcbiAqICAgZWxzZSBSZXBvcnQgRGF0YVxuICogICAgIENsaWVudC0+PlRlc3RSZXBvcnRlcjogcmVwb3J0RGF0YShyZWZlcmVuY2UsIGRhdGEsIHR5cGUpXG4gKiAgICAgVGVzdFJlcG9ydGVyLT4+RGVwZW5kZW5jaWVzOiBQcm9jZXNzIGRhdGFcbiAqICAgICBUZXN0UmVwb3J0ZXItPj5GaWxlU3lzdGVtOiBTdG9yZSBmb3JtYXR0ZWQgZGF0YVxuICogICBlbHNlIFJlcG9ydCBUYWJsZVxuICogICAgIENsaWVudC0+PlRlc3RSZXBvcnRlcjogcmVwb3J0VGFibGUocmVmZXJlbmNlLCB0YWJsZURlZilcbiAqICAgICBUZXN0UmVwb3J0ZXItPj5EZXBlbmRlbmNpZXM6IENvbnZlcnQgdG8gTUQgZm9ybWF0XG4gKiAgICAgVGVzdFJlcG9ydGVyLT4+RmlsZVN5c3RlbTogU3RvcmUgdGFibGVcbiAqICAgZW5kXG4gKi9cbmV4cG9ydCBjbGFzcyBUZXN0UmVwb3J0ZXIge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZ1bmN0aW9uIGZvciBhZGRpbmcgbWVzc2FnZXMgdG8gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBzdW1tYXJ5IFN0YXRpYyBoYW5kbGVyIGZvciBwcm9jZXNzaW5nIGFuZCBzdG9yaW5nIHRlc3QgbWVzc2FnZXNcbiAgICogQHR5cGUge2Z1bmN0aW9uKEFkZE1zZ1BhcmFtcyk6IFByb21pc2U8dm9pZD59XG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGFkZE1zZ0Z1bmN0aW9uOiAocGFyYW1zOiBBZGRNc2dQYXJhbXMpID0+IFByb21pc2U8dm9pZD47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBGdW5jdGlvbiBmb3IgYWRkaW5nIGF0dGFjaG1lbnRzIHRvIHRoZSB0ZXN0IHJlcG9ydFxuICAgKiBAc3VtbWFyeSBTdGF0aWMgaGFuZGxlciBmb3IgcHJvY2Vzc2luZyBhbmQgc3RvcmluZyB0ZXN0IGF0dGFjaG1lbnRzXG4gICAqIEB0eXBlIHtmdW5jdGlvbihBZGRBdHRhY2hQYXJhbXMpOiBQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgcHJvdGVjdGVkIHN0YXRpYyBhZGRBdHRhY2hGdW5jdGlvbjogKFxuICAgIHBhcmFtczogQWRkQXR0YWNoUGFyYW1zXG4gICkgPT4gUHJvbWlzZTx2b2lkPjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIE1hcCBvZiBkZXBlbmRlbmNpZXMgcmVxdWlyZWQgYnkgdGhlIHJlcG9ydGVyXG4gICAqIEBzdW1tYXJ5IFN0b3JlcyB0aGUgY3VycmVudCBzdGF0ZSBvZiBkZXBlbmRlbmNpZXNcbiAgICogQHR5cGUge1NpbXBsZURlcGVuZGVuY3lNYXB9XG4gICAqL1xuICBwcml2YXRlIGRlcHM/OiBTaW1wbGVEZXBlbmRlbmN5TWFwO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCB0ZXN0Q2FzZTogc3RyaW5nID0gXCJ0ZXN0c1wiLFxuICAgIHByb3RlY3RlZCBiYXNlUGF0aCA9IHBhdGguam9pbihcbiAgICAgIHByb2Nlc3MuY3dkKCksXG4gICAgICBcIndvcmtkb2NzXCIsXG4gICAgICBcInJlcG9ydHNcIixcbiAgICAgIFwiZXZpZGVuY2VzXCJcbiAgICApXG4gICkge1xuICAgIHRoaXMuYmFzZVBhdGggPSBwYXRoLmpvaW4oYmFzZVBhdGgsIHRoaXMudGVzdENhc2UpO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmJhc2VQYXRoKSkge1xuICAgICAgZnMubWtkaXJTeW5jKGJhc2VQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEltcG9ydHMgcmVxdWlyZWQgaGVscGVyIGZ1bmN0aW9uc1xuICAgKiBAc3VtbWFyeSBFbnN1cmVzIGFsbCBuZWNlc3NhcnkgZGVwZW5kZW5jaWVzIGFyZSBhdmFpbGFibGUgYW5kIGltcG9ydHMgaGVscGVyIGZ1bmN0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBoZWxwZXJzIGFyZSBpbXBvcnRlZFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBpbXBvcnRIZWxwZXJzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuZGVwcyA9IGF3YWl0IGluc3RhbGxJZk5vdEF2YWlsYWJsZShbZGVwZW5kZW5jaWVzWzBdXSwgdGhpcy5kZXBzKTtcbiAgICAvLyBpZiAoIXByb2Nlc3MuZW52W0plc3RSZXBvcnRlcnNUZW1wUGF0aEVudktleV0pXG4gICAgLy8gICBwcm9jZXNzLmVudltKZXN0UmVwb3J0ZXJzVGVtcFBhdGhFbnZLZXldID0gJy4vd29ya2RvY3MvcmVwb3J0cyc7XG4gICAgY29uc3QgeyBhZGRNc2csIGFkZEF0dGFjaCB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KFxuICAgICAgaW1wb3J0KGAke2RlcGVuZGVuY2llc1swXX0vaGVscGVyYClcbiAgICApO1xuICAgIFRlc3RSZXBvcnRlci5hZGRNc2dGdW5jdGlvbiA9IGFkZE1zZztcbiAgICBUZXN0UmVwb3J0ZXIuYWRkQXR0YWNoRnVuY3Rpb24gPSBhZGRBdHRhY2g7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgYSBtZXNzYWdlIHRvIHRoZSB0ZXN0IHJlcG9ydFxuICAgKiBAc3VtbWFyeSBBZGRzIGEgZm9ybWF0dGVkIG1lc3NhZ2UgdG8gdGhlIHRlc3QgcmVwb3J0IHdpdGggYW4gb3B0aW9uYWwgdGl0bGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRpdGxlIC0gVGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBvYmplY3R9IG1lc3NhZ2UgLSBDb250ZW50IG9mIHRoZSBtZXNzYWdlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBtZXNzYWdlIGlzIHJlcG9ydGVkXG4gICAqL1xuICBhc3luYyByZXBvcnRNZXNzYWdlKHRpdGxlOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyB8IG9iamVjdCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghVGVzdFJlcG9ydGVyLmFkZE1zZ0Z1bmN0aW9uKSBhd2FpdCB0aGlzLmltcG9ydEhlbHBlcnMoKTtcbiAgICBjb25zdCBtc2cgPSBgJHt0aXRsZX0ke21lc3NhZ2UgPyBgXFxuJHttZXNzYWdlfWAgOiBcIlwifWA7XG4gICAgYXdhaXQgVGVzdFJlcG9ydGVyLmFkZE1zZ0Z1bmN0aW9uKHsgbWVzc2FnZTogbXNnIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXBvcnRzIGFuIGF0dGFjaG1lbnQgdG8gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBzdW1tYXJ5IEFkZHMgYSBmb3JtYXR0ZWQgbWVzc2FnZSB0byB0aGUgdGVzdCByZXBvcnQgd2l0aCBhbiBvcHRpb25hbCB0aXRsZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGl0bGUgLSBUaXRsZSBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0ge3N0cmluZyB8IEJ1ZmZlcn0gYXR0YWNobWVudCAtIENvbnRlbnQgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG1lc3NhZ2UgaXMgcmVwb3J0ZWRcbiAgICovXG4gIGFzeW5jIHJlcG9ydEF0dGFjaG1lbnQoXG4gICAgdGl0bGU6IHN0cmluZyxcbiAgICBhdHRhY2htZW50OiBzdHJpbmcgfCBCdWZmZXJcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCFUZXN0UmVwb3J0ZXIuYWRkQXR0YWNoRnVuY3Rpb24pIGF3YWl0IHRoaXMuaW1wb3J0SGVscGVycygpO1xuICAgIGF3YWl0IFRlc3RSZXBvcnRlci5hZGRBdHRhY2hGdW5jdGlvbih7XG4gICAgICBhdHRhY2g6IGF0dGFjaG1lbnQsXG4gICAgICBkZXNjcmlwdGlvbjogdGl0bGUsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgZGF0YSB3aXRoIHNwZWNpZmllZCB0eXBlXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhbmQgc3RvcmVzIGRhdGEgaW4gdGhlIHRlc3QgcmVwb3J0IHdpdGggZm9ybWF0dGluZ1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmZXJlbmNlIC0gUmVmZXJlbmNlIGlkZW50aWZpZXIgZm9yIHRoZSBkYXRhXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyIHwgb2JqZWN0fSBkYXRhIC0gRGF0YSB0byBiZSByZXBvcnRlZFxuICAgKiBAcGFyYW0ge1BheWxvYWRUeXBlfSB0eXBlIC0gVHlwZSBvZiB0aGUgcGF5bG9hZFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt0cmltPWZhbHNlXSAtIFdoZXRoZXIgdG8gdHJpbSB0aGUgZGF0YVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBkYXRhIGlzIHJlcG9ydGVkXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcmVwb3J0KFxuICAgIHJlZmVyZW5jZTogc3RyaW5nLFxuICAgIGRhdGE6IHN0cmluZyB8IG51bWJlciB8IG9iamVjdCB8IEJ1ZmZlcixcbiAgICB0eXBlOiBQYXlsb2FkVHlwZSxcbiAgICB0cmltOiBib29sZWFuID0gZmFsc2VcbiAgKSB7XG4gICAgdHJ5IHtcbiAgICAgIGxldCBhdHRhY2hGdW5jdGlvbjpcbiAgICAgICAgfCB0eXBlb2YgdGhpcy5yZXBvcnRNZXNzYWdlXG4gICAgICAgIHwgdHlwZW9mIHRoaXMucmVwb3J0QXR0YWNobWVudCA9IHRoaXMucmVwb3J0TWVzc2FnZS5iaW5kKHRoaXMpO1xuICAgICAgbGV0IGV4dGVuc2lvbjogXCIucG5nXCIgfCBcIi50eHRcIiB8IFwiLm1kXCIgfCBcIi5qc29uXCIgPSBcIi50eHRcIjtcblxuICAgICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICAgIGNhc2UgXCJpbWFnZVwiOlxuICAgICAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbShkYXRhIGFzIEJ1ZmZlcik7XG4gICAgICAgICAgZXh0ZW5zaW9uID0gXCIucG5nXCI7XG4gICAgICAgICAgYXR0YWNoRnVuY3Rpb24gPSB0aGlzLnJlcG9ydEF0dGFjaG1lbnQuYmluZCh0aGlzKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImpzb25cIjpcbiAgICAgICAgICBpZiAodHJpbSkge1xuICAgICAgICAgICAgaWYgKChkYXRhIGFzIHsgcmVxdWVzdD86IHVua25vd24gfSkucmVxdWVzdClcbiAgICAgICAgICAgICAgZGVsZXRlIChkYXRhIGFzIHsgcmVxdWVzdD86IHVua25vd24gfSlbXCJyZXF1ZXN0XCJdO1xuICAgICAgICAgICAgaWYgKChkYXRhIGFzIHsgY29uZmlnPzogdW5rbm93biB9KS5jb25maWcpXG4gICAgICAgICAgICAgIGRlbGV0ZSAoZGF0YSBhcyB7IGNvbmZpZz86IHVua25vd24gfSlbXCJjb25maWdcIl07XG4gICAgICAgICAgfVxuICAgICAgICAgIGRhdGEgPSBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKTtcbiAgICAgICAgICBleHRlbnNpb24gPSBcIi5qc29uXCI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJtZFwiOlxuICAgICAgICAgIGV4dGVuc2lvbiA9IFwiLm1kXCI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJ0ZXh0XCI6XG4gICAgICAgICAgZXh0ZW5zaW9uID0gXCIudHh0XCI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgY29uc29sZS5sb2coYFVuc3VwcG9ydGVkIHR5cGUgJHt0eXBlfS4gYXNzdW1pbmcgdGV4dGApO1xuICAgICAgfVxuICAgICAgcmVmZXJlbmNlID0gcmVmZXJlbmNlLmluY2x1ZGVzKFwiXFxuXCIpXG4gICAgICAgID8gcmVmZXJlbmNlXG4gICAgICAgIDogYCR7cmVmZXJlbmNlfSR7ZXh0ZW5zaW9ufWA7XG4gICAgICBhd2FpdCBhdHRhY2hGdW5jdGlvbihyZWZlcmVuY2UsIGRhdGEgYXMgQnVmZmVyIHwgc3RyaW5nKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3Qgc3RvcmUgYXR0YWNoIGFydGlmYWN0ICR7cmVmZXJlbmNlfSB1bmRlciB0byB0ZXN0IHJlcG9ydCAke3RoaXMudGVzdENhc2V9IC0gJHtlfWBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcmVwb3J0RGF0YShcbiAgICByZWZlcmVuY2U6IHN0cmluZyxcbiAgICBkYXRhOiBzdHJpbmcgfCBudW1iZXIgfCBvYmplY3QsXG4gICAgdHlwZTogUGF5bG9hZFR5cGUgPSBcImpzb25cIixcbiAgICB0cmltID0gZmFsc2VcbiAgKSB7XG4gICAgcmV0dXJuIHRoaXMucmVwb3J0KHJlZmVyZW5jZSwgZGF0YSwgdHlwZSwgdHJpbSk7XG4gIH1cblxuICBhc3luYyByZXBvcnRPYmplY3QocmVmZXJlbmNlOiBzdHJpbmcsIGpzb246IG9iamVjdCwgdHJpbSA9IGZhbHNlKSB7XG4gICAgcmV0dXJuIHRoaXMucmVwb3J0KHJlZmVyZW5jZSwganNvbiwgXCJqc29uXCIsIHRyaW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXBvcnRzIGEgdGFibGUgaW4gbWFya2Rvd24gZm9ybWF0XG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGFuZCBzdG9yZXMgYSB0YWJsZSBkZWZpbml0aW9uIGluIG1hcmtkb3duIGZvcm1hdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmZXJlbmNlIC0gUmVmZXJlbmNlIGlkZW50aWZpZXIgZm9yIHRoZSB0YWJsZVxuICAgKiBAcGFyYW0ge01kVGFibGVEZWZpbml0aW9ufSB0YWJsZURlZiAtIFRhYmxlIGRlZmluaXRpb24gb2JqZWN0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRhYmxlIGlzIHJlcG9ydGVkXG4gICAqL1xuICBhc3luYyByZXBvcnRUYWJsZShyZWZlcmVuY2U6IHN0cmluZywgdGFibGVEZWY6IE1kVGFibGVEZWZpbml0aW9uKSB7XG4gICAgdGhpcy5kZXBzID0gYXdhaXQgaW5zdGFsbElmTm90QXZhaWxhYmxlKFtkZXBlbmRlbmNpZXNbMV1dLCB0aGlzLmRlcHMpO1xuICAgIGxldCB0eHQ6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgY29uc3QganNvbjJtZCA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoYCR7ZGVwZW5kZW5jaWVzWzFdfWApKTtcbiAgICAgIHR4dCA9IGpzb24ybWQodGFibGVEZWYpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGNvbnZlcnQgSlNPTiB0byBNYXJrZG93biAtICR7ZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yZXBvcnQocmVmZXJlbmNlLCB0eHQsIFwibWRcIik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgYSBncmFwaCB1c2luZyBDaGFydC5qc1xuICAgKiBAc3VtbWFyeSBHZW5lcmF0ZXMgYW5kIHN0b3JlcyBhIGdyYXBoIHZpc3VhbGl6YXRpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZmVyZW5jZSAtIFJlZmVyZW5jZSBpZGVudGlmaWVyIGZvciB0aGUgZ3JhcGhcbiAgICogQHBhcmFtIHthbnl9IGNvbmZpZyAtIENoYXJ0LmpzIGNvbmZpZ3VyYXRpb24gb2JqZWN0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGdyYXBoIGlzIHJlcG9ydGVkXG4gICAqL1xuICBhc3luYyByZXBvcnRHcmFwaChyZWZlcmVuY2U6IHN0cmluZywgY29uZmlnOiBhbnkpIHtcbiAgICB0aGlzLmRlcHMgPSBhd2FpdCBpbnN0YWxsSWZOb3RBdmFpbGFibGUoW2RlcGVuZGVuY2llc1syXV0sIHRoaXMuZGVwcyk7XG4gICAgY29uc3QgeyBDaGFydEpTTm9kZUNhbnZhcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KFxuICAgICAgaW1wb3J0KGRlcGVuZGVuY2llc1syXSlcbiAgICApO1xuXG4gICAgY29uc3Qgd2lkdGggPSA2MDA7IC8vcHhcbiAgICBjb25zdCBoZWlnaHQgPSA4MDA7IC8vcHhcbiAgICBjb25zdCBiYWNrZ3JvdW5kQ29sb3VyID0gXCJ3aGl0ZVwiOyAvLyBVc2VzIGh0dHBzOi8vd3d3Lnczc2Nob29scy5jb20vdGFncy9jYW52YXNfZmlsbHN0eWxlLmFzcFxuICAgIGNvbnN0IGNoYXJ0SlNOb2RlQ2FudmFzID0gbmV3IENoYXJ0SlNOb2RlQ2FudmFzKHtcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0LFxuICAgICAgYmFja2dyb3VuZENvbG91cixcbiAgICB9KTtcblxuICAgIGNvbnN0IGltYWdlID0gYXdhaXQgY2hhcnRKU05vZGVDYW52YXMucmVuZGVyVG9CdWZmZXIoY29uZmlnKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5yZXBvcnRJbWFnZShyZWZlcmVuY2UsIGltYWdlKTtcbiAgfVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlcG9ydHMgYW4gaW1hZ2UgdG8gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBzdW1tYXJ5IFN0b3JlcyBhbiBpbWFnZSBidWZmZXIgaW4gdGhlIHRlc3QgcmVwb3J0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWZlcmVuY2UgLSBSZWZlcmVuY2UgaWRlbnRpZmllciBmb3IgdGhlIGltYWdlXG4gICAqIEBwYXJhbSB7QnVmZmVyfSBidWZmZXIgLSBJbWFnZSBkYXRhIGJ1ZmZlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBpbWFnZSBpcyByZXBvcnRlZFxuICAgKi9cbiAgYXN5bmMgcmVwb3J0SW1hZ2UocmVmZXJlbmNlOiBzdHJpbmcsIGJ1ZmZlcjogQnVmZmVyKSB7XG4gICAgcmV0dXJuIHRoaXMucmVwb3J0KHJlZmVyZW5jZSwgYnVmZmVyLCBcImltYWdlXCIpO1xuICB9XG59XG4iXX0=