diff --git a/src/cli.ts b/src/cli.ts index 46c7661a..5e48d256 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -93,6 +93,8 @@ const yargs = require('yargs') .default('e', 'utf8') .alias('e', 'encoding') .describe('e', 'Encoding of files/piped data.') + // Not .choices() as node takes the name of an encoding in any case, like `UTF8` + .check((argv) => Buffer.isEncoding(argv.encoding) || `Unknown encoding: ${argv.encoding}`) .alias('E', 'engine') .describe( diff --git a/src/engine.ts b/src/engine.ts index 6cb51667..da504e35 100644 --- a/src/engine.ts +++ b/src/engine.ts @@ -26,9 +26,16 @@ export {version} from '../package.json'; const runtime = process.versions.bun ? 'Bun' : 'Node'; const runtimeEngine = process.versions.bun ? 'JSC' : 'V8'; +function validateEncoding(encoding = 'utf8') { + if (!Buffer.isEncoding(encoding)) { + die('Unknown encoding:', encoding); + } +} + // Returns a promise that resolves when all files are done export async function engine(config: any = {engine: 'default'}) { outputConfig(config); + validateEncoding(config.encoding); step('Displaying steps for:'); step(config); diff --git a/test/cli/run.sh b/test/cli/run.sh index 3454688c..593f634c 100644 --- a/test/cli/run.sh +++ b/test/cli/run.sh @@ -130,6 +130,16 @@ else fi +# -e +# An unknown encoding stops the run with an error, both for files and for piped data (#690) +reset +assert_failure "rexreplace o x my.file -e nope" +assert "cat my.file" 'foobar' +assert_failure "printf foo | rexreplace o x -e nope" +assert "printf foo | rexreplace o x -e nope 2>&1 | grep -v 'exited with code' | tail -1" 'Unknown encoding: nope' +assert "printf foo | rexreplace o x -e LATIN1" 'fxx' + + # -b reset rexreplace o x my.file --keep-backup diff --git a/test/js/encoding.test.js b/test/js/encoding.test.js index 8d7d665f..60561781 100644 --- a/test/js/encoding.test.js +++ b/test/js/encoding.test.js @@ -49,15 +49,26 @@ describe('--encoding', () => { ); }); - test.todo( - 'BUG #690: an unknown encoding gives an error message instead of crashing', - async () => { - fs.writeFileSync('my.file', 'foobar'); - const result = await rr('o', 'x', {includeGlob: ['my.file'], encoding: 'nope'}); - expect(result.exit).toBe(1); - expect(result.err).toContain('nope'); - } - ); + // The error message, and not the stack trace from deep inside node, when an encoding is unknown (#690) + const unknownEncoding = {out: '', err: ' ❌ Unknown encoding: nope\n\n', exit: 1}; + + test('stops the run with an error if it is unknown (#690)', async () => { + fs.writeFileSync('my.file', 'foobar'); + expect(await rr('o', 'x', {includeGlob: ['my.file'], encoding: 'nope'})).toEqual( + unknownEncoding + ); + expect(fs.readFileSync('my.file', 'utf8')).toBe('foobar'); + }); + + test('stops the run with an error if it is unknown, also for piped data (#690)', async () => { + expect(await rr('o', 'x', {pipedData: 'foo', encoding: 'nope'})).toEqual(unknownEncoding); + }); + + test('is known in any case', async () => { + fs.writeFileSync('my.file', latin1()); + await rr('æ', 'ø', {includeGlob: ['my.file'], encoding: 'LATIN1'}); + expect(fs.readFileSync('my.file')).toEqual(Buffer.from([0x66, 0xf8, 0x6f])); + }); describe('combined', () => { test.each([