Files
enviPy-bayer/static/js/ketcher2/node_modules/tap/bin/run.js
2025-06-23 20:13:54 +02:00

810 lines
19 KiB
JavaScript
Executable File

#!/usr/bin/env node
var node = process.execPath
var fs = require('fs')
var spawn = require('child_process').spawn
var fg = require('foreground-child')
var opener = require('opener')
var colorSupport = require('color-support')
var nycBin = require.resolve('nyc/bin/nyc.js')
var glob = require('glob')
var isexe = require('isexe')
var osHomedir = require('os-homedir')
var yaml = require('js-yaml')
var path = require('path')
var exists = require('fs-exists-cached').sync
var os = require('os');
var coverageServiceTest = process.env.COVERAGE_SERVICE_TEST === 'true'
// NYC will not wrap a module in node_modules.
// So, we need to tell the child proc when it's been added.
if (process.env._TAP_COVERAGE_ === '1')
global.__coverage__ = global.__coverage__ || {}
// console.error(process.argv.join(' '))
// console.error('CST=%j', process.env.COVERAGE_SERVICE_TEST)
// console.error('CRT=%j', process.env.COVERALLS_REPO_TOKEN)
if (coverageServiceTest)
console.log('COVERAGE_SERVICE_TEST')
// Add new coverage services here.
// it'll check for the environ named and pipe appropriately.
//
// Currently only Coveralls is supported, but the infrastructure
// is left in place in case some noble soul fixes the codecov
// module in the future. See https://github.com/tapjs/node-tap/issues/270
var coverageServices = [
{
env: 'COVERALLS_REPO_TOKEN',
bin: require.resolve('coveralls/bin/coveralls.js'),
name: 'Coveralls'
}
]
main()
function main () {
var args = process.argv.slice(2)
if (!args.length && process.stdin.isTTY) {
console.error(usage())
process.exit(1)
}
// set default args
var defaults = constructDefaultArgs()
// parse dotfile
var rcFile = process.env.TAP_RCFILE || (osHomedir() + '/.taprc')
var rcOptions = parseRcFile(rcFile)
// supplement defaults with parsed rc options
if (rcOptions)
Object.keys(rcOptions).forEach(function (k) {
defaults[k] = rcOptions[k]
})
defaults.rcFile = rcFile
// parse args
var options = parseArgs(args, defaults)
if (!options)
return
process.stdout.on('error', function (er) {
if (er.code === 'EPIPE')
process.exit()
else
throw er
})
options.files = globFiles(options.files)
if ((options.coverageReport || options.checkCoverage) &&
options.files.length === 0)
return runCoverageReport(options)
if (options.files.length === 0) {
console.error('Reading TAP data from stdin (use "-" argument to suppress)')
options.files.push('-')
}
if (options.files.length === 1 && options.files[0] === '-') {
if (options.coverage)
console.error('Coverage disabled because stdin cannot be instrumented')
stdinOnly(options)
return
}
// By definition, the next block cannot be covered, because
// they are only relevant when coverage is turned off.
/* istanbul ignore if */
if (options.coverage && !global.__coverage__)
return respawnWithCoverage(options)
setupTapEnv(options)
runTests(options)
}
function constructDefaultArgs () {
var defaultTimeout = 30
if (global.__coverage__)
defaultTimeout = 240
var defaultArgs = {
nodeArgs: [],
nycArgs: [],
testArgs: [],
timeout: +process.env.TAP_TIMEOUT || defaultTimeout,
color: !!colorSupport.level,
reporter: null,
files: [],
grep: [],
grepInvert: false,
bail: false,
saveFile: null,
pipeToService: false,
coverageReport: null,
browser: true,
coverage: undefined,
checkCoverage: false,
branches: 0,
functions: 0,
lines: 0,
statements: 0,
jobs: 1,
outputFile: null
}
if (process.env.TAP_COLORS !== undefined)
defaultArgs.color = !!(+process.env.TAP_COLORS)
return defaultArgs
}
function parseArgs (args, defaults) {
var options = defaults || {}
var singleFlags = {
b: 'bail',
B: 'no-bail',
i: 'invert',
I: 'no-invert',
c: 'color',
C: 'no-color',
T: 'no-timeout',
J: 'jobs-auto',
O: 'only',
h: 'help',
'?': 'help',
v: 'version'
}
var singleOpts = {
j: 'jobs',
g: 'grep',
R: 'reporter',
t: 'timeout',
s: 'save',
o: 'output-file'
}
// If we're running under Travis-CI with a Coveralls.io token,
// then it's a safe bet that we ought to output coverage.
for (var i = 0; i < coverageServices.length && !options.pipeToService; i++) {
if (process.env[coverageServices[i].env])
options.pipeToService = true
}
var defaultCoverage = options.pipeToService
var dumpConfig = false
for (i = 0; i < args.length; i++) {
var arg = args[i]
if (arg.charAt(0) !== '-' || arg === '-') {
options.files.push(arg)
continue
}
// short-flags
if (arg.charAt(1) !== '-' && arg !== '-gc') {
var expand = []
for (var f = 1; f < arg.length; f++) {
var fc = arg.charAt(f)
var sf = singleFlags[fc]
var so = singleOpts[fc]
if (sf)
expand.push('--' + sf)
else if (so) {
var soval = arg.slice(f + 1)
if (soval.charAt(0) !== '=') {
soval = '=' + soval
}
expand.push('--' + so + soval)
f = arg.length
} else if (arg !== '-' + fc)
expand.push('-' + fc)
}
if (expand.length) {
args.splice.apply(args, [i, 1].concat(expand))
i--
continue
}
}
var key = arg
var val = null
if (key.match(/^--/) && arg.indexOf('=') !== -1) {
var kv = arg.split('=')
key = kv.shift()
val = kv.join('=')
}
switch (key) {
case '--help':
console.log(usage())
return null
case '--dump-config':
dumpConfig = true
continue
case '--nyc-help':
nycHelp()
return null
case '--nyc-version':
nycVersion()
return null
case '--version':
console.log(require('../package.json').version)
return null
case '--jobs':
val = val || args[++i]
options.jobs = +val
continue
case '--jobs-auto':
val = os.cpus().length;
options.jobs = +val
continue
case '--coverage-report':
options.coverageReport = val || args[++i]
if (options.coverageReport === 'html')
options.coverageReport = 'lcov'
defaultCoverage = true
continue
case '--no-browser':
options.browser = false
continue
case '--no-coverage-report':
options.coverageReport = false
continue
case '--no-cov': case '--no-coverage':
options.coverage = false
continue
case '--cov': case '--coverage':
options.coverage = true
continue
case '--save':
val = val || args[++i]
options.saveFile = val
continue
case '--reporter':
val = val || args[++i]
options.reporter = val
continue
case '--gc': case '-gc': case '--expose-gc':
options.nodeArgs.push('--expose-gc')
continue
case '--strict':
options.nodeArgs.push('--use_strict')
continue
case '--debug':
options.nodeArgs.push('--debug')
continue
case '--debug-brk':
options.nodeArgs.push('--debug-brk')
continue
case '--harmony':
options.nodeArgs.push('--harmony')
continue
case '--node-arg':
val = val || args[++i]
if (val !== undefined)
options.nodeArgs.push(val)
continue
case '--check-coverage':
defaultCoverage = true
options.checkCoverage = true
continue
case '--test-arg':
val = val || args[++i]
if (val !== undefined)
options.testArgs.push(val)
continue
case '--nyc-arg':
val = val || args[++i]
if (val !== undefined)
options.nycArgs.push(val)
continue
case '--100':
defaultCoverage = true
options.checkCoverage = true
options.branches = 100
options.functions = 100
options.lines = 100
options.statements = 100
continue
case '--branches':
case '--functions':
case '--lines':
case '--statements':
defaultCoverage = true
val = val || args[++i]
options.checkCoverage = true
options[key.slice(2)] = val
continue
case '--color':
options.color = true
continue
case '--no-color':
options.color = false
continue
case '--output-file':
val = val || args[++i]
if (val !== undefined)
options.outputFile = val
continue
case '--no-timeout':
options.timeout = 0
continue
case '--timeout':
val = val || args[++i]
options.timeout = +val
continue
case '--invert':
options.grepInvert = true
continue
case '--no-invert':
options.grepInvert = false
continue
case '--grep':
val = val || args[++i]
if (val !== undefined)
options.grep.push(strToRegExp(val))
continue
case '--bail':
options.bail = true
continue
case '--no-bail':
options.bail = false
continue
case '--only':
options.only = true
continue
case '--':
options.files = options.files.concat(args.slice(i + 1))
i = args.length
continue
default:
throw new Error('Unknown argument: ' + arg)
}
}
if (options.coverage === undefined)
options.coverage = defaultCoverage
if (process.env.TAP === '1')
options.reporter = 'tap'
// default to tap for non-tty envs
if (!options.reporter)
options.reporter = options.color ? 'classic' : 'tap'
if (dumpConfig)
return console.log(JSON.stringify(options, null, 2))
return options
}
/* istanbul ignore next */
function respawnWithCoverage (options) {
// console.error('respawn with coverage')
// Re-spawn with coverage
var args = [nycBin].concat(
'--silent',
'--cache=true',
options.nycArgs,
'--',
process.execArgv,
process.argv.slice(1)
)
process.env._TAP_COVERAGE_ = '1'
var child = fg(node, args)
child.removeAllListeners('close')
child.on('close', function (code, signal) {
runCoverageReport(options, code, signal)
})
}
function pipeToCoverageServices (options, child) {
// console.error('pipe to services')
var piped = false
for (var i = 0; i < coverageServices.length; i++) {
// console.error('pipe to service?', coverageServices[i].env)
if (process.env[coverageServices[i].env]) {
pipeToCoverageService(coverageServices[i], options, child)
piped = true
}
}
/* istanbul ignore if */
if (!piped)
throw new Error('unknown service, internal error')
}
function pipeToCoverageService (service, options, child) {
// console.error('pipe to service yes', service.env)
var bin = service.bin
if (coverageServiceTest) {
// console.error('use fakey test bin')
// test scaffolding.
// don't actually send stuff to the service
bin = require.resolve('../test/fixtures/cat.js')
console.log('%s:%s', service.name, process.env[service.env])
}
var ca = spawn(node, [bin], {
stdio: [ 'pipe', 1, 2 ]
})
child.stdout.pipe(ca.stdin)
ca.on('close', function (code, signal) {
if (signal)
process.kill(process.pid, signal)
else if (code)
console.log('Error piping coverage to ' + service.name)
else
console.log('Successfully piped to ' + service.name)
})
}
function runCoverageReport (options, code, signal) {
if (options.checkCoverage)
runCoverageCheck(options, code, signal)
else
runCoverageReportOnly(options, code, signal)
}
function runCoverageReportOnly (options, code, signal) {
if (options.coverageReport === false)
return close(code, signal)
if (!options.coverageReport) {
if (options.pipeToService || coverageServiceTest)
options.coverageReport = 'text-lcov'
else
options.coverageReport = 'text'
}
var args = [nycBin, 'report', '--reporter', options.coverageReport]
// console.error('run coverage report', args)
var child
// automatically hook into coveralls
if (options.coverageReport === 'text-lcov' && options.pipeToService) {
// console.error('pipeToService')
child = spawn(node, args, { stdio: [ 0, 'pipe', 2 ] })
pipeToCoverageServices(options, child)
} else {
// otherwise just run the reporter
child = fg(node, args)
if (options.coverageReport === 'lcov' && options.browser)
child.on('exit', function () {
opener('coverage/lcov-report/index.html')
})
}
if (code || signal) {
child.removeAllListeners('close')
child.on('close', close)
}
function close (c, s) {
if (signal || s) {
setTimeout(function () {}, 200)
return process.kill(process.pid, signal || s)
}
if (code || c)
return process.exit(code || c)
}
}
function coverageCheckArgs (options) {
var args = []
if (options.branches)
args.push('--branches', options.branches)
if (options.functions)
args.push('--functions', options.functions)
if (options.lines)
args.push('--lines', options.lines)
if (options.statements)
args.push('--statements', options.statements)
return args
}
function runCoverageCheck (options, code, signal) {
var args = [nycBin, 'check-coverage'].concat(coverageCheckArgs(options))
var child = fg(node, args)
child.removeAllListeners('close')
child.on('close', function (c, s) {
runCoverageReportOnly(options, code || c, signal || s)
})
}
function usage () {
return fs.readFileSync(__dirname + '/usage.txt', 'utf8')
.split('@@REPORTERS@@')
.join(getReporters())
}
function nycHelp () {
fg(node, [nycBin, '--help'])
}
function nycVersion () {
console.log(require('nyc/package.json').version)
}
function getReporters () {
var types = require('tap-mocha-reporter').types
types = types.reduce(function (str, t) {
var ll = str.split('\n').pop().length + t.length
if (ll < 40)
return str + ' ' + t
else
return str + '\n' + t
}, '').trim()
var ind = ' '
return ind + types.split('\n').join('\n' + ind)
}
function setupTapEnv (options) {
process.env.TAP_TIMEOUT = options.timeout
if (options.color)
process.env.TAP_COLORS = 1
else
process.env.TAP_COLORS = 0
if (options.bail)
process.env.TAP_BAIL = '1'
if (options.grepInvert)
process.env.TAP_GREP_INVERT = '1'
if (options.grep.length)
process.env.TAP_GREP = options.grep.map(function (pattern) {
return pattern.toString()
}).join('\n')
if (options.only)
process.env.TAP_ONLY = '1'
}
function globFiles (files) {
return files.reduce(function (acc, f) {
if (f === '-') {
acc.push(f)
return acc
}
// glob claims patterns MUST not include any '\'s
if (!/\\/.test(f))
f = glob.sync(f) || f
return acc.concat(f)
}, [])
}
function makeReporter (options) {
var TMR = require('tap-mocha-reporter')
return new TMR(options.reporter)
}
function stdinOnly (options) {
// if we didn't specify any files, then just passthrough
// to the reporter, so we don't get '/dev/stdin' in the suite list.
// We have to pause() before piping to switch streams2 into old-mode
process.stdin.pause()
var reporter = makeReporter(options)
process.stdin.pipe(reporter)
process.stdin.resume()
}
function readSaveFile (options) {
if (options.saveFile)
try {
return fs.readFileSync(options.saveFile, 'utf8').trim().split('\n')
} catch (er) {}
return null
}
function saveFails (options, tap) {
if (!options.saveFile)
return
var fails = []
var successes = []
tap.on('result', function (res) {
// we will continue to re-run todo tests, even though they're
// not technically "failures".
if (!res.ok && !res.extra.skip)
fails.push(res.extra.file)
else
successes.push(res.extra.file)
})
tap.on('bailout', function (reason) {
// add any pending test files to the fails list.
fails.push.apply(fails, options.files.filter(function (file) {
return successes.indexOf(file) === -1
}))
save()
})
tap.on('end', save)
function save () {
fails = fails.reduce(function (set, f) {
if (set.indexOf(f) === -1)
set.push(f)
return set
}, [])
if (!fails.length)
try {
fs.unlinkSync(options.saveFile)
} catch (er) {}
else
try {
fs.writeFileSync(options.saveFile, fails.join('\n') + '\n')
} catch (er) {}
}
}
function filterFiles (files, saved, parallelOk) {
return files.filter(function (file) {
if (path.basename(file) === 'tap-parallel-ok')
parallelOk[path.resolve(path.dirname(file))] = true
else if (path.basename(file) === 'tap-parallel-not-ok')
parallelOk[path.resolve(path.dirname(file))] = false
else
return saved === null || saved.indexOf(file) !== -1
})
}
function isParallelOk (parallelOk, file) {
var dir = path.resolve(path.dirname(file))
if (dir in parallelOk)
return parallelOk[dir]
if (exists(dir + '/tap-parallel-ok'))
return parallelOk[dir] = true
if (exists(dir + '/tap-parallel-not-ok'))
return parallelOk[dir] = false
if (dir.length >= process.cwd().length)
return isParallelOk(parallelOk, dir)
}
function runAllFiles (options, saved, tap) {
var doStdin = false
var parallelOk = Object.create(null)
options.files = filterFiles(options.files, saved, parallelOk)
for (var i = 0; i < options.files.length; i++) {
var opt = {}
var file = options.files[i]
// Pick up stdin after all the other files are handled.
if (file === '-') {
doStdin = true
continue
}
var st = fs.statSync(options.files[i])
if (options.timeout)
opt.timeout = options.timeout * 1000
opt.file = file
if (options.jobs > 1)
opt.buffered = isParallelOk(parallelOk, file) !== false
if (file.match(/\.js$/)) {
var args = options.nodeArgs.concat(file).concat(options.testArgs)
tap.spawn(node, args, opt, file)
} else if (st.isDirectory()) {
var dir = filterFiles(fs.readdirSync(file).map(function (f) {
return file + '/' + f
}), saved, parallelOk)
options.files.push.apply(options.files, dir)
} else if (isexe.sync(options.files[i]))
tap.spawn(options.files[i], options.testArgs, opt, file)
}
if (doStdin)
tap.stdin()
}
function runTests (options) {
var saved = readSaveFile(options)
// At this point, we know we need to use the tap root,
// because there are 1 or more files to spawn.
var tap = require('../lib/tap.js')
tap.runOnly = false
// greps are passed to children, but not the runner itself
tap.grep = []
tap.jobs = options.jobs
tap.patchProcess()
// if not -Rtap, then output what the user wants.
// otherwise just dump to stdout
tap.pipe(options.reporter === 'tap' ? process.stdout: makeReporter(options))
// need to replay the first version line, because the previous
// line will have flushed it out to stdout or the reporter already.
if (options.outputFile !== null)
tap.pipe(fs.createWriteStream(options.outputFile)).write('TAP version 13\n')
saveFails(options, tap)
runAllFiles(options, saved, tap)
tap.end()
}
function parseRcFile (path) {
try {
var contents = fs.readFileSync(path, 'utf8')
return yaml.safeLoad(contents) || {}
} catch (er) {
// if no dotfile exists, or invalid yaml, fail gracefully
return {}
}
}
function strToRegExp (g) {
var p = g.match(/^\/(.*)\/([a-z]*)$/)
g = p ? p[1] : g
var flags = p ? p[2] : ''
return new RegExp(g, flags)
}