diff --git a/spec/cli_spec.js b/spec/cli_spec.js new file mode 100644 index 00000000..eb6215fd --- /dev/null +++ b/spec/cli_spec.js @@ -0,0 +1,40 @@ +"use strict"; + +import { spawnSync } from "child_process"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const cliPath = path.join(__dirname, "../src/cli/cli.js"); +const missingPath = path.join(__dirname, "assets/does-not-exist.xml"); + +function runCli(args, input) { + return spawnSync(process.execPath, [cliPath, ...args], { input, encoding: "utf8" }); +} + +describe("CLI", function() { + + it("should parse xml from stdin", function() { + const result = runCli([], "1"); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual({ a: 1 }); + }); + + it("should report a missing input file instead of crashing", function() { + const result = runCli([missingPath]); + + expect(result.status).toBe(1); + expect(result.stdout).toContain("Seems an invalid file or stream."); + expect(result.stdout).toContain("ENOENT"); + expect(result.stderr).not.toContain("throw err"); + }); + + it("should report an unwritable output file instead of crashing", function() { + const result = runCli(["-o", path.join(missingPath, "out.json")], "1"); + + expect(result.status).toBe(1); + expect(result.stdout).toContain("Seems an invalid file or stream."); + expect(result.stderr).not.toContain("throw err"); + }); +}); diff --git a/src/cli/cli.js b/src/cli/cli.js index b4773e40..6b3effba 100755 --- a/src/cli/cli.js +++ b/src/cli/cli.js @@ -70,27 +70,37 @@ if (process.argv[2] === '--help' || process.argv[2] === '-h') { if (!fileName) { ReadToEnd.readToEnd(process.stdin, function(err, data) { if (err) { - throw err; + onError(err); + return; } callback(data.toString()); }); } else { fs.readFile(fileName, function(err, data) { if (err) { - throw err; + onError(err); + return; } callback(data.toString()); }); } } catch (e) { - console.log('Seems an invalid file or stream.' + e); + onError(e); } } +// errors raised inside async callbacks are not caught by the try/catch above, +// so they are reported here instead of being thrown +function onError(err) { + console.log('Seems an invalid file or stream.' + err); + process.exitCode = 1; +} + function writeToFile(fileName, data) { fs.writeFile(fileName, data, function(err) { if (err) { - throw err; + onError(err); + return; } console.log('JSON output has been written to ' + fileName); });