Skip to content

Commit

Permalink
Fix Misnamed Tags & More useful validity tests
Browse files Browse the repository at this point in the history
  • Loading branch information
BellCubeDev committed Sep 1, 2023
1 parent 1e4b57d commit 9c96361
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
15 changes: 12 additions & 3 deletions src/definitions/Fomod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class Fomod<TStrict extends boolean = true> extends XmlRepresentation<TSt
reason: InvalidityReason.FomodModuleNameMetadataInvalidPosition,
};

if (!isNaN(parseInt(this.moduleNameMetadata.colour ?? '2', 16))) return {
if (isNaN(parseInt(this.moduleNameMetadata.colour ?? '2', 16))) return {
tree,
offendingValue: this.moduleNameMetadata.colour!,
reason: InvalidityReason.FomodModuleNameMetadataColorHexNotHexNumber,
Expand All @@ -115,7 +115,16 @@ export class Fomod<TStrict extends boolean = true> extends XmlRepresentation<TSt
reason: InvalidityReason.FomodModuleImageMetadataShowImageNotBool,
};

// TODO: Require more invalidity reports!
for (const step of this.steps) {
const reason = step.reasonForInvalidity(...tree);
if (reason) return reason;
}

for (const installOrPattern of this.installs) {
const reason = installOrPattern.reasonForInvalidity(...tree);
if (reason) return reason;
}

return null;
}

Expand Down Expand Up @@ -207,7 +216,7 @@ export class Fomod<TStrict extends boolean = true> extends XmlRepresentation<TSt
if (parsed) fomod.installs.add(parsed);
}

for (const step of element.querySelectorAll(':scope > installSteps > step')) {
for (const step of element.querySelectorAll(':scope > installSteps > installStep')) {
const parsed = Step.parse(step);
if (parsed) fomod.steps.add(parsed);
}
Expand Down
2 changes: 1 addition & 1 deletion src/definitions/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class Group<TStrict extends boolean = true> extends XmlRepresentation<TSt
if (existing && existing instanceof this) return existing;

const name = element.getAttribute('name');
const behaviorType = element.getAttribute('behaviorType');
const behaviorType = element.getAttribute('type');

const group = new Group<false>(name ?? '', behaviorType ?? '');
group.assignElement(element);
Expand Down
36 changes: 24 additions & 12 deletions src/definitions/Install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,30 @@ import { Verifiable, XmlRepresentation } from "./_core";



// TODO: Use patorjk ASCII art generator
// Single-File Install

/***
* $$$$$$\ $$\ $$\ $$$$$$$$\ $$\ $$\
* $$ __$$\ \__| $$ | $$ _____|\__|$$ |
* $$ / \__|$$\ $$$$$$$\ $$$$$$\ $$ | $$$$$$\ $$ | $$\ $$ | $$$$$$\
* \$$$$$$\ $$ |$$ __$$\ $$ __$$\ $$ |$$ __$$\ $$$$$$\ $$$$$\ $$ |$$ |$$ __$$\
* \____$$\ $$ |$$ | $$ |$$ / $$ |$$ |$$$$$$$$ |\______|$$ __| $$ |$$ |$$$$$$$$ |
* $$\ $$ |$$ |$$ | $$ |$$ | $$ |$$ |$$ ____| $$ | $$ |$$ |$$ ____|
* \$$$$$$ |$$ |$$ | $$ |\$$$$$$$ |$$ |\$$$$$$$\ $$ | $$ |$$ |\$$$$$$$\
* \______/ \__|\__| \__| \____$$ |\__| \_______| \__| \__|\__| \_______|
* $$\ $$ |
* \$$$$$$ |
* \______/
* $$$$$$\ $$\ $$\ $$\
* \_$$ _| $$ | $$ |$$ |
* $$ | $$$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$ |$$ |
* $$ | $$ __$$\ $$ _____|\_$$ _| \____$$\ $$ |$$ |
* $$ | $$ | $$ |\$$$$$$\ $$ | $$$$$$$ |$$ |$$ |
* $$ | $$ | $$ | \____$$\ $$ |$$\ $$ __$$ |$$ |$$ |
* $$$$$$\ $$ | $$ |$$$$$$$ | \$$$$ |\$$$$$$$ |$$ |$$ |
* \______|\__| \__|\_______/ \____/ \_______|\__|\__|
*
*
*
*/



Expand Down Expand Up @@ -233,15 +254,6 @@ export class Install<TStrict extends boolean = true> extends XmlRepresentation<T





// TODO: Use patorjk ASCII art generator
// Files Wrapper





/***
* $$$$$$$$\ $$\ $$\ $$\ $$\
* $$ _____|\__|$$ | $$ | $\ $$ |
Expand Down
4 changes: 2 additions & 2 deletions tests/build-from-scratch.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dependencies, Fomod, GameVersionDependency, Group, GroupBehaviorType, Install, InstallPattern, Option, ScriptExtenderVersionDependency, SortingOrder as SortingOrder, Step } from "../src";
import parseTag from "./parseTag";
import { parseTag, testValidity } from "./testUtils";

const fomod = new Fomod('That Test Fomod', 'someImage.gif');

Expand Down Expand Up @@ -40,7 +40,7 @@ fomod.steps.add(step);

// Logging: InvalidStateError: Invalid attribute localName value

test('Fomod Is Valid', () => expect(fomod.isValid()).toBe(true));
test('Fomod Is Valid', () => testValidity(fomod));


console.log(fomod.asElement(parseTag`<p>`.ownerDocument).outerHTML);
12 changes: 6 additions & 6 deletions tests/definitions/Dependencies.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -38,7 +38,7 @@ describe('File Dependencies', () => {
const element = parseTag`<fileDependency file="appleBanana123" state="Some Odd State" />`;
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'));
});
Expand All @@ -47,7 +47,7 @@ describe('File Dependencies', () => {
const element = parseTag`<fileDependency file="appleBanana456" state="Active" />`;
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'));
});
Expand All @@ -56,7 +56,7 @@ describe('File Dependencies', () => {
const element = parseTag`<fileDependency file="appleBanana789" state="Inactive" />`;
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'));
});
Expand All @@ -65,7 +65,7 @@ describe('File Dependencies', () => {
const element = parseTag`<fileDependency file="appleBanana0-=" state="Missing" />`;
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'));
});
Expand Down
5 changes: 3 additions & 2 deletions tests/definitions/Fomod.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Fomod } from '../../src';

import parseTag from '../parseTag';
import { parseTag } from '../testUtils';



Expand Down Expand Up @@ -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);
});

2 changes: 1 addition & 1 deletion tests/definitions/Install.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import parseTag from '../parseTag';
import {parseTag} from '../testUtils';

import { Install } from '../../src';

Expand Down
10 changes: 0 additions & 10 deletions tests/parseTag.ts

This file was deleted.

28 changes: 28 additions & 0 deletions tests/testUtils.ts
Original file line number Diff line number Diff line change
@@ -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<boolean>, 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);
}

0 comments on commit 9c96361

Please sign in to comment.