diff --git a/tests/unit/games/minecraft/minecraft-version-lookup.spec.ts b/tests/unit/games/minecraft/minecraft-version-lookup.spec.ts new file mode 100644 index 0000000..56e08e8 --- /dev/null +++ b/tests/unit/games/minecraft/minecraft-version-lookup.spec.ts @@ -0,0 +1,169 @@ +import { parseVersion } from "@/utils/versioning/version"; +import { MinecraftVersion } from "@/games/minecraft/minecraft-version"; +import { MinecraftVersionType } from "@/games/minecraft/minecraft-version-type"; +import { getMinecraftVersionRegExp, normalizeMinecraftVersion, normalizeMinecraftVersionRange } from "@/games/minecraft/minecraft-version-lookup"; + +describe("normalizeMinecraftVersion", () => { + test("return a normalized version as is", () => { + expect(normalizeMinecraftVersion("1.16.5")).toBe("1.16.5"); + expect(normalizeMinecraftVersion("1.17")).toBe("1.17"); + expect(normalizeMinecraftVersion("2.0")).toBe("2.0"); + expect(normalizeMinecraftVersion("1.8.4-alpha.15.14.a+loveandhugs")).toBe("1.8.4-alpha.15.14.a+loveandhugs"); + expect(normalizeMinecraftVersion("1.16-alpha.20.13.inf")).toBe("1.16-alpha.20.13.inf"); + expect(normalizeMinecraftVersion("1.19.4-rc.3")).toBe("1.19.4-rc.3"); + expect(normalizeMinecraftVersion("1.17.1-pre.3")).toBe("1.17.1-pre.3"); + }); + + test("normalizes snapshots", () => { + const manifest = [ + { id: "90w03a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "1.16.5", type: MinecraftVersionType.RELEASE, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "1.16.5-rc1", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "20w51a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "20w49a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "20w48a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "20w46a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "20w45a", type: MinecraftVersionType.SNAPSHOT, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + { id: "1.16.4", type: MinecraftVersionType.RELEASE, url: "", time: "", releaseTime: "", releaseDate: new Date(), sha1: "", complianceLevel: 1 }, + ]; + + expect(normalizeMinecraftVersion("90w03a", manifest, 0)).toBe("1.16.6-alpha.90.3.a"); + expect(normalizeMinecraftVersion("20w51a", manifest, 2)).toBe("1.16.5-alpha.20.51.a"); + }); + + test("normalizes April Fools' releases", () => { + expect(normalizeMinecraftVersion("1.RV-Pre1")).toBe("1.9.2-rv+trendy"); + expect(normalizeMinecraftVersion("15w14a")).toBe("1.8.4-alpha.15.14.a+loveandhugs"); + expect(normalizeMinecraftVersion("20w14~")).toBe("1.16-alpha.20.13.inf"); + expect(normalizeMinecraftVersion("20w14infinite")).toBe("1.16-alpha.20.13.inf"); + expect(normalizeMinecraftVersion("22w13oneblockatatime")).toBe("1.19-alpha.22.13.oneblockatatime"); + expect(normalizeMinecraftVersion("23w13a_or_b")).toBe("1.20-alpha.23.13.ab"); + expect(normalizeMinecraftVersion("3D Shareware v1.34")).toBe("1.14-alpha.19.13.shareware"); + expect(normalizeMinecraftVersion("2point0_red")).toBe("1.5.2-red"); + expect(normalizeMinecraftVersion("2point0_blue")).toBe("1.5.2-blue"); + expect(normalizeMinecraftVersion("2point0_purple")).toBe("1.5.2-purple"); + }); + + test("normalizes legacy releases", () => { + expect(normalizeMinecraftVersion("rd-20090515")).toBe("0.0.0-rd.150000"); + expect(normalizeMinecraftVersion("rd-161348")).toBe("0.0.0-rd.161348"); + expect(normalizeMinecraftVersion("inf-20100618")).toBe("0.31.20100618"); + expect(normalizeMinecraftVersion("c0.30_01c")).toBe("0.30.1-c"); + expect(normalizeMinecraftVersion("c0.0.13a")).toBe("0.0.13-a"); + expect(normalizeMinecraftVersion("c0.0.13a_03")).toBe("0.0.13-a.3"); + expect(normalizeMinecraftVersion("a1.0.4")).toBe("1.0.0-alpha.0.4"); + expect(normalizeMinecraftVersion("a1.0.5_01")).toBe("1.0.0-alpha.0.5.1"); + expect(normalizeMinecraftVersion("a1.0.17_04")).toBe("1.0.0-alpha.0.17.4"); + expect(normalizeMinecraftVersion("b1.5_01")).toBe("1.0.0-beta.5.1"); + expect(normalizeMinecraftVersion("b1.6")).toBe("1.0.0-beta.6"); + expect(normalizeMinecraftVersion("b1.8.1")).toBe("1.0.0-beta.8.1"); + }); +}); + +describe("normalizeMinecraftVersionRange", () => { + test("returns a normalized version range", () => { + const versions = new Map([ + new MinecraftVersion("21w03a", parseVersion("1.17-alpha.21.3.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("1.16.5", parseVersion("1.16.5"), MinecraftVersionType.RELEASE, "", new Date()), + new MinecraftVersion("1.16.5-rc1", parseVersion("1.16.5-rc.1"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("20w51a", parseVersion("1.16.5-alpha.20.51.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("20w49a", parseVersion("1.16.5-alpha.20.49.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("20w48a", parseVersion("1.16.5-alpha.20.48.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("20w46a", parseVersion("1.16.5-alpha.20.46.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("20w45a", parseVersion("1.16.5-alpha.20.45.a"), MinecraftVersionType.SNAPSHOT, "", new Date()), + new MinecraftVersion("1.16.4", parseVersion("1.16.4"), MinecraftVersionType.RELEASE, "", new Date()), + ].map(x => [x.id, x])); + const versionRegex = getMinecraftVersionRegExp(versions.keys()); + + const normalize = (x : Iterable) => normalizeMinecraftVersionRange(x, versions, versionRegex); + + expect(normalize(">1.16.4 <=1.16.5").includes("1.16.3")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5").includes("1.16.4")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5").includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize(">1.16.4 <=1.16.5").includes("1.17")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5").includes("1.17-alpha.21.3.a")).toBe(false); + + expect(normalize([">1.16.4 <=1.16.5"]).includes("1.16.3")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5"]).includes("1.16.4")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5"]).includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize([">1.16.4 <=1.16.5"]).includes("1.17")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5"]).includes("1.17-alpha.21.3.a")).toBe(false); + + expect(normalize(">1.16.4 <=1.16.5 || 1.16.4").includes("1.16.3")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5 || 1.16.4").includes("1.16.4")).toBe(true); + expect(normalize(">1.16.4 <=1.16.5 || 1.16.4").includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize(">1.16.4 <=1.16.5 || 1.16.4").includes("1.17")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5 || 1.16.4").includes("1.17-alpha.21.3.a")).toBe(false); + + expect(normalize([">1.16.4 <=1.16.5", "1.16.4"]).includes("1.16.3")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5", "1.16.4"]).includes("1.16.4")).toBe(true); + expect(normalize([">1.16.4 <=1.16.5", "1.16.4"]).includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize([">1.16.4 <=1.16.5", "1.16.4"]).includes("1.17")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5", "1.16.4"]).includes("1.17-alpha.21.3.a")).toBe(false); + + expect(normalize(">1.16.4 <=1.16.5 || 21w03a").includes("1.16.3")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5 || 21w03a").includes("1.16.4")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5 || 21w03a").includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize(">1.16.4 <=1.16.5 || 21w03a").includes("1.17")).toBe(false); + expect(normalize(">1.16.4 <=1.16.5 || 21w03a").includes("1.17-alpha.21.3.a")).toBe(true); + + expect(normalize([">1.16.4 <=1.16.5", "21w03a"]).includes("1.16.3")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5", "21w03a"]).includes("1.16.4")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5", "21w03a"]).includes("1.16.5-alpha.20.45.a")).toBe(true); + expect(normalize([">1.16.4 <=1.16.5", "21w03a"]).includes("1.17")).toBe(false); + expect(normalize([">1.16.4 <=1.16.5", "21w03a"]).includes("1.17-alpha.21.3.a")).toBe(true); + }); +}); + +describe("getMinecraftVersionRegExp", () => { + test("matches releases", () => { + const regex = getMinecraftVersionRegExp(); + + expect(regex.test("1.16.5")).toBe(true); + expect(regex.test("1.17")).toBe(true); + expect(regex.test("1.18")).toBe(true); + expect(regex.test("1.20.4")).toBe(true); + expect(regex.test("2.0.0")).toBe(true); + expect(regex.test("1.0")).toBe(true); + }); + + test("matches snapshots", () => { + const regex = getMinecraftVersionRegExp(); + + expect(regex.test("1.20.4-rc1")).toBe(true); + expect(regex.test("1.19-pre5")).toBe(true); + expect(regex.test("20w48a")).toBe(true); + expect(regex.test("15w43c")).toBe(true); + expect(regex.test("1.14.2 Pre-Release 4")).toBe(true); + expect(regex.test("13w21b")).toBe(true); + }); + + test("matches legacy releases", () => { + const regex = getMinecraftVersionRegExp(); + + expect(regex.test("rd-20090515")).toBe(true); + expect(regex.test("rd-161348")).toBe(true); + expect(regex.test("inf-20100618")).toBe(true); + expect(regex.test("c0.30_01c")).toBe(true); + expect(regex.test("c0.0.13a")).toBe(true); + expect(regex.test("c0.0.13a_03")).toBe(true); + expect(regex.test("a1.0.4")).toBe(true); + expect(regex.test("a1.0.5_01")).toBe(true); + expect(regex.test("a1.0.17_04")).toBe(true); + expect(regex.test("b1.5_01")).toBe(true); + expect(regex.test("b1.6")).toBe(true); + expect(regex.test("b1.8.1")).toBe(true); + }); + + test("matches additionally provided versions", () => { + const versions = [ + "10w10twoblocksatatime", + "4D Shareware v2.45", + "This is a Minecraft version", + ]; + + const regex = getMinecraftVersionRegExp(versions); + + versions.forEach(x => expect(x.match(regex)).toBeTruthy()); + }); +});