135 lines
3.9 KiB
JavaScript
135 lines
3.9 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
ALLOWED_LICENSES,
|
|
BLOCKED_LICENSE_PATTERNS,
|
|
classifyLicense,
|
|
isReviewed,
|
|
parseLicenseField,
|
|
splitSpdxExpression,
|
|
} from "./verify-licenses.mjs";
|
|
|
|
describe("parseLicenseField", () => {
|
|
it("reads a plain string license", () => {
|
|
expect(parseLicenseField({ license: "MIT" })).toBe("MIT");
|
|
});
|
|
|
|
it("reads the legacy { type } object form", () => {
|
|
expect(parseLicenseField({ license: { type: "Apache-2.0", url: "x" } })).toBe(
|
|
"Apache-2.0",
|
|
);
|
|
});
|
|
|
|
it("collapses a multi-entry `licenses` array into an SPDX OR expression", () => {
|
|
expect(
|
|
parseLicenseField({
|
|
licenses: [{ type: "MIT" }, { type: "Apache-2.0" }],
|
|
}),
|
|
).toBe("(MIT OR Apache-2.0)");
|
|
});
|
|
|
|
it("returns null for an empty package", () => {
|
|
expect(parseLicenseField({})).toBeNull();
|
|
expect(parseLicenseField({ license: "" })).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("splitSpdxExpression", () => {
|
|
it("returns single-atom expressions untouched", () => {
|
|
expect(splitSpdxExpression("MIT")).toEqual(["MIT"]);
|
|
});
|
|
|
|
it("splits parenthesised OR expressions", () => {
|
|
expect(splitSpdxExpression("(MIT OR Apache-2.0)")).toEqual([
|
|
"MIT",
|
|
"Apache-2.0",
|
|
]);
|
|
});
|
|
|
|
it("is case-insensitive on the OR conjunction", () => {
|
|
expect(splitSpdxExpression("MIT or BSD-3-Clause")).toEqual([
|
|
"MIT",
|
|
"BSD-3-Clause",
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("classifyLicense — allowlist", () => {
|
|
it.each([...ALLOWED_LICENSES])("accepts %s", (lic) => {
|
|
expect(classifyLicense(lic)).toBe("allowed");
|
|
});
|
|
|
|
it("treats an OR expression with one allowed atom as allowed", () => {
|
|
expect(classifyLicense("(MIT OR FooLicense-1.0)")).toBe("allowed");
|
|
});
|
|
});
|
|
|
|
describe("classifyLicense — blocklist", () => {
|
|
it.each([
|
|
"GPL-2.0",
|
|
"GPL-3.0-or-later",
|
|
"AGPL-3.0",
|
|
"SSPL-1.0",
|
|
"MIT AND Commons-Clause",
|
|
"LGPL-2.1",
|
|
])("blocks %s", (lic) => {
|
|
expect(classifyLicense(lic)).toBe("blocked");
|
|
});
|
|
|
|
it("blocks an OR expression that contains a blocked atom", () => {
|
|
expect(classifyLicense("(MIT OR GPL-3.0)")).toBe("blocked");
|
|
});
|
|
|
|
it("uses the configured pattern list, not the hardcoded one", () => {
|
|
expect(
|
|
classifyLicense("MIT", {
|
|
allowed: new Set(),
|
|
blockedPatterns: [/^MIT$/],
|
|
}),
|
|
).toBe("blocked");
|
|
});
|
|
});
|
|
|
|
describe("classifyLicense — unknown", () => {
|
|
it("returns 'unknown' for a missing license", () => {
|
|
expect(classifyLicense(null)).toBe("unknown");
|
|
});
|
|
|
|
it("returns 'unknown' for a license string we have no opinion on", () => {
|
|
expect(classifyLicense("Some-Bespoke-License-1.0")).toBe("unknown");
|
|
});
|
|
|
|
it("does not treat a partial blocklist match as blocked", () => {
|
|
// "NotGPL" must not match /^GPL-/
|
|
expect(classifyLicense("NotGPL-Public-1.0")).toBe("unknown");
|
|
});
|
|
});
|
|
|
|
describe("baseline allowlist", () => {
|
|
it("recognises an entry by exact name@version key", () => {
|
|
const baseline = { "moment@2.29.4": "legacy MIT shim, reviewed" };
|
|
expect(isReviewed(baseline, "moment", "2.29.4")).toBe(true);
|
|
expect(isReviewed(baseline, "moment", "2.29.5")).toBe(false);
|
|
});
|
|
|
|
it("ignores unrelated metadata keys without throwing", () => {
|
|
const baseline = { __doc__: "header", "react@19.2.3": "ok" };
|
|
expect(isReviewed(baseline, "react", "19.2.3")).toBe(true);
|
|
expect(isReviewed(baseline, "anything-else", "1.0.0")).toBe(false);
|
|
});
|
|
|
|
it("treats an empty/missing baseline as no exceptions", () => {
|
|
expect(isReviewed({}, "react", "19.2.3")).toBe(false);
|
|
expect(isReviewed(null, "react", "19.2.3")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("BLOCKED_LICENSE_PATTERNS export", () => {
|
|
it("contains the headline copyleft families", () => {
|
|
const blob = BLOCKED_LICENSE_PATTERNS.map(String).join("|");
|
|
expect(blob).toMatch(/GPL/);
|
|
expect(blob).toMatch(/AGPL/);
|
|
expect(blob).toMatch(/SSPL/);
|
|
expect(blob).toMatch(/Commons-Clause/);
|
|
});
|
|
});
|