Files
healer-man/scripts/coa-source-policy.test.mjs
T

115 lines
5.0 KiB
JavaScript

import assert from "node:assert/strict";
import path from "node:path";
import test from "node:test";
import {
collectRealmSpellIds,
expandCoaSpellIds,
resolveCoaSourcePaths,
sharedRealmSpellIds,
} from "./coa-source-policy.mjs";
test("CoA payload closure includes effect-168 links, cycles and absent IDs without overlay fallback", () => {
const buffer = Buffer.alloc(20 + 3 * 234 * 4);
buffer.write("WDBC");
buffer.writeUInt32LE(3, 4);
buffer.writeUInt32LE(234, 8);
buffer.writeUInt32LE(234 * 4, 12);
const write = (row, field, value) => buffer.writeUInt32LE(value, 20 + (row * 234 + field) * 4);
write(0, 0, 100);
write(0, 71, 168);
write(0, 110, 200);
write(1, 0, 200);
write(1, 116, 300);
write(2, 0, 300);
write(2, 116, 100);
write(2, 117, 400);
assert.deepEqual([...expandCoaSpellIds(buffer, [100])], [100, 200, 300, 400]);
assert.throws(() => expandCoaSpellIds(Buffer.from("invalid"), [100]), /234-field/);
});
test("CoA source resolution selects global patch-T and patch-M while classic keeps Area52 priority", () => {
const root = path.resolve("fixture/client-current");
const legacy = path.resolve("fixture/legacy");
const exists = new Set([
path.join(root, "area-52", "patch-D", "DBFilesClient", "Spell.dbc"),
path.join(root, "area-52", "patch-D", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(root, "patch-T", "DBFilesClient", "Spell.dbc"),
path.join(root, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(legacy, "patch-T", "DBFilesClient", "Spell.dbc"),
path.join(legacy, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"),
]);
const sources = resolveCoaSourcePaths({
extractedClientRoot: root,
legacyExtractedRoot: legacy,
exists: (candidate) => exists.has(candidate),
});
assert.equal(sources.classicSpellDbcPath, path.join(root, "area-52", "patch-D", "DBFilesClient", "Spell.dbc"));
assert.equal(sources.classicSkillLineAbilityDbcPath, path.join(root, "area-52", "patch-D", "DBFilesClient", "SkillLineAbility.dbc"));
assert.equal(sources.coaSpellDbcPath, path.join(root, "patch-T", "DBFilesClient", "Spell.dbc"));
assert.equal(sources.coaSkillLineAbilityDbcPath, path.join(root, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"));
});
test("CoA sources fall back only to global legacy files, never Area52", () => {
const root = path.resolve("fixture/client-current");
const legacy = path.resolve("fixture/legacy");
const exists = new Set([
path.join(root, "area-52", "patch-D", "DBFilesClient", "Spell.dbc"),
path.join(root, "area-52", "patch-D", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(legacy, "patch-T", "DBFilesClient", "Spell.dbc"),
path.join(legacy, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"),
]);
const sources = resolveCoaSourcePaths({
extractedClientRoot: root,
legacyExtractedRoot: legacy,
exists: (candidate) => exists.has(candidate),
});
assert.equal(sources.coaSpellDbcPath, path.join(legacy, "patch-T", "DBFilesClient", "Spell.dbc"));
assert.equal(sources.coaSkillLineAbilityDbcPath, path.join(legacy, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"));
});
test("classic SkillLineAbility follows the selected Spell.dbc when that sibling exists", () => {
const root = path.resolve("fixture/client-current");
const legacy = path.resolve("fixture/legacy");
const exists = new Set([
path.join(root, "area-52", "patch-D", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(root, "patch-T", "DBFilesClient", "Spell.dbc"),
path.join(root, "patch-T", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(root, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"),
path.join(legacy, "patch-T", "DBFilesClient", "Spell.dbc"),
path.join(legacy, "patch-M", "DBFilesClient", "SkillLineAbility.dbc"),
]);
const sources = resolveCoaSourcePaths({
extractedClientRoot: root,
legacyExtractedRoot: legacy,
exists: (candidate) => exists.has(candidate),
});
assert.equal(sources.classicSpellDbcPath, path.join(root, "patch-T", "DBFilesClient", "Spell.dbc"));
assert.equal(sources.classicSkillLineAbilityDbcPath, path.join(root, "patch-T", "DBFilesClient", "SkillLineAbility.dbc"));
});
test("realm spell ownership protects classic references and includes CoA tree ranks", () => {
const { classicIds, coaIds } = collectRealmSpellIds({
classicClassIds: [11],
coaClassIds: [27],
classSpellRows: [
{ id: 100, classId: 11 },
{ id: 200, classId: 27 },
{ id: 300, classId: 27 },
{ id: 400, classId: 11 },
{ id: 400, classId: 27 },
],
classicRankCandidates: [{ id: 101 }],
coaRankCandidates: [{ id: 201 }],
coaEntrySpellIds: [300, 301],
});
assert.deepEqual([...classicIds].sort(), [100, 101, 400]);
assert.deepEqual([...coaIds].sort(), [200, 201, 300, 301, 400]);
assert.ok(classicIds.has(100) && coaIds.has(300) && classicIds.has(400) && coaIds.has(400));
assert.deepEqual(sharedRealmSpellIds(classicIds, coaIds), [400]);
assert.deepEqual(sharedRealmSpellIds(new Set([401]), new Set([401])), [401]);
});