Jest test for webamp-modern-2

This commit is contained in:
Jordan Eldredge 2022-03-02 09:03:20 -08:00
parent c571888fe3
commit ecd290adea
13 changed files with 4614 additions and 445 deletions

View file

@ -4,7 +4,10 @@
"description": "Render .ani cursors as CSS animations in the browser",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist/", "src/**/*.ts"],
"files": [
"dist/",
"src/**/*.ts"
],
"author": "Jordan Eldredge <jordan@jordaneldredge.com>",
"license": "MIT",
"repository": {
@ -27,7 +30,7 @@
"@babel/preset-typescript": "^7.12.7",
"@types/jest": "^26.0.18",
"babel-jest": "^26.6.3",
"jest": "^26.6.3",
"jest": "^27.5.1",
"typescript": "^4.1.2"
},
"dependencies": {
@ -35,6 +38,9 @@
"riff-file": "^1.0.3"
},
"jest": {
"modulePathIgnorePatterns": ["dist"]
"modulePathIgnorePatterns": [
"dist"
],
"testEnvironment": "jsdom"
}
}

View file

@ -0,0 +1,17 @@
module.exports = {
...require("@snowpack/app-scripts-react/jest.config.js")(),
testMatch: ["**/__tests__/**/?(*.)+(spec|test).[jt]s?(x)"],
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "ts-jest",
//"^.+\\.svg$": "<rootDir>/jest/svgTransform.js",
// "^.+\\.css$": "<rootDir>/jest/cssTransform.js",
},
// testEnvironment: "jsdom",
globals: {
"ts-jest": {
diagnostics: {
warnOnly: true,
},
},
},
};

View file

@ -0,0 +1,2 @@
// This has to exist for some reason, or Jest complains...
// I think it's something about the Snowpack config that we are using.

View file

@ -10,19 +10,24 @@
"build-lint": "tsup tools/eslint-rules/proper-maki-types.ts -d tools/eslint-rules/dist --no-splitting --minify"
},
"devDependencies": {
"@babel/preset-typescript": "^7.16.7",
"@snowpack/app-scripts-react": "^2.0.1",
"@types/eslint": "^7.2.14",
"@types/estree": "^0.0.50",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"eslint": "^7.30.0",
"eslint-plugin-rulesdir": "^0.2.0",
"jest": "^27.5.1",
"snowpack": "^3.5.5",
"typescript": "^4.3.5",
"tsup": "^4.12.5"
"ts-jest": "^27.1.3",
"tsup": "^4.12.5",
"typescript": "^4.3.5"
},
"prettier": {},
"dependencies": {
"@rgrove/parse-xml": "^3.0.0",
"jszip": "^3.6.0"
"jszip": "^3.6.0",
"ts-jest": "^27.1.3"
}
}

View file

@ -0,0 +1,64 @@
import { getClass } from "../objects";
export function classResolver(guid: string): any {
switch (guid) {
case "d6f50f6449b793fa66baf193983eaeef":
return MockSystem;
case "45be95e5419120725fbb5c93fd17f1f9":
return MockGroup;
case "6129fec14d51dab7ca016591db701b0c":
return MockGuiList;
}
throw new Error(
`Unresolvable class "${getClass(guid).name}" (guid: ${guid})`
);
}
export class MockSystem {
group = new MockGroup();
getruntimeversion() {
return 5.666;
}
messagebox(
message: string,
msgtitle: string,
flag: number,
notanymore_id: string
) {
return 1;
}
getscriptgroup() {
return this.group;
}
// Not part of the original Maki code, but added to access test data.
getAssertions(): string[][] {
return this.group.list.items;
}
}
class MockGroup {
list = new MockGuiList();
getobject(objectId: string) {
if (objectId !== "results") {
throw new Error(
"In this test, we only expect this to be called to get the list."
);
}
return this.list;
}
}
class MockGuiList {
items: string[][] = [];
additem(status: string) {
this.items.push([status]);
return 1;
}
getlastaddeditempos() {
return this.items.length - 1;
}
setsubitem(i: number, j: number, value: string) {
this.items[i][j] = value;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,38 @@
#include "lib/std.mi"
// To compile in VM:
// From within this directoy (so the compiled .maki file ends up here)
// & '..\..\..\..\..\..\..\webamp-modern\resources\maki_compiler\v1.2.0 (Winamp 5.66)\mc.exe' .\assertions.m
Global GuiList resultsList;
Function Boolean assert(Boolean isTrue, String code, String description);
// This is our special test function we wraps messageBox for now.
// In the future this should be a function that renders a green/red box in a
// skin.
Boolean assert(Boolean isTrue, String code, String description) {
String response;
if(isTrue) {
resultsList.addItem("SUCCESS");
} else {
resultsList.addItem("FAILURE");
}
Int i = resultsList.getLastAddedItemPos();
resultsList.setSubItem(i, 1, code);
resultsList.setSubItem(i, 2, description);
}
System.onScriptLoaded()
{
Group systemGroup;
systemGroup = System.getScriptGroup();
if(systemGroup == null) {
System.messageBox("Null", "Null", 0, "Null");
}
resultsList = systemGroup.getObject("results");
assert(1 + 1 == 2, "1 + 1 == 2", "Summing two integers results in an integer");
assert(3 / 2 == 1.5, "3 / 2 == 1.5", "Division of two integers results in a float");
assert(1 + 1.5 == 2.5, "1 + 1.5 == 2.5", "Summing an integer and a float results in a float");
assert(1.5 + 1 == 2.5, "1.5 + 1 == 2.5", "Summing a float and an integer results in a float");
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<WinampAbstractionLayer version="0.8">
<skininfo>
<name>Modern Skin Test Suite</name>
<version>1.0</version>
<comment>A Skin Which Runs Tests in Maki and confirms that they behave as expected.</comment>
<author>Jordan Eldredge</author>
<email>jordan@jordaneldredge.com</email>
<homepage>https://jordaneldredge.com</homepage>
<!--<screenshot>skinshot.png</screenshot>-->
</skininfo>
<elements>
<bitmap id="main.bg.shadow" file="images/main-bg-shadow.png" gammagroup="backgrounds"/>
</elements>
<container name="Main Window" default_visible="1" w="500" h="500">
<layout background="main.bg.shadow" desktopalpha="1" w="500" fitparent="1">
<group x="0" y="0" w="500" h="500">
<script id="custom" file="scripts/assertions.maki"/>
<list
id="results"
y="10"
w="500"
columnwidths="75;75;150"
columnlabels="Status;Test Case;Description"
numcolumns="3"
antialias="1"
autodeselect="1"
/>
</group>
</layout>
</container>
</WinampAbstractionLayer>

View file

@ -0,0 +1,70 @@
import fs from "fs";
import path from "path";
import { parse } from "../parser";
import { interpret } from "../interpreter";
import { MockSystem, classResolver } from "./MockSystem";
/**
* Loads a specially crafted Maki script that can be used to test the behavior
* of Winamp. The script is a collection of assertions that are run against the
* Maki runtime.
*
* The script can run in real Winamp using the test skin as a harness. In that
* case, it renders a GuiList showing the result of each test.
*
* In unit tests (here) it runs against a mock environment `MockSystem` which is
* tightly coupled to the implementaiton of the Maki code. Specifically, the
* test environment expects the Maki to code construct a single GuiList
* containing assertions and their results with a specific structure. Each item
* is a tripple of:
*
* - Status: "SUCCESS" or "FAILURE"
* - Code: A string representiaton of the code that was expected to return "true"
* - Description: A human-readable description of what was being tested
*/
const scriptPath = path.join(
__dirname,
"fixtures",
"TestBedSkin",
"scripts",
"assertions.maki"
);
describe(`Maki test harness`, () => {
const maki = fs.readFileSync(scriptPath);
const script = parse(maki);
const initialVariable = script.variables[0];
if (initialVariable.type !== "OBJECT") {
throw new Error("First variable was not SystemObject.");
}
// Our types say this should extend GuiObj, but that would
// require pulling in code that does not run well in jsdom.
// So we just cast to `any` here.
const system = new MockSystem() as any;
initialVariable.value = system;
const onScriptLoadedBinding = script.bindings.find(
(binding) =>
script.methods[binding.methodOffset].name === "onscriptloaded" &&
script.variables[binding.variableOffset].value === system
);
if (onScriptLoadedBinding === undefined) {
throw new Error("Could not find event binding for System.onscriptloaded");
}
const variables = [];
interpret(
onScriptLoadedBinding.commandOffset,
script,
variables,
classResolver
);
for (const result of system.group.list.items) {
const [status, code, description] = result;
test(`${description}: (${code})`, () => expect(status).toBe("SUCCESS"));
}
});

View file

@ -0,0 +1,7 @@
{
"compilerOptions": {
"esModuleInterop": true,
"allowJs": true,
"resolveJsonModule": true
}
}

2026
yarn.lock

File diff suppressed because it is too large Load diff