const {execFile} = require('child_process') const path = require('path') const {promisify} = require('util') exports.execFilePromise = promisify(execFile) function* reorderings(fixed, reorderable) { if (!reorderable.length) { yield fixed return } const [first, ...rest] = reorderable for (let i = 0; i <= fixed.length; i++) { yield* reorderings(fixed.slice(0, i).concat([first], fixed.slice(i)), rest) } } exports.reorderings = reorderings const updatePath = filename => path.join(...filename.split('/')) exports.updatePath = updatePath /** Updates the path separators in an expected output to match the OS's separator */ exports.updateExpectedPaths = expected => expected.map(lineGroup => lineGroup.map(line => { const pathEnd = line.indexOf(':') if (pathEnd < 0) throw new Error('Line does not have a path') return updatePath(line.slice(0, pathEnd)) + line.slice(pathEnd) })) function toLines(text) { const lines = text.split('\n') if (lines.length && !lines[lines.length - 1]) lines.pop() return lines } /** * Checks that grep.js's output matches an array of expected outputs for each file. * Each file's lines must appear in order, * but lines from different files can be intermingled. * The expected lines must be unique. */ exports.matchOutput = (t, actual, expected) => { // Has an entry for each file with remaining lines. // The first remaining line in the file is mapped to the set of subsequent lines. const nextLines = new Map() function addNextLine(lines) { if (lines.size) { const [firstLine] = lines lines.delete(firstLine) nextLines.set(firstLine, lines) } } for (const expectedLines of expected) addNextLine(new Set(expectedLines)) const expectedOutput = [] for (const line of toLines(actual)) { const expectedRest = nextLines.get(line) // If this was not the next line in any file, skip it if (!expectedRest) continue // If this was the next line in some file, record that it was matched // and remove it from the remaining lines in that file expectedOutput.push(line) nextLines.delete(line) addNextLine(expectedRest) } // Add all unmatched lines to the expected output for (const [firstLine, remainingLines] of nextLines) { expectedOutput.push(firstLine, ...remainingLines) } t.deepEqual( actual, expectedOutput.map(line => `${line}\n`).join(''), 'Unexpected grep.js output' ) }