lib/runnerQueue.js

const getReporters = require('./getReporters.js');
const gc = require('./gc.js');

/**
 * @module pete/lib/runnerQueue
 */
module.exports = enqueue;

/**
 * @private
 */
var queueHead = null;

/**
 * @private
 */
var queueTail = null;

/**
 * @private
 */
var queueExit = false;

/**
 * Add runner function to queue.
 * Start specified run on `nextTick` if this is the first test added.
 *
 * @alias module:pete/lib/runnerQueue
 * @param {module:pete/lib/runner~startRun} run
 * @param {object}                          options
 * @param {string}                          mode
 * @param {Function}                        [report]
 */
function enqueue (run, options, mode, report) {
	var r = {
		run,
		options,
		mode,
		report: report || dummyReport,
		next  : null
	};

	r.report = wrapReport(r);

	if (queueTail) {
		queueTail.next = r;
	}

	queueTail = r;

	if (!queueHead) {
		queueHead = r;
		queueExit = false;
		process.nextTick(next);
	}
}

/**
 * Dummy report function used when no real function was passed to `enqueue`.
 *
 * @private
 */
function dummyReport () {
	/* Nothing to do here */
}

/**
 * Shift queue linked list by one item.
 * Start run if there was item available.
 *
 * @private
 */
function next () {
	var r = queueHead;
	queueHead = r && r.next;

	if (!r || queueExit) {
		queueHead = null;
		queueTail = null;
		queueExit = false;
		// Close all reporters
		getReporters(null, {close: true});
		return;
	}

	r.run(r.mode, r.report);
}

/**
 * Wrap `report` function, so when it's called wthout args (marking "end of report"),
 * we can ignore that, so next run can continue reporting.
 *
 * @private
 * @param {object} r
 * @return {module:pete/lib/getReporters~report}
 */
function wrapReport (r) {
	var report = r.report;

	return function wrappedReport (err, data) {
		if (!r) {
			return;
		}

		if (err && r.options.exitOnError && (!data || data.exitOnError)) {
			queueExit = true;
		}

		if (err || data) {
			report(err, data);
			return;
		}

		process.nextTick(next);

		if (r.next && r.next.run !== r.run) {
			gc(true);
		}

		r = null;
		report = null;
	};
}