-
-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
471 additions
and
570 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env node | ||
import process from 'node:process'; | ||
import {writeSync} from 'node:fs'; | ||
|
||
const fileDescriptorIndex = Number(process.argv[3] || 3); | ||
writeSync(fileDescriptorIndex, `${process.argv[2]}\n`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env node | ||
import process from 'node:process'; | ||
import {readFileSync} from 'node:fs'; | ||
|
||
const fileDescriptorIndex = Number(process.argv[3] || 3); | ||
console.log(readFileSync(fileDescriptorIndex, {encoding: 'utf8'})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export const getStdinOption = stdioOption => ({stdin: stdioOption}); | ||
export const getStdoutOption = stdioOption => ({stdout: stdioOption}); | ||
export const getStderrOption = stdioOption => ({stderr: stdioOption}); | ||
export const getPlainStdioOption = stdioOption => ({stdio: stdioOption}); | ||
export const getInputOption = input => ({input}); | ||
export const getInputFileOption = inputFile => ({inputFile}); | ||
|
||
export const getScriptSync = $ => $.sync; | ||
|
||
export const identity = value => value; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import {readFile, open} from 'node:fs/promises'; | ||
import test from 'ava'; | ||
import tempfile from 'tempfile'; | ||
import {execa, execaSync} from '../../index.js'; | ||
import {setFixtureDir} from '../helpers/fixtures-dir.js'; | ||
import {getStdinOption, getStdoutOption, getStderrOption} from '../helpers/stdio.js'; | ||
|
||
setFixtureDir(); | ||
|
||
const getStdinProp = ({stdin}) => stdin; | ||
|
||
const testFileDescriptorOption = async (t, fixtureName, getOptions, execaMethod) => { | ||
const filePath = tempfile(); | ||
const fileDescriptor = await open(filePath, 'w'); | ||
await execaMethod(fixtureName, ['foobar'], getOptions(fileDescriptor)); | ||
t.is(await readFile(filePath, 'utf8'), 'foobar\n'); | ||
}; | ||
|
||
test('pass `stdout` to a file descriptor', testFileDescriptorOption, 'noop.js', getStdoutOption, execa); | ||
test('pass `stderr` to a file descriptor', testFileDescriptorOption, 'noop-err.js', getStderrOption, execa); | ||
test('pass `stdout` to a file descriptor - sync', testFileDescriptorOption, 'noop.js', getStdoutOption, execaSync); | ||
test('pass `stderr` to a file descriptor - sync', testFileDescriptorOption, 'noop-err.js', getStderrOption, execaSync); | ||
|
||
const testStdinWrite = async (t, getStreamProp, fixtureName, getOptions) => { | ||
const subprocess = execa(fixtureName, getOptions('pipe')); | ||
getStreamProp(subprocess).end('unicorns'); | ||
const {stdout} = await subprocess; | ||
t.is(stdout, 'unicorns'); | ||
}; | ||
|
||
test('you can write to child.stdin', testStdinWrite, getStdinProp, 'stdin.js', getStdinOption); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import {readFile, writeFile} from 'node:fs/promises'; | ||
import {relative} from 'node:path'; | ||
import {pathToFileURL} from 'node:url'; | ||
import test from 'ava'; | ||
import tempfile from 'tempfile'; | ||
import {execa, execaSync, $} from '../../index.js'; | ||
import {setFixtureDir} from '../helpers/fixtures-dir.js'; | ||
import {getStdinOption, getStdoutOption, getStderrOption, getInputFileOption, getScriptSync, identity} from '../helpers/stdio.js'; | ||
|
||
setFixtureDir(); | ||
|
||
const nonFileUrl = new URL('https://example.com'); | ||
|
||
const getRelativePath = filePath => relative('.', filePath); | ||
|
||
const testStdinFile = async (t, mapFilePath, execaMethod) => { | ||
const inputPath = tempfile(); | ||
await writeFile(inputPath, 'foobar'); | ||
const {stdout} = await execaMethod('stdin.js', {stdin: mapFilePath(inputPath)}); | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('stdin can be a file URL', testStdinFile, pathToFileURL, execa); | ||
test('stdin can be an absolute file path', testStdinFile, identity, execa); | ||
test('stdin can be a relative file path', testStdinFile, getRelativePath, execa); | ||
test('stdin can be a file URL - sync', testStdinFile, pathToFileURL, execaSync); | ||
test('stdin can be an absolute file path - sync', testStdinFile, identity, execaSync); | ||
test('stdin can be a relative file path - sync', testStdinFile, getRelativePath, execaSync); | ||
|
||
// eslint-disable-next-line max-params | ||
const testOutputFile = async (t, mapFile, fixtureName, getOptions, execaMethod) => { | ||
const outputFile = tempfile(); | ||
await execaMethod(fixtureName, ['foobar'], getOptions(mapFile(outputFile))); | ||
t.is(await readFile(outputFile, 'utf8'), 'foobar\n'); | ||
}; | ||
|
||
test('stdout can be a file URL', testOutputFile, pathToFileURL, 'noop.js', getStdoutOption, execa); | ||
test('stderr can be a file URL', testOutputFile, pathToFileURL, 'noop-err.js', getStderrOption, execa); | ||
test('stdout can be an absolute file path', testOutputFile, identity, 'noop.js', getStdoutOption, execa); | ||
test('stderr can be an absolute file path', testOutputFile, identity, 'noop-err.js', getStderrOption, execa); | ||
test('stdout can be a relative file path', testOutputFile, getRelativePath, 'noop.js', getStdoutOption, execa); | ||
test('stderr can be a relative file path', testOutputFile, getRelativePath, 'noop-err.js', getStderrOption, execa); | ||
test('stdout can be a file URL - sync', testOutputFile, pathToFileURL, 'noop.js', getStdoutOption, execaSync); | ||
test('stderr can be a file URL - sync', testOutputFile, pathToFileURL, 'noop-err.js', getStderrOption, execaSync); | ||
test('stdout can be an absolute file path - sync', testOutputFile, identity, 'noop.js', getStdoutOption, execaSync); | ||
test('stderr can be an absolute file path - sync', testOutputFile, identity, 'noop-err.js', getStderrOption, execaSync); | ||
test('stdout can be a relative file path - sync', testOutputFile, getRelativePath, 'noop.js', getStdoutOption, execaSync); | ||
test('stderr can be a relative file path - sync', testOutputFile, getRelativePath, 'noop-err.js', getStderrOption, execaSync); | ||
|
||
const testStdioNonFileUrl = (t, getOptions, method) => { | ||
t.throws(() => { | ||
method('noop.js', getOptions(nonFileUrl)); | ||
}, {message: /pathToFileURL/}); | ||
}; | ||
|
||
test('stdin cannot be a non-file URL', testStdioNonFileUrl, getStdinOption, execa); | ||
test('stdout cannot be a non-file URL', testStdioNonFileUrl, getStdoutOption, execa); | ||
test('stderr cannot be a non-file URL', testStdioNonFileUrl, getStderrOption, execa); | ||
test('stdin cannot be a non-file URL - sync', testStdioNonFileUrl, getStdinOption, execaSync); | ||
test('stdout cannot be a non-file URL - sync', testStdioNonFileUrl, getStdoutOption, execaSync); | ||
test('stderr cannot be a non-file URL - sync', testStdioNonFileUrl, getStderrOption, execaSync); | ||
|
||
const testStdioValidUrl = (t, getOptions, method) => { | ||
t.throws(() => { | ||
method('noop.js', getOptions('foobar')); | ||
}, {message: /absolute file path/}); | ||
}; | ||
|
||
test('stdin must start with . when being a relative file path', testStdioValidUrl, getStdinOption, execa); | ||
test('stdout must start with . when being a relative file path', testStdioValidUrl, getStdoutOption, execa); | ||
test('stderr must start with . when being a relative file path', testStdioValidUrl, getStderrOption, execa); | ||
test('stdin must start with . when being a relative file path - sync', testStdioValidUrl, getStdinOption, execaSync); | ||
test('stdout must start with . when being a relative file path - sync', testStdioValidUrl, getStdoutOption, execaSync); | ||
test('stderr must start with . when being a relative file path - sync', testStdioValidUrl, getStderrOption, execaSync); | ||
|
||
const testFileError = async (t, mapFile, getOptions) => { | ||
await t.throwsAsync( | ||
execa('noop.js', getOptions(mapFile('./unknown/file'))), | ||
{code: 'ENOENT'}, | ||
); | ||
}; | ||
|
||
test('stdin file URL errors should be handled', testFileError, pathToFileURL, getStdinOption); | ||
test('stdout file URL errors should be handled', testFileError, pathToFileURL, getStdoutOption); | ||
test('stderr file URL errors should be handled', testFileError, pathToFileURL, getStderrOption); | ||
test('inputFile file URL errors should be handled', testFileError, pathToFileURL, getInputFileOption); | ||
test('stdin file path errors should be handled', testFileError, identity, getStdinOption); | ||
test('stdout file path errors should be handled', testFileError, identity, getStdoutOption); | ||
test('stderr file path errors should be handled', testFileError, identity, getStderrOption); | ||
test('inputFile file path errors should be handled', testFileError, identity, getInputFileOption); | ||
|
||
const testFileErrorSync = (t, mapFile, getOptions) => { | ||
t.throws(() => { | ||
execaSync('noop.js', getOptions(mapFile('./unknown/file'))); | ||
}, {code: 'ENOENT'}); | ||
}; | ||
|
||
test('stdin file URL errors should be handled - sync', testFileErrorSync, pathToFileURL, getStdinOption); | ||
test('stdout file URL errors should be handled - sync', testFileErrorSync, pathToFileURL, getStdoutOption); | ||
test('stderr file URL errors should be handled - sync', testFileErrorSync, pathToFileURL, getStderrOption); | ||
test('inputFile file URL errors should be handled - sync', testFileErrorSync, pathToFileURL, getInputFileOption); | ||
test('stdin file path errors should be handled - sync', testFileErrorSync, identity, getStdinOption); | ||
test('stdout file path errors should be handled - sync', testFileErrorSync, identity, getStdoutOption); | ||
test('stderr file path errors should be handled - sync', testFileErrorSync, identity, getStderrOption); | ||
test('inputFile file path errors should be handled - sync', testFileErrorSync, identity, getInputFileOption); | ||
|
||
const testInputFile = async (t, execaMethod) => { | ||
const inputFile = tempfile(); | ||
await writeFile(inputFile, 'foobar'); | ||
const {stdout} = await execaMethod('stdin.js', {inputFile}); | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('inputFile can be set', testInputFile, execa); | ||
test('inputFile can be set - sync', testInputFile, execa); | ||
|
||
const testInputFileScript = async (t, getExecaMethod) => { | ||
const inputFile = tempfile(); | ||
await writeFile(inputFile, 'foobar'); | ||
const {stdout} = await getExecaMethod($({inputFile}))`stdin.js`; | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('inputFile can be set with $', testInputFileScript, identity); | ||
test('inputFile can be set with $.sync', testInputFileScript, getScriptSync); | ||
|
||
test('inputFile option cannot be set when stdin is set', t => { | ||
t.throws(() => { | ||
execa('stdin.js', {inputFile: '', stdin: 'ignore'}); | ||
}, {message: /`inputFile` and `stdin` options/}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import {Buffer} from 'node:buffer'; | ||
import {Readable} from 'node:stream'; | ||
import {pathToFileURL} from 'node:url'; | ||
import test from 'ava'; | ||
import {execa, execaSync, $} from '../../index.js'; | ||
import {setFixtureDir} from '../helpers/fixtures-dir.js'; | ||
import {getStdinOption, getPlainStdioOption, getScriptSync, identity} from '../helpers/stdio.js'; | ||
|
||
setFixtureDir(); | ||
|
||
const testInputOptionError = (t, stdin, inputName) => { | ||
t.throws(() => { | ||
execa('stdin.js', {stdin, [inputName]: 'foobar'}); | ||
}, {message: new RegExp(`\`${inputName}\` and \`stdin\` options`)}); | ||
}; | ||
|
||
test('stdin option cannot be an iterable when "input" is used', testInputOptionError, ['foo', 'bar'], 'input'); | ||
test('stdin option cannot be an iterable when "inputFile" is used', testInputOptionError, ['foo', 'bar'], 'inputFile'); | ||
test('stdin option cannot be a file URL when "input" is used', testInputOptionError, pathToFileURL('unknown'), 'input'); | ||
test('stdin option cannot be a file URL when "inputFile" is used', testInputOptionError, pathToFileURL('unknown'), 'inputFile'); | ||
test('stdin option cannot be a file path when "input" is used', testInputOptionError, './unknown', 'input'); | ||
test('stdin option cannot be a file path when "inputFile" is used', testInputOptionError, './unknown', 'inputFile'); | ||
test('stdin option cannot be a ReadableStream when "input" is used', testInputOptionError, new ReadableStream(), 'input'); | ||
test('stdin option cannot be a ReadableStream when "inputFile" is used', testInputOptionError, new ReadableStream(), 'inputFile'); | ||
|
||
const testInput = async (t, input, execaMethod) => { | ||
const {stdout} = await execaMethod('stdin.js', {input}); | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('input option can be a String', testInput, 'foobar', execa); | ||
test('input option can be a String - sync', testInput, 'foobar', execaSync); | ||
test('input option can be a Buffer', testInput, Buffer.from('foobar'), execa); | ||
test('input option can be a Buffer - sync', testInput, Buffer.from('foobar'), execaSync); | ||
|
||
const testInputScript = async (t, getExecaMethod) => { | ||
const {stdout} = await getExecaMethod($({input: 'foobar'}))`stdin.js`; | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('input option can be used with $', testInputScript, identity); | ||
test('input option can be used with $.sync', testInputScript, getScriptSync); | ||
|
||
const testInputWithStdinError = (t, input, getOptions, execaMethod) => { | ||
t.throws(() => { | ||
execaMethod('stdin.js', {input, ...getOptions('ignore')}); | ||
}, {message: /`input` and `stdin` options/}); | ||
}; | ||
|
||
test('input option cannot be a String when stdin is set', testInputWithStdinError, 'foobar', getStdinOption, execa); | ||
test('input option cannot be a String when stdio is set', testInputWithStdinError, 'foobar', getPlainStdioOption, execa); | ||
test('input option cannot be a String when stdin is set - sync', testInputWithStdinError, 'foobar', getStdinOption, execaSync); | ||
test('input option cannot be a String when stdio is set - sync', testInputWithStdinError, 'foobar', getPlainStdioOption, execaSync); | ||
test('input option cannot be a Node.js Readable when stdin is set', testInputWithStdinError, new Readable(), getStdinOption, execa); | ||
test('input option cannot be a Node.js Readable when stdio is set', testInputWithStdinError, new Readable(), getPlainStdioOption, execa); | ||
|
||
const testInputAndInputFile = async (t, execaMethod) => { | ||
t.throws(() => execaMethod('stdin.js', {inputFile: '', input: ''}), { | ||
message: /cannot be both set/, | ||
}); | ||
}; | ||
|
||
test('inputFile and input cannot be both set', testInputAndInputFile, execa); | ||
test('inputFile and input cannot be both set - sync', testInputAndInputFile, execaSync); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import test from 'ava'; | ||
import {execa, execaSync} from '../../index.js'; | ||
import {setFixtureDir} from '../helpers/fixtures-dir.js'; | ||
import {getStdinOption, getStdoutOption, getStderrOption} from '../helpers/stdio.js'; | ||
|
||
setFixtureDir(); | ||
|
||
const textEncoder = new TextEncoder(); | ||
const binaryFoo = textEncoder.encode('foo'); | ||
const binaryBar = textEncoder.encode('bar'); | ||
|
||
const stringGenerator = function * () { | ||
yield * ['foo', 'bar']; | ||
}; | ||
|
||
const binaryGenerator = function * () { | ||
yield * [binaryFoo, binaryBar]; | ||
}; | ||
|
||
// eslint-disable-next-line require-yield | ||
const throwingGenerator = function * () { | ||
throw new Error('generator error'); | ||
}; | ||
|
||
const testIterable = async (t, stdioOption, fixtureName, getOptions) => { | ||
const {stdout} = await execa(fixtureName, getOptions(stdioOption)); | ||
t.is(stdout, 'foobar'); | ||
}; | ||
|
||
test('stdin option can be a sync iterable of strings', testIterable, ['foo', 'bar'], 'stdin.js', getStdinOption); | ||
test('stdin option can be a sync iterable of Uint8Arrays', testIterable, [binaryFoo, binaryBar], 'stdin.js', getStdinOption); | ||
test('stdin option can be an sync iterable of strings', testIterable, stringGenerator(), 'stdin.js', getStdinOption); | ||
test('stdin option can be an sync iterable of Uint8Arrays', testIterable, binaryGenerator(), 'stdin.js', getStdinOption); | ||
|
||
const testIterableSync = (t, stdioOption, fixtureName, getOptions) => { | ||
t.throws(() => { | ||
execaSync(fixtureName, getOptions(stdioOption)); | ||
}, {message: /an iterable in sync mode/}); | ||
}; | ||
|
||
test('stdin option cannot be a sync iterable - sync', testIterableSync, ['foo', 'bar'], 'stdin.js', getStdinOption); | ||
test('stdin option cannot be an async iterable - sync', testIterableSync, stringGenerator(), 'stdin.js', getStdinOption); | ||
|
||
const testIterableError = async (t, fixtureName, getOptions) => { | ||
const {originalMessage} = await t.throwsAsync(execa(fixtureName, getOptions(throwingGenerator()))); | ||
t.is(originalMessage, 'generator error'); | ||
}; | ||
|
||
test('stdin option handles errors in iterables', testIterableError, 'stdin.js', getStdinOption); | ||
|
||
const testNoIterableOutput = (t, getOptions, execaMethod) => { | ||
t.throws(() => { | ||
execaMethod('noop.js', getOptions(['foo', 'bar'])); | ||
}, {message: /cannot be an iterable/}); | ||
}; | ||
|
||
test('stdout option cannot be an iterable', testNoIterableOutput, getStdoutOption, execa); | ||
test('stderr option cannot be an iterable', testNoIterableOutput, getStderrOption, execa); | ||
test('stdout option cannot be an iterable - sync', testNoIterableOutput, getStdoutOption, execaSync); | ||
test('stderr option cannot be an iterable - sync', testNoIterableOutput, getStderrOption, execaSync); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {once} from 'node:events'; | ||
import {createReadStream, createWriteStream} from 'node:fs'; | ||
import {readFile, writeFile, rm} from 'node:fs/promises'; | ||
import {Readable, Writable, PassThrough} from 'node:stream'; | ||
import test from 'ava'; | ||
import tempfile from 'tempfile'; | ||
import {execa, execaSync} from '../../index.js'; | ||
import {setFixtureDir} from '../helpers/fixtures-dir.js'; | ||
import {getStdinOption, getStdoutOption, getStderrOption, getInputOption} from '../helpers/stdio.js'; | ||
|
||
setFixtureDir(); | ||
|
||
const createNoFileReadable = value => { | ||
const stream = new PassThrough(); | ||
stream.write(value); | ||
stream.end(); | ||
return stream; | ||
}; | ||
|
||
const testNodeStreamSync = (t, StreamClass, getOptions, optionName) => { | ||
t.throws(() => { | ||
execaSync('noop.js', getOptions(new StreamClass())); | ||
}, {message: `The \`${optionName}\` option cannot be a Node.js stream in sync mode.`}); | ||
}; | ||
|
||
test('input cannot be a Node.js Readable - sync', testNodeStreamSync, Readable, getInputOption, 'input'); | ||
|
||
test('input can be a Node.js Readable without a file descriptor', async t => { | ||
const {stdout} = await execa('stdin.js', {input: createNoFileReadable('foobar')}); | ||
t.is(stdout, 'foobar'); | ||
}); | ||
|
||
const testNoFileStream = async (t, getOptions, StreamClass) => { | ||
await t.throwsAsync(execa('noop.js', getOptions(new StreamClass())), {code: 'ERR_INVALID_ARG_VALUE'}); | ||
}; | ||
|
||
test('stdin cannot be a Node.js Readable without a file descriptor', testNoFileStream, getStdinOption, Readable); | ||
test('stdout cannot be a Node.js Writable without a file descriptor', testNoFileStream, getStdoutOption, Writable); | ||
test('stderr cannot be a Node.js Writable without a file descriptor', testNoFileStream, getStderrOption, Writable); | ||
|
||
const createFileReadable = async value => { | ||
const filePath = tempfile(); | ||
await writeFile(filePath, value); | ||
const stream = createReadStream(filePath); | ||
await once(stream, 'open'); | ||
const cleanup = () => rm(filePath); | ||
return {stream, cleanup}; | ||
}; | ||
|
||
const testFileReadable = async (t, fixtureName, getOptions) => { | ||
const {stream, cleanup} = await createFileReadable('foobar'); | ||
try { | ||
const {stdout} = await execa(fixtureName, getOptions(stream)); | ||
t.is(stdout, 'foobar'); | ||
} finally { | ||
await cleanup(); | ||
} | ||
}; | ||
|
||
test('input can be a Node.js Readable with a file descriptor', testFileReadable, 'stdin.js', getInputOption); | ||
test('stdin can be a Node.js Readable with a file descriptor', testFileReadable, 'stdin.js', getStdinOption); | ||
|
||
const createFileWritable = async () => { | ||
const filePath = tempfile(); | ||
const stream = createWriteStream(filePath); | ||
await once(stream, 'open'); | ||
const cleanup = () => rm(filePath); | ||
return {stream, filePath, cleanup}; | ||
}; | ||
|
||
const testFileWritable = async (t, getOptions, fixtureName) => { | ||
const {stream, filePath, cleanup} = await createFileWritable(); | ||
try { | ||
await execa(fixtureName, ['foobar'], getOptions(stream)); | ||
t.is(await readFile(filePath, 'utf8'), 'foobar\n'); | ||
} finally { | ||
await cleanup(); | ||
} | ||
}; | ||
|
||
test('stdout can be a Node.js Writable with a file descriptor', testFileWritable, getStdoutOption, 'noop.js'); | ||
test('stderr can be a Node.js Writable with a file descriptor', testFileWritable, getStderrOption, 'noop-err.js'); |
Oops, something went wrong.