Files
5etools-mirror-2.github.io/test/test-foundry.js
TheGiddyLimit 8117ebddc5 v1.198.1
2024-01-01 19:34:49 +00:00

166 lines
5.8 KiB
JavaScript

import * as fs from "fs";
import * as ut from "../node/util.js";
import "../js/parser.js";
import "../js/utils.js";
import "../js/render.js";
import "../js/render-dice.js";
class TestFoundry {
static async pLoadData (originalFilename, originalPath) {
switch (originalFilename) {
case "races.json": {
ut.patchLoadJson();
const out = await DataUtil.race.loadJSON({isAddBaseRaces: true});
ut.unpatchLoadJson();
return out;
}
default: return ut.readJson(originalPath);
}
}
static testClasses ({errors}) {
const classIndex = ut.readJson("./data/class/index.json");
const classFiles = Object.values(classIndex)
.map(file => ut.readJson(`./data/class/${file}`));
const uidsClass = new Set();
const uidsClassFeature = new Set();
const uidsSubclassFeature = new Set();
classFiles.forEach(data => {
(data.class || []).forEach(cls => {
const uid = UrlUtil.URL_TO_HASH_BUILDER[UrlUtil.PG_CLASSES](cls);
uidsClass.add(uid);
});
(data.classFeature || []).forEach(cf => {
const uid = UrlUtil.URL_TO_HASH_BUILDER["classFeature"](cf);
uidsClassFeature.add(uid);
});
(data.subclassFeature || []).forEach(scf => {
const uid = UrlUtil.URL_TO_HASH_BUILDER["subclassFeature"](scf);
uidsSubclassFeature.add(uid);
});
});
const foundryData = ut.readJson("./data/class/foundry.json");
(foundryData.class || []).forEach(cls => {
const uid = UrlUtil.URL_TO_HASH_BUILDER[UrlUtil.PG_CLASSES](cls);
if (!uidsClass.has(uid)) errors.push(`\tClass "${uid}" not found!`);
});
(foundryData.classFeature || []).forEach(fcf => {
const uid = UrlUtil.URL_TO_HASH_BUILDER["classFeature"](fcf);
if (!uidsClassFeature.has(uid)) errors.push(`\tClass feature "${uid}" not found!`);
});
(foundryData.subclassFeature || []).forEach(fscf => {
const uid = UrlUtil.URL_TO_HASH_BUILDER["subclassFeature"](fscf);
if (!uidsSubclassFeature.has(uid)) errors.push(`\tSubclass feature "${uid}" not found!`);
});
}
static async pTestDir ({errors, dir}) {
const FOUNDRY_FILE = "foundry.json";
const dirList = fs.readdirSync(`./data/${dir}`)
.filter(it => !it.startsWith("fluff-") && it !== "sources.json" && it !== "index.json");
if (!dirList.includes(FOUNDRY_FILE)) throw new Error(`No "${FOUNDRY_FILE}" file found in dir "${dir}"!`);
const foundryPath = `./data/${dir}/${FOUNDRY_FILE}`;
const foundryData = ut.readJson(foundryPath);
const originalDatas = await dirList
.filter(it => it !== FOUNDRY_FILE)
.pSerialAwaitMap(it => this.pLoadData(it, `./data/${dir}/${it}`));
await this.pTestFile({errors, foundryData, foundryPath, originalDatas});
}
static async pTestRoot ({errors}) {
const dirList = fs.readdirSync(`./data/`);
const foundryFiles = dirList.filter(it => it.startsWith("foundry-") && it.endsWith(".json"));
for (const foundryFile of foundryFiles) {
const foundryPath = `./data/${foundryFile}`;
const foundryData = ut.readJson(foundryPath);
const originalFile = foundryFile.replace(/^foundry-/i, "");
const originalData = await this.pLoadData(originalFile, `./data/${originalFile}`);
await this.pTestFile({errors, foundryData, foundryPath, originalDatas: [originalData]});
}
}
static testSpecialRaceFeatures ({foundryData, originalDatas, errors}) {
const uidsRaceFeature = new Set();
const HASH_BUILDER = it => UrlUtil.encodeForHash([it.name, it.source, it.raceName, it.raceSource]);
originalDatas.forEach(originalData => {
originalData.race.forEach(race => {
DataUtil.generic.getVersions(race).forEach(ver => this._testSpecialRaceFeatures_addRace({HASH_BUILDER, uidsRaceFeature, race: ver}));
this._testSpecialRaceFeatures_addRace({HASH_BUILDER, uidsRaceFeature, race});
});
});
foundryData.raceFeature.forEach(raceFeature => {
const uid = HASH_BUILDER(raceFeature);
if (!uidsRaceFeature.has(uid)) errors.push(`\tRace feature "${uid}" not found!`);
});
}
static _testSpecialRaceFeatures_addRace ({HASH_BUILDER, uidsRaceFeature, race}) {
(race.entries || []).forEach(ent => {
const uid = HASH_BUILDER({source: race.source, ...ent, raceName: race.name, raceSource: race.source});
uidsRaceFeature.add(uid);
});
}
static async pTestSpecialMagicItemVariants ({foundryData, originalDatas, errors}) {
const variants = await this.pLoadData("magicvariants.json", `./data/magicvariants.json`);
const prop = "magicvariant";
this.doCompareData({prop, foundryData, originalDatas: [variants], errors});
}
static doCompareData ({prop, foundryData, originalDatas, errors}) {
foundryData[prop].forEach(it => {
const match = originalDatas.first(variants => variants[prop].find(og => og.name === it.name && (og?.inherits?.source ?? og.source) === it.source));
if (!match) errors.push(`\t"${prop}" ${it.name} (${it.source}) not found!`);
});
}
static async pTestFile ({foundryPath, foundryData, originalDatas, errors}) {
Object.entries(foundryData)
.forEach(([prop, arr]) => {
if (SPECIAL_PROPS[prop]) return SPECIAL_PROPS[prop]({foundryPath, foundryData, originalDatas, errors});
if (!(arr instanceof Array)) return;
if (originalDatas.every(originalData => !originalData[prop] || !(originalData[prop] instanceof Array))) return console.warn(`\tUntested prop "${prop}" in file ${foundryPath}`);
this.doCompareData({prop, foundryData, originalDatas, errors});
});
}
}
const SPECIAL_PROPS = {
"raceFeature": TestFoundry.testSpecialRaceFeatures.bind(TestFoundry),
"magicvariant": TestFoundry.pTestSpecialMagicItemVariants.bind(TestFoundry),
};
async function main () {
const errors = [];
TestFoundry.testClasses({errors});
await TestFoundry.pTestDir({dir: "spells", errors});
await TestFoundry.pTestRoot({errors});
if (!errors.length) console.log("##### Foundry Tests Passed #####");
else {
console.error("Foundry data errors:");
errors.forEach(err => console.error(err));
}
return !errors.length;
}
export default main();