Skip to content

Commit

Permalink
Parse outputs of beta toolchain: add unit and integration tests for t…
Browse files Browse the repository at this point in the history
…he regression (#30)
  • Loading branch information
placintaalexandru authored Nov 14, 2023
1 parent 949faea commit 3a3c546
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI Test - install stable & nightly
name: CI Test - install stable, nightly, and beta
on:
push:
branches:
Expand Down Expand Up @@ -28,6 +28,7 @@ jobs:
toolchain:
- stable
- nightly
- beta
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -58,6 +59,7 @@ jobs:
toolchain:
- stable
- nightly
- beta
# Docker image, not the GitHub Actions VM
container: ubuntu:latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions src/output.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Output } from "./types";
import { execStdout } from "./utils/exec";
import * as execUtils from "./utils/exec";
import * as core from "@actions/core";

export class Outputs {
Expand All @@ -20,58 +20,63 @@ export class Outputs {
* @param{string[]} args - list of arguments the executable accepts.
* @param{RegExp} r - regular expression used to extract the desired piece of the command's output.
* @param{string} outputName - name of the output.
* @param matchIndex{number} - index of the match in the regular expression.
* @returns{Promise<Output>} - absolute path to the toolchain file.
*/
static parseCmdOutputWithRegex = async (
exe: string,
args: string[],
r: RegExp,
outputName: string,
matchIndex: number,
): Promise<Output> => {
const stdout = await execStdout(exe, args);
const stdout = await execUtils.execStdout(exe, args);

core.debug(
`Command: ${exe}\nArgs:${args.toString()}\nOutput: ${stdout}`,
);

const match = stdout.match(r);

if (!match || !match[1]) {
if (!match || matchIndex >= match.length) {
const msg = `Could not match ${stdout}`;
core.error(msg);
throw new Error(msg);
}

return Promise.resolve({
name: outputName,
value: match[1],
value: match[matchIndex],
});
};

static rustc = async (): Promise<Output> => {
return await Outputs.parseCmdOutputWithRegex(
"rustc",
["-V"],
/rustc (\d+\.\d+\.\d+(-nightly)?)/,
/rustc (\d+\.\d+\.\d+(-nightly|-beta\.\d+)?)/,
"rustc",
1,
);
};

static rustcHash = async (): Promise<Output> => {
return await Outputs.parseCmdOutputWithRegex(
"rustc",
["-V"],
/rustc \d+\.\d+\.\d+(?:-\w+)? \((\w+) \d+-\d+-\d+\)/,
/rustc (\d+\.\d+\.\d+(-nightly|-beta\.\d+)?) \((\w+) \d+-\d+-\d+\)/,
"rustc_hash",
3,
);
};

static cargo = async (): Promise<Output> => {
return await Outputs.parseCmdOutputWithRegex(
"cargo",
["-V"],
/cargo (\d+\.\d+\.\d+(-nightly)?) \(.+ (\d{4}-\d{2}-\d{2})\)/,
/cargo (\d+\.\d+\.\d+(-nightly|-beta\.\d+)?) \(.+ (\d{4}-\d{2}-\d{2})\)/,
"cargo",
1,
);
};

Expand All @@ -81,6 +86,7 @@ export class Outputs {
["-V"],
/rustup (\d+\.\d+\.\d+) \(.+\)/,
"rustup",
1,
);
};
}
73 changes: 49 additions & 24 deletions tests/output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as mockedExecUtils from "../src/utils/exec";
jest.mock("@actions/core", () => ({
info: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
}));
describe("Outputs tests", () => {
afterEach(() => {
Expand All @@ -14,6 +15,7 @@ describe("Outputs tests", () => {
for (const stdout of [
"rustc 1.75.0-nightly (aa1a71e9e 2023-10-26)",
"rustc 1.75.0 (aa1a71e9e 2023-10-26)",
"rustc 1.75.0-beta.1 (782883f60 2023-11-12)",
]) {
jest.spyOn(mockedExecUtils, "execStdout").mockReturnValue(
Promise.resolve(stdout),
Expand All @@ -27,6 +29,7 @@ describe("Outputs tests", () => {
for (const stdout of [
"rustc 1.75.0-nightly (aa1a71e9e 2023-10-26)",
"rustc 1.75.0 (aa1a71e9e 2023-10-26)",
"rustc 1.75.0-beta.1 (782883f60 2023-11-12)",
]) {
jest.spyOn(mockedExecUtils, "execStdout").mockReturnValue(
Promise.resolve(stdout),
Expand All @@ -42,6 +45,7 @@ describe("Outputs tests", () => {
for (const stdout of [
"cargo 1.75.0-nightly (df3509237 2023-10-24)",
"cargo 1.75.0 (df3509237 2023-10-24)",
"cargo 1.75.0-beta.1 (6790a5127 2023-11-10)",
]) {
jest.spyOn(mockedExecUtils, "execStdout").mockReturnValue(
Promise.resolve(stdout),
Expand All @@ -66,29 +70,26 @@ describe("Outputs tests", () => {
});

test("All", async () => {
jest.spyOn(Outputs, "rustc").mockReturnValue(
Promise.resolve({
name: "rustc",
value: "rustc",
}),
);
jest.spyOn(Outputs, "rustcHash").mockReturnValue(
Promise.resolve({
name: "rustc_hash",
value: "rustcHash",
}),
);
jest.spyOn(Outputs, "cargo").mockReturnValue(
Promise.resolve({
name: "cargo",
value: "cargo",
}),
);
jest.spyOn(Outputs, "rustUp").mockReturnValue(
Promise.resolve({
name: "rustup",
value: "rustup",
}),
jest.spyOn(mockedExecUtils, "execStdout").mockImplementation(
async (exe) => {
if (exe === "rustc") {
return Promise.resolve(
"rustc 1.75.0-beta.1 (782883f60 2023-11-12)",
);
} else if (exe === "cargo") {
return Promise.resolve(
"cargo 1.75.0-nightly (df3509237 2023-10-24)",
);
} else if (exe === "rustup") {
return Promise.resolve(
"rustup 1.26.0 (5af9b9484 2023-04-05)\n" +
"info: This is the version for the rustup toolchain manager, not the rustc compiler.\n" +
"info: The currently active `rustc` version is `rustc 1.75.0-nightly (aa1a71e9e 2023-10-26)`",
);
}

throw new Error("Unexpected exe");
},
);

expect(
Expand All @@ -97,6 +98,30 @@ describe("Outputs tests", () => {
return output.value;
})
.toString(),
).toBe(["rustc", "rustcHash", "cargo", "rustup"].toString());
).toBe(
[
"1.75.0-beta.1",
"782883f60",
"1.75.0-nightly",
"1.26.0",
].toString(),
);
});

test("Error when not possible to match", async () => {
const rustcVersion = "blah blah";
const expectedMessage = `Could not match ${rustcVersion}`;
let threwError = false;

jest.spyOn(mockedExecUtils, "execStdout").mockReturnValue(
Promise.resolve(rustcVersion),
);

await Outputs.outputs().catch((e: Error) => {
expect(e.message).toBe(expectedMessage);
threwError = true;
});

expect(threwError).toBe(true);
});
});
7 changes: 3 additions & 4 deletions tests/utils/toolchain.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { describe } from "jest-circus";
import * as utils from "../../src/utils/toolchain";
import * as mockedFs from "fs";
import fs from "fs";

jest.mock("fs");

Expand Down Expand Up @@ -38,7 +37,7 @@ describe("Tests of toolchain utils", () => {
profile = "${profile}"
`;

(fs.readFileSync as jest.Mock).mockReturnValue(tomlData);
(mockedFs.readFileSync as jest.Mock).mockReturnValue(tomlData);
const toolchainArgs = utils.toolchainArgs("");

expect(toolchainArgs.toolchain).toBe(toolchain);
Expand All @@ -53,7 +52,7 @@ describe("Tests of toolchain utils", () => {
const tomlData = `
[toolchain]
`;
(fs.readFileSync as jest.Mock).mockReturnValue(tomlData);
(mockedFs.readFileSync as jest.Mock).mockReturnValue(tomlData);
const toolchainArgs = utils.toolchainArgs("");

expect(toolchainArgs.toolchain == null);
Expand All @@ -64,7 +63,7 @@ describe("Tests of toolchain utils", () => {

test("File is empty", () => {
const tomlData = "";
(fs.readFileSync as jest.Mock).mockReturnValue(tomlData);
(mockedFs.readFileSync as jest.Mock).mockReturnValue(tomlData);
const toolchainArgs = utils.toolchainArgs("");

expect(toolchainArgs.toolchain == null);
Expand Down

0 comments on commit 3a3c546

Please sign in to comment.