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/); }); });