lib/runner.js

const path = require('node:path');

const createReport = require('./createReport.js');
const include = require('./include.js');
const RunState = require('./RunState.js');
const callbackReporter = require('./reporters/callback.js');

/**
 * @module pete/lib/runner
 */

/**
 * Parse options from command line arguments and assign them to `options`.
 * Parse `args` into `fn`, `options` and `name` - each of them optional.
 *
 * @param {string}                     id        see {@link module:pete/lib/createId}
 * @param {module:pete/lib/RunOptions} options   target options object that will be changed
 * @param {any[]}                      args      arguments passed caller function
 * @return {Function|undefined} if any was passed through the `args`
 */
module.exports.setOptions = function setOptions (id, options, args) {
	var name;
	var fn;
	var cb;
	var opts;
	for (let i = 0, max = args.length; i < max; i++) {
		if (typeof args[i] === 'function') {
			if (fn) {
				cb = args[i];
			}
			else {
				fn = args[i];
			}
		}
		else if (typeof args[i] === 'object') {
			opts = args[i];
		}
		else if (typeof args[i] === 'string') {
			name = args[i];
		}
	}

	options.setFromOptions(opts);
	options.setFromArgv();

	options.id = id;

	if (name && !fn) {
		fn = name;
		name = null;
	}

	if (!name && typeof fn === 'function') {
		name = fn.name || id;
	}

	options.name = options.name || name;

	if (cb) {
		options.reporters.push(callbackReporter({out: cb}));
	}

	return fn;
};

/**
 * Run and report.
 *
 * @typedef {Function} run
 * @param {module:pete/lib/getReporters~report} report
 */

/**
 * Create run function that will call `fn`, depending on passed options.
 * `state` will be updated by the run function with benchmark scores.
 *
 * @param {Function|string} fn        either a Function or a path to script
 * @param {object}          options
 * @param {object}          [state]
 * @return {module:pete/lib/runner~startRun}
 */
module.exports.createRun = function createRun (fn, options, state) {
	const maxHDRValue = Number(options.limitRealTime > options.limitCPUTime ? options.limitRealTime : options.limitCPUTime);

	if (!state) {
		state = new RunState(maxHDRValue);
	}

	const factory = include(`./runs/${path.basename(options.runType || 'auto')}`) || include(options.runType);
	const run = factory(fn, options, state);
	const runType = state.runType;

	const error = state.error || (!options.limitCPUTime && !options.limitRealTime && new Error('At least one limit has to be set for Runner to start'));

	/**
	 * Resets state, reports error if any.
	 * Starts running test function if there were no errors.
	 * Reports results after run is finished.
	 *
	 * @typedef {Function} startRun
	 * @param {string}                              mode
	 * @param {module:pete/lib/getReporters~report} report
	 */
	return function startRun (mode, report) {
		state.reset();
		state.mode = mode;
		state.runType = state.runType || runType;

		if (error) {
			state.error = error;
			report(error, createReport(options, state));
			report();
			return;
		}

		run(report);
	};
};