lib/createReport.js

const NanoTime = require('./NanoTime.js');

/**
 * @module pete/lib/createReport
 */
module.exports = createReport;

/**
 * Pseudo hdr that returns `Infinity` for every percentile.
 *
 * @private
 */
const HDR2INFINITY = {percentile: () => Infinity};

/**
 * Information about test run.
 *
 * `percentiles.p1` to `percentiles.p100` are optional, depending on `options.percentiles` passed to test function.
 *
 * @typedef {object} Report
 * @alias module:pete/lib/createReport~Report
 * @property {string}   id                   Unique identifier of place from which test function was called
 * @property {string}   name                 Name of the test
 * @property {string}   mode                 For example: "skip", "todo", "warmup" or "regular"
 * @property {string}   type                 Type of runner used to call target function
 * @property {NanoTime} limitCPUTime         Maximum time target function can run
 * @property {NanoTime} limitRealTime        Maximum total real time test can run
 * @property {number}   limitSamples         Maximum number of times target function should be run
 * @property {string[]} args                 Arguments passed to target function
 * @property {boolean}  exitOnError          Should test be cancelled after error
 * @property {NanoTime} started
 * @property {NanoTime} finished
 * @property {NanoTime} totalCPUTime         Sum of time it took to run target function
 * @property {NanoTime} totalRealTime        Time it took to run whole test
 * @property {number}   samples              Number of times target function was run
 * @property {number}   min                  see {@link external:Histogram}
 * @property {number}   max                  see {@link external:Histogram}
 * @property {number}   mean                 see {@link external:Histogram}
 * @property {number}   stddev               see {@link external:Histogram}
 * @property {object}   percentiles
 * @property {number}   [percentiles.p1]     If test options contained percentile 1, p1 will contain its value
 * @property {number}   [percentiles.p100]   If test options contained percentile 100, p100 will contain its value
 * @property {Error}    [error]              If there was any, while running the test
 */

/**
 * Creates report object from runner's options and state.
 *
 * @alias module:pete/lib/createReport
 * @param {module:pete/lib/RunOptions} options
 * @param {module:pete/lib/RunState}   state
 * @return {module:pete/lib/createReport~Report}
 */
function createReport (options, state) {
	var result = {
		id           : options.id,
		name         : options.name,
		mode         : state.mode,
		type         : state.runType,
		limitCPUTime : new NanoTime(options.limitCPUTime),
		limitRealTime: new NanoTime(options.limitRealTime),
		limitSamples : options.limitSamples,
		args         : options.args,
		exitOnError  : options.exitOnError,
		started      : new NanoTime(state.started),
		finished     : new NanoTime(state.finished),
		totalCPUTime : new NanoTime(state.totalCPUTime),
		totalRealTime: new NanoTime(state.finished - state.started),
		samples      : state.samplesCount,
		min          : nanToInfinity(state.hdr.min),
		max          : nanToInfinity(state.hdr.max),
		mean         : nanToInfinity(state.hdr.mean),
		stddev       : nanToInfinity(state.hdr.stddev),
		percentiles  : {},
		error        : state.error && state.error.toString()
	};

	if (result.max < result.min) {
		result.max = Infinity;
	}

	var p = 0;
	var value = 0;
	var hdr = state.hdr || HDR2INFINITY;
	for (var i = 0, max = options.percentiles.length; i < max; i++) {
		p = options.percentiles[i];
		value = hdr.percentile(p);
		result.percentiles[`p${p}`] = value >= result.min ? value : Infinity;
	}

	return result;
}

/**
 * Helper function to convert NaN to Infinity.
 *
 * @private
 * @param {any} value
 * @return {number}
 */
function nanToInfinity (value) {
	return isNaN(value) ? Infinity : value;
}