diff --git a/package.json b/package.json index c022f53..73c0943 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "type": "module", "name": "fomod", "description": "A library for creating, parsing, editing, and validating XML-based Fomod installers, widely popularized in the Bethesda modding scne", - "version": "0.1.3", + "version": "0.1.4", "main": "dist/index.js", "repository": "https://github.com/BellCubeDev/fomod-js/", "bugs": { diff --git a/src/definitions/Fomod.ts b/src/definitions/Fomod.ts index bbf6bf7..35e86f8 100644 --- a/src/definitions/Fomod.ts +++ b/src/definitions/Fomod.ts @@ -97,7 +97,7 @@ export class Fomod extends XmlRepresentation extends XmlRepresentation extends XmlRepresentation installSteps > step')) { + for (const step of element.querySelectorAll(':scope > installSteps > installStep')) { const parsed = Step.parse(step); if (parsed) fomod.steps.add(parsed); } diff --git a/src/definitions/Group.ts b/src/definitions/Group.ts index 33b88b0..4517ddc 100644 --- a/src/definitions/Group.ts +++ b/src/definitions/Group.ts @@ -79,7 +79,7 @@ export class Group extends XmlRepresentation(name ?? '', behaviorType ?? ''); group.assignElement(element); diff --git a/src/definitions/Install.ts b/src/definitions/Install.ts index baecb69..1db6365 100644 --- a/src/definitions/Install.ts +++ b/src/definitions/Install.ts @@ -7,9 +7,30 @@ import { Verifiable, XmlRepresentation } from "./_core"; -// TODO: Use patorjk ASCII art generator -// Single-File Install - +/*** + * $$$$$$\ $$\ $$\ $$$$$$$$\ $$\ $$\ + * $$ __$$\ \__| $$ | $$ _____|\__|$$ | + * $$ / \__|$$\ $$$$$$$\ $$$$$$\ $$ | $$$$$$\ $$ | $$\ $$ | $$$$$$\ + * \$$$$$$\ $$ |$$ __$$\ $$ __$$\ $$ |$$ __$$\ $$$$$$\ $$$$$\ $$ |$$ |$$ __$$\ + * \____$$\ $$ |$$ | $$ |$$ / $$ |$$ |$$$$$$$$ |\______|$$ __| $$ |$$ |$$$$$$$$ | + * $$\ $$ |$$ |$$ | $$ |$$ | $$ |$$ |$$ ____| $$ | $$ |$$ |$$ ____| + * \$$$$$$ |$$ |$$ | $$ |\$$$$$$$ |$$ |\$$$$$$$\ $$ | $$ |$$ |\$$$$$$$\ + * \______/ \__|\__| \__| \____$$ |\__| \_______| \__| \__|\__| \_______| + * $$\ $$ | + * \$$$$$$ | + * \______/ + * $$$$$$\ $$\ $$\ $$\ + * \_$$ _| $$ | $$ |$$ | + * $$ | $$$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$ |$$ | + * $$ | $$ __$$\ $$ _____|\_$$ _| \____$$\ $$ |$$ | + * $$ | $$ | $$ |\$$$$$$\ $$ | $$$$$$$ |$$ |$$ | + * $$ | $$ | $$ | \____$$\ $$ |$$\ $$ __$$ |$$ |$$ | + * $$$$$$\ $$ | $$ |$$$$$$$ | \$$$$ |\$$$$$$$ |$$ |$$ | + * \______|\__| \__|\_______/ \____/ \_______|\__|\__| + * + * + * + */ @@ -233,15 +254,6 @@ export class Install extends XmlRepresentation expect(fomod.isValid()).toBe(true)); +test('Fomod Is Valid', () => testValidity(fomod)); console.log(fomod.asElement(parseTag`

`.ownerDocument).outerHTML); diff --git a/tests/definitions/Dependencies.test.ts b/tests/definitions/Dependencies.test.ts index 7d0239c..e122aea 100644 --- a/tests/definitions/Dependencies.test.ts +++ b/tests/definitions/Dependencies.test.ts @@ -2,8 +2,8 @@ * @jest-environment jsdom */ -import { FileDependency, FlagDependency, GameVersionDependency, ModManagerVersionDependency, ScriptExtenderVersionDependency, VersionDependency } from "../../src"; -import parseTag from "../parseTag"; +import { FileDependency, FlagDependency, GameVersionDependency, InvalidityReason, ModManagerVersionDependency, ScriptExtenderVersionDependency, VersionDependency } from "../../src"; +import { parseTag, testValidity } from "../testUtils"; describe('Flag Dependencies', () => { const flagName = 'Some Flag 01'; @@ -38,7 +38,7 @@ describe('File Dependencies', () => { const element = parseTag``; const obj = FileDependency.parse(element); - test('File Dependency Is Invalid', () => expect(obj.isValid()).toBe(false)); + test('File Dependency Is Invalid', () => testValidity(obj, InvalidityReason.DependencyFileInvalidState)); test('File Name Is Correct', () => expect(obj.filePath).toBe('appleBanana123')); test('Invalid State Is Preserved', () => expect(obj.desiredState).toBe('Some Odd State')); }); @@ -47,7 +47,7 @@ describe('File Dependencies', () => { const element = parseTag``; const obj = FileDependency.parse(element); - test('File Dependency Is Valid', () => expect(obj.isValid()).toBe(true)); + test('File Dependency Is Valid', () => testValidity(obj)); test('File Name Is Correct', () => expect(obj.filePath).toBe('appleBanana456')); test('State Is Correct', () => expect(obj.desiredState).toBe('Active')); }); @@ -56,7 +56,7 @@ describe('File Dependencies', () => { const element = parseTag``; const obj = FileDependency.parse(element); - test('File Dependency Is Valid', () => expect(obj.isValid()).toBe(true)); + test('File Dependency Is Valid', () => testValidity(obj)); test('File Name Is Correct', () => expect(obj.filePath).toBe('appleBanana789')); test('State Is Correct', () => expect(obj.desiredState).toBe('Inactive')); }); @@ -65,7 +65,7 @@ describe('File Dependencies', () => { const element = parseTag``; const obj = FileDependency.parse(element); - test('File Dependency Is Valid', () => expect(obj.isValid()).toBe(true)); + test('File Dependency Is Valid', () => testValidity(obj)); test('File Name Is Correct', () => expect(obj.filePath).toBe('appleBanana0-=')); test('State Is Correct', () => expect(obj.desiredState).toBe('Missing')); }); diff --git a/tests/definitions/Fomod.test.ts b/tests/definitions/Fomod.test.ts index b891f55..c60a823 100644 --- a/tests/definitions/Fomod.test.ts +++ b/tests/definitions/Fomod.test.ts @@ -1,6 +1,6 @@ import { Fomod } from '../../src'; -import parseTag from '../parseTag'; +import { parseTag } from '../testUtils'; @@ -166,6 +166,7 @@ test('Fomod Has Correct Image', () => { }); test('Fomod Is Valid', () => { - expect(fomod.isValid()).toBe(true); + const reason = fomod.reasonForInvalidity(); + expect(reason).toBe(null); }); diff --git a/tests/definitions/Install.test.ts b/tests/definitions/Install.test.ts index 2fd7d86..cce843f 100644 --- a/tests/definitions/Install.test.ts +++ b/tests/definitions/Install.test.ts @@ -1,4 +1,4 @@ -import parseTag from '../parseTag'; +import {parseTag} from '../testUtils'; import { Install } from '../../src'; diff --git a/tests/parseTag.ts b/tests/parseTag.ts deleted file mode 100644 index f93e1d1..0000000 --- a/tests/parseTag.ts +++ /dev/null @@ -1,10 +0,0 @@ -const parser = new DOMParser(); - -export default function parseTag(literals: TemplateStringsArray, ...expressions: string[]) { - let str = ''; - literals.forEach((string, i) => { - str += string + (expressions[i] ?? ''); - }); - const doc = parser.parseFromString(str, 'text/xml'); - return doc.documentElement; -} diff --git a/tests/testUtils.ts b/tests/testUtils.ts new file mode 100644 index 0000000..efcf5dd --- /dev/null +++ b/tests/testUtils.ts @@ -0,0 +1,28 @@ +import { InvalidityReason, Verifiable } from "../src"; + +const parser = new DOMParser(); + +export function parseTag(literals: TemplateStringsArray, ...expressions: string[]) { + let str = ''; + literals.forEach((string, i) => { + str += string + (expressions[i] ?? ''); + }); + const doc = parser.parseFromString(str, 'text/xml'); + return doc.documentElement; +} + +/** Ensures the provided Verifiable object is valid. Alternatively, if specified, ensures the provided Verifiable object is invalid and has the specified reason for invalidity. + * + * Will check that isValid() and reasonForInvalidity() agree, and that the reasonForInvalidity() matches the expected reason. If a mismatch occurs, + * + * @param v + * @param expectedReason + */ +export function testValidity(v: Verifiable, expectedReason?: InvalidityReason) { + const reason = v.reasonForInvalidity(); + const validity = v.isValid(); + + expect(reason).toBe(validity ? null : reason); // Always fail if isValid() and reasonForInvalidity() disagree + expect(reason?.reason).toBe(expectedReason); + expect(validity).toBe(!expectedReason); +}