import { describe, expect, it } from "vitest"; import { implausibleSubstats, inferRarity, isPlausibleSubstat, isPlausibleSubstatValue, parseSubstatEntry, possibleSubstatRollCounts, } from "./substatRolls"; describe("substatRolls parsing", () => { it("parses percent and flat entries", () => { expect(parseSubstatEntry("CRIT DMG+13.2%")).toEqual({ stat: "CRIT DMG", value: 13.2, percent: true }); expect(parseSubstatEntry("HP+1,509")).toEqual({ stat: "HP", value: 1509, percent: false }); expect(parseSubstatEntry("garbage")).toBeNull(); }); }); describe("substatRolls plausibility", () => { it("reports possible roll counts for artifact-level consistency checks", () => { expect(possibleSubstatRollCounts("DEF%+11.7%")).toContain(2); expect(possibleSubstatRollCounts("DEF%+31.7%")).toContain(6); expect(possibleSubstatRollCounts("HP+1,165")).toContain(4); expect(possibleSubstatRollCounts("CRIT Rate+2.3%", 5)).toEqual([]); expect(possibleSubstatRollCounts("CRIT Rate+2.3%", 4)).toEqual([1]); }); it("accepts real single-roll values (5-star)", () => { expect(isPlausibleSubstatValue("CRIT DMG", 7.8)).toBe(true); // 7.77 high roll expect(isPlausibleSubstatValue("CRIT DMG", 5.4)).toBe(true); // 5.44 low roll expect(isPlausibleSubstatValue("CRIT Rate", 3.9)).toBe(true); // 3.89 expect(isPlausibleSubstatValue("ATK", 19)).toBe(true); // 19.45 expect(isPlausibleSubstatValue("HP", 269)).toBe(true); // 268.88 }); it("accepts multi-roll sums", () => { expect(isPlausibleSubstat("CRIT DMG+13.2%")).toBe(true); // 5.44+7.77 or 6.22+6.99 expect(isPlausibleSubstat("Elemental Mastery+68")).toBe(true); expect(isPlausibleSubstat("Energy Recharge+11.7%")).toBe(true); expect(isPlausibleSubstat("CRIT Rate+2.3%", 5)).toBe(false); expect(isPlausibleSubstat("CRIT Rate+2.3%", 4)).toBe(true); }); it("rejects values that fit no roll combination at either rarity (OCR misreads)", () => { // 8.1% CRIT DMG sits in the gap: single roll maxes at 7.8 (5-star), and the // smallest two-roll sum is 8.2 (4-star), so it is unreachable at both. expect(isPlausibleSubstatValue("CRIT DMG", 8.1)).toBe(false); // 3.5% CRIT DMG is below the lowest possible roll at either rarity. expect(isPlausibleSubstatValue("CRIT DMG", 3.5)).toBe(false); // A dropped digit on flat ATK. expect(isPlausibleSubstatValue("ATK", 5)).toBe(false); }); it("does not flag unknown stats", () => { expect(isPlausibleSubstatValue("Mystery Stat", 12.3)).toBe(true); }); it("collects the implausible entries from a substat list", () => { const bad = implausibleSubstats(["CRIT DMG+13.2%", "CRIT DMG+8.1%", "ATK+19"]); expect(bad).toEqual(["CRIT DMG+8.1%"]); expect(implausibleSubstats(["CRIT Rate+2.3%"], 5)).toEqual(["CRIT Rate+2.3%"]); }); }); describe("substatRolls rarity inference", () => { it("is 5-star for any artifact leveled past +16", () => { expect(inferRarity(20, ["ATK%+3.5%"])).toBe(5); expect(inferRarity(17, [])).toBe(5); }); it("detects 5-star from a substat that only fits the 5-star table", () => { // 7.8% CRIT DMG is a 5-star single high roll; not reachable at 4-star. expect(inferRarity(12, ["CRIT DMG+7.8%"])).toBe(5); }); it("detects 4-star from a substat that only fits the 4-star table", () => { // 4.1% CRIT DMG is a 4-star single low roll; below any 5-star roll. expect(inferRarity(12, ["CRIT DMG+4.1%"])).toBe(4); }); it("defaults to 5-star when ambiguous", () => { expect(inferRarity(8, [])).toBe(5); }); });