Make tests and solving runtime agnostic

This commit is contained in:
Simon Sawicki
2025-08-31 11:52:53 +02:00
parent b429843661
commit c0927ec09d
6 changed files with 207 additions and 177 deletions

View File

@@ -1,15 +1,13 @@
import { writeAll } from "@std/io";
import { read, write } from "./io.ts";
import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
import { isOneOf } from "./utils.ts";
async function main(): Promise<Output> {
if (Deno.stdin.isTerminal()) {
throw "Expected input on stdin";
}
const input: Input = await new Response(Deno.stdin.readable).json();
const preprocessedPlayer = input.type === "player"
? preprocessPlayer(input.player)
: input.preprocessed_player;
function main(input: Input): Output {
const preprocessedPlayer =
input.type === "player"
? preprocessPlayer(input.player)
: input.preprocessed_player;
const solvers = getFromPrepared(preprocessedPlayer);
const responses = input.requests.map(
@@ -18,7 +16,7 @@ async function main(): Promise<Output> {
return {
type: "error",
request,
error: `Failed to extract ${request.type} function`,
error: `Unknown request type: ${request.type}`,
};
}
const solver = solvers[request.type];
@@ -39,10 +37,13 @@ async function main(): Promise<Output> {
return {
type: "error",
request,
error: `${error}`,
error:
error instanceof Error
? `${error.message}\n${error.stack}`
: `${error}`,
};
}
},
}
);
const output: Output = {
@@ -55,33 +56,33 @@ async function main(): Promise<Output> {
return output;
}
async function safeMain(): Promise<Output> {
async function safeMain(): Promise<void> {
try {
return await main();
const input = await read();
const output = main(input);
await write(output);
} catch (error) {
return {
await write({
type: "error",
error: `${error}`,
};
});
}
}
const output = await safeMain();
const bytes = new TextEncoder().encode(JSON.stringify(output));
await writeAll(Deno.stdout, bytes);
safeMain();
type Input =
export type Input =
| {
type: "player";
player: string;
requests: JsChallengeRequest[];
output_preprocessed: boolean;
}
type: "player";
player: string;
requests: JsChallengeRequest[];
output_preprocessed: boolean;
}
| {
type: "preprocessed";
preprocessed_player: string;
requests: JsChallengeRequest[];
};
type: "preprocessed";
preprocessed_player: string;
requests: JsChallengeRequest[];
};
type JsChallengeRequest = {
type: string;
@@ -92,23 +93,23 @@ type JsChallengeRequest = {
type JsChallengeProviderResponse =
| {
type: "result";
request: JsChallengeRequest;
response: string;
}
type: "result";
request: JsChallengeRequest;
response: string;
}
| {
type: "error";
request: JsChallengeRequest;
error: string;
};
type: "error";
request: JsChallengeRequest;
error: string;
};
type Output =
export type Output =
| {
type: "result";
preprocessed_player?: string;
responses: JsChallengeProviderResponse[];
}
type: "result";
preprocessed_player?: string;
responses: JsChallengeProviderResponse[];
}
| {
type: "error";
error: string;
};
type: "error";
error: string;
};

View File

@@ -3,122 +3,7 @@ import { parse } from "meriyah";
export const setupNodes = parse(`
globalThis.XMLHttpRequest = { prototype: {} };
const window = Object.assign(Object.create(null), globalThis);
window.location = new URL("https://www.youtube.com/watch?v=yt-dlp-wins");
const document = {};
`).body || [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
left: {
type: "MemberExpression",
object: {
type: "Identifier",
name: "globalThis",
},
computed: false,
property: {
type: "Identifier",
name: "XMLHttpRequest",
},
optional: false,
},
operator: "=",
right: {
type: "ObjectExpression",
properties: [
{
type: "Property",
key: {
type: "Identifier",
name: "prototype",
},
value: {
type: "ObjectExpression",
properties: [],
},
kind: "init",
computed: false,
method: false,
shorthand: false,
},
],
},
},
},
{
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "window",
},
init: {
type: "CallExpression",
callee: {
type: "MemberExpression",
object: {
type: "Identifier",
name: "Object",
},
computed: false,
property: {
type: "Identifier",
name: "assign",
},
optional: false,
},
arguments: [
{
type: "CallExpression",
callee: {
type: "MemberExpression",
object: {
type: "Identifier",
name: "Object",
},
computed: false,
property: {
type: "Identifier",
name: "create",
},
optional: false,
},
arguments: [
{
type: "Literal",
value: null,
},
],
optional: false,
},
{
type: "Identifier",
name: "globalThis",
},
],
optional: false,
},
},
],
},
{
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "document",
},
init: {
type: "ObjectExpression",
properties: [],
},
},
],
},
];
let self = globalThis;
`).body;

View File

@@ -1,22 +1,24 @@
import { assertStrictEquals } from "@std/assert";
import { getFromPrepared, preprocessPlayer } from "./solvers.ts";
import { players, tests } from "../tests/tests.ts";
import { getCachePath } from "../tests/utils.ts";
import { getIO } from "../tests/io.ts";
const io = await getIO();
for (const test of tests) {
for (const variant of test.variants ?? players.keys()) {
const path = getCachePath(test.player, variant);
Deno.test(`${test.player} ${variant}`, async (t) => {
const content = await Deno.readTextFile(path);
await io.test(`${test.player} ${variant}`, async (assert, subtest) => {
const content = await io.read(path);
const solvers = getFromPrepared(preprocessPlayer(content));
for (const mode of ["nsig", "sig"] as const) {
for (const step of test[mode] || []) {
await t.step(`${step.input} (${mode})`, () => {
await subtest(`${step.input} (${mode})`, () => {
const got = solvers[mode]?.(step.input);
assertStrictEquals(got, step.expected);
});
assert.equal(got, step.expected);
})
}
}
});
})
}
}