Skip to content

Commit

Permalink
Merge pull request #327 from Fdawgs/refactor/spawn
Browse files Browse the repository at this point in the history
  • Loading branch information
Fdawgs committed Sep 24, 2023
2 parents 0e8db11 + a5e4e2d commit 4f67d04
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 42 deletions.
77 changes: 48 additions & 29 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"use strict";

const { execFile, spawn } = require("node:child_process");
const { promisify } = require("node:util");
const { spawn, spawnSync } = require("node:child_process");
const { readFile } = require("node:fs/promises");
const { gt, lt } = require("semver");
const { joinSafe, normalizeTrim } = require("upath");

const execFileAsync = promisify(execFile);

const errorMessages = {
3221225477: "Segmentation fault",
};
Expand Down Expand Up @@ -77,24 +74,59 @@ function parseOptions(acceptedOptions, options, version) {
}

class UnRTF {
/** @param {string} [binPath] - Path of UnRTF binary. */
/**
* @param {string} [binPath] - Path of UnRTF binary.
* If not provided, the constructor will attempt to find the binary
* in the PATH environment variable.
*
* For `win32`, a binary is bundled with the package and will be used
* if a local installation is not found.
*/
constructor(binPath) {
/* istanbul ignore else: requires specific OS */
if (binPath) {
this.unrtfPath = normalizeTrim(binPath);
} else if (process.platform === "win32") {
this.unrtfPath = joinSafe(
__dirname,
"lib",
"win32",
"unrtf-0.19.3",
"bin"
);
/** @type {string|undefined} */
this.unrtfPath = binPath;
} else {
const { platform } = process;

const which = spawnSync(platform === "win32" ? "where" : "which", [
"unrtf",
]).stdout.toString();
const unrtfPath = /(.+)unrtf/u.exec(which)?.[1];

if (unrtfPath) {
this.unrtfPath = unrtfPath;
}
if (platform === "win32" && !unrtfPath) {
this.unrtfPath = joinSafe(
__dirname,
"lib",
"win32",
"unrtf-0.19.3",
"bin"
);
}
}

if (!this.unrtfPath) {
throw new Error(
`${process.platform} UnRTF binaries are not provided, please pass the installation directory as a parameter to the UnRTF instance.`
`Unable to find ${process.platform} UnRTF binaries, please pass the installation directory as a parameter to the UnRTF instance.`
);
}
this.unrtfPath = normalizeTrim(this.unrtfPath);

/**
* Get version of UnRTF binary for use in `convert` function.
* UnRTF outputs the version into stderr:
* v0.19.3 returns "0.19.3\r\n"
* v0.21.0 returns "0.21.10\nsearch path is: /usr/share/unrtf/\n"
*/
const version = spawnSync(joinSafe(this.unrtfPath, "unrtf"), [
"--version",
]).stderr.toString();
/** @type {string|undefined} */
this.unrtfVersion = /^(\d{1,2}\.\d{1,2}\.\d{1,2})/u.exec(version)?.[1];
}

/**
Expand Down Expand Up @@ -182,20 +214,7 @@ class UnRTF {
);
}

const { stderr } = await execFileAsync(
joinSafe(this.unrtfPath, "unrtf"),
["--version"]
);

/**
* UnRTF outputs the version into stderr:
* v0.19.3 returns "0.19.3\r\n"
* v0.21.0 returns "0.21.10\nsearch path is: /usr/share/unrtf/\n"
*/
// @ts-ignore: parseOptions checks if falsy
const versionInfo = /^(\d{1,2}\.\d{1,2}\.\d{1,2})/u.exec(stderr)[1];

const args = parseOptions(acceptedOptions, options, versionInfo);
const args = parseOptions(acceptedOptions, options, this.unrtfVersion);
args.push(normalizeTrim(file));

return new Promise((resolve, reject) => {
Expand Down
45 changes: 32 additions & 13 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable jest/no-conditional-expect */
/* eslint-disable global-require, jest/no-conditional-expect */

"use strict";

Expand All @@ -15,7 +15,6 @@ const { UnRTF } = require("./index");
const testDirectory = `${__dirname}/../test_resources/test_files/`;
const file = `${testDirectory}test-rtf-complex.rtf`;

const windowsPath = joinSafe(__dirname, "lib", "win32", "unrtf-0.19.3", "bin");
let testBinaryPath;
switch (process.platform) {
// macOS
Expand All @@ -30,14 +29,20 @@ switch (process.platform) {
// Windows OS
case "win32":
default:
testBinaryPath = windowsPath;
testBinaryPath = joinSafe(
__dirname,
"lib",
"win32",
"unrtf-0.19.3",
"bin"
);
break;
}

describe("Constructor", () => {
let platform;

beforeEach(() => {
beforeAll(() => {
// Copy the process platform
({ platform } = process);
});
Expand All @@ -49,27 +54,41 @@ describe("Constructor", () => {
});
});

it("Creates a new UnRTF instance without the binary path set on win32", () => {
Object.defineProperty(process, "platform", {
value: "win32",
});

it("Creates a new UnRTF instance without the binary path set", () => {
const unRtf = new UnRTF();
expect(unRtf.unrtfPath).toBe(windowsPath);
expect(unRtf.unrtfPath).toBe(testBinaryPath);
});

it("Throws an Error if the binary path is not set and the platform is not win32", () => {
/**
* @todo Fix this test, mocking of "node:" scheme not supported yet
* @see {@link https://github.com/jestjs/jest/pull/14297 | Jest PR #14297}
*/
// eslint-disable-next-line jest/no-disabled-tests
it.skip("Throws an Error if the binary path is not found", () => {
Object.defineProperty(process, "platform", {
value: "mockOS",
});

// Ensure the mock is used by the UnRTF constructor
jest.resetModules();
jest.mock("node:child_process", () => ({
spawnSync: jest.fn(() => ({
stdout: {
toString: () => "",
},
})),
}));
// eslint-disable-next-line security/detect-child-process
require("node:child_process");
const { UnRTF: UnRTFMock } = require("./index");

expect.assertions(1);
try {
// eslint-disable-next-line no-unused-vars
const unRtf = new UnRTF();
const unRtf = new UnRTFMock();
} catch (err) {
expect(err.message).toBe(
`${process.platform} UnRTF binaries are not provided, please pass the installation directory as a parameter to the UnRTF instance.`
`Unable to find ${process.platform} UnRTF binaries, please pass the installation directory as a parameter to the UnRTF instance.`
);
}
});
Expand Down

0 comments on commit 4f67d04

Please sign in to comment.