2023-10-23 23:16:24 +02:00
|
|
|
import fs from "node:fs"
|
|
|
|
import path from "node:path"
|
|
|
|
import { performance } from "node:perf_hooks"
|
2021-06-09 20:31:45 +02:00
|
|
|
|
2023-10-23 23:16:24 +02:00
|
|
|
import type { Solution } from "./Solution.js"
|
|
|
|
import { docker } from "./Docker.js"
|
|
|
|
import { SolutionTestsResult } from "./SolutionTestsResult.js"
|
|
|
|
import { TemporaryFolder } from "./TemporaryFolder.js"
|
2021-06-09 20:31:45 +02:00
|
|
|
|
|
|
|
export interface InputOutput {
|
|
|
|
input: string
|
|
|
|
output: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface TestRunOptions {
|
2022-09-22 16:16:21 +02:00
|
|
|
testNumber: number
|
2021-06-09 20:31:45 +02:00
|
|
|
path: string
|
2022-09-22 16:16:21 +02:00
|
|
|
solution: Solution
|
2021-06-09 20:31:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface TestOptions {
|
2022-09-22 16:16:21 +02:00
|
|
|
testNumber: number
|
2021-06-09 20:31:45 +02:00
|
|
|
path: string
|
|
|
|
isSuccess: boolean
|
|
|
|
input: string
|
|
|
|
output: string
|
|
|
|
stdout: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Test implements TestOptions {
|
2022-09-22 16:16:21 +02:00
|
|
|
public testNumber: number
|
2021-06-09 20:31:45 +02:00
|
|
|
public path: string
|
|
|
|
public isSuccess: boolean
|
|
|
|
public input: string
|
|
|
|
public output: string
|
|
|
|
public stdout: string
|
|
|
|
|
2022-04-24 20:27:51 +02:00
|
|
|
constructor(options: TestOptions) {
|
2022-09-22 16:16:21 +02:00
|
|
|
this.testNumber = options.testNumber
|
2021-06-09 20:31:45 +02:00
|
|
|
this.path = options.path
|
|
|
|
this.isSuccess = options.isSuccess
|
|
|
|
this.input = options.input
|
|
|
|
this.output = options.output
|
|
|
|
this.stdout = options.stdout
|
2022-08-30 15:48:07 +02:00
|
|
|
}
|
|
|
|
|
2022-09-22 16:16:21 +02:00
|
|
|
static async runAll(solution: Solution): Promise<SolutionTestsResult> {
|
2023-10-23 23:16:24 +02:00
|
|
|
const testsPath = path.join(solution.challenge.path, "test")
|
2021-06-09 20:31:45 +02:00
|
|
|
const testsFolders = await fs.promises.readdir(testsPath)
|
2022-09-22 16:16:21 +02:00
|
|
|
const testsNumbers = testsFolders.map((test) => {
|
|
|
|
return Number(test)
|
|
|
|
})
|
|
|
|
const testsPromises: Array<Promise<Test>> = []
|
|
|
|
const start = performance.now()
|
2021-11-30 21:42:43 +01:00
|
|
|
for (const testNumber of testsNumbers) {
|
2022-09-22 16:16:21 +02:00
|
|
|
const testPath = path.join(testsPath, testNumber.toString())
|
|
|
|
testsPromises.push(Test.run({ testNumber, path: testPath, solution }))
|
2021-06-09 20:31:45 +02:00
|
|
|
}
|
2022-09-22 16:16:21 +02:00
|
|
|
const tests = await Promise.all(testsPromises)
|
|
|
|
const end = performance.now()
|
|
|
|
const elapsedTimeMilliseconds = end - start
|
|
|
|
return new SolutionTestsResult({ solution, tests, elapsedTimeMilliseconds })
|
2021-06-09 20:31:45 +02:00
|
|
|
}
|
|
|
|
|
2022-04-24 20:27:51 +02:00
|
|
|
static async getInputOutput(testPath: string): Promise<InputOutput> {
|
2023-10-23 23:16:24 +02:00
|
|
|
const inputPath = path.join(testPath, "input.txt")
|
|
|
|
const outputPath = path.join(testPath, "output.txt")
|
|
|
|
const input = await fs.promises.readFile(inputPath, { encoding: "utf-8" })
|
2021-06-09 20:31:45 +02:00
|
|
|
const output = await fs.promises.readFile(outputPath, {
|
2023-10-23 23:16:24 +02:00
|
|
|
encoding: "utf-8",
|
2021-06-09 20:31:45 +02:00
|
|
|
})
|
|
|
|
return { input, output }
|
|
|
|
}
|
|
|
|
|
2023-01-10 23:15:36 +01:00
|
|
|
static async runManyWithSolutions(solutions: Solution[]): Promise<number> {
|
2022-09-22 16:16:21 +02:00
|
|
|
const solutionTestsResultsPromises: Array<Promise<SolutionTestsResult>> = []
|
|
|
|
let isSolutionSuccess = true
|
2021-11-09 16:45:42 +01:00
|
|
|
for (const solution of solutions) {
|
2022-09-22 16:16:21 +02:00
|
|
|
const solutionTestsResultPromise = solution.test()
|
|
|
|
solutionTestsResultsPromises.push(solutionTestsResultPromise)
|
|
|
|
solutionTestsResultPromise
|
|
|
|
.then((solutionTestsResult) => {
|
|
|
|
solutionTestsResult.print()
|
|
|
|
if (!solutionTestsResult.isSuccess) {
|
|
|
|
isSolutionSuccess = false
|
|
|
|
}
|
|
|
|
})
|
2024-11-18 08:05:00 +01:00
|
|
|
.catch(() => {
|
|
|
|
isSolutionSuccess = false
|
|
|
|
})
|
2021-11-09 16:45:42 +01:00
|
|
|
}
|
2022-09-22 16:16:21 +02:00
|
|
|
await Promise.all(solutionTestsResultsPromises)
|
|
|
|
await TemporaryFolder.cleanAll()
|
|
|
|
if (isSolutionSuccess) {
|
|
|
|
console.log(SolutionTestsResult.SUCCESS_MESSAGE)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return 1
|
2021-11-09 16:45:42 +01:00
|
|
|
}
|
|
|
|
|
2022-04-24 20:27:51 +02:00
|
|
|
static async run(options: TestRunOptions): Promise<Test> {
|
2021-06-09 20:31:45 +02:00
|
|
|
const { input, output } = await Test.getInputOutput(options.path)
|
2022-09-22 16:16:21 +02:00
|
|
|
try {
|
|
|
|
const { stdout } = await docker.run(
|
|
|
|
input,
|
2023-10-23 23:16:24 +02:00
|
|
|
options.solution.temporaryFolder.id,
|
2022-09-22 16:16:21 +02:00
|
|
|
)
|
|
|
|
const test = new Test({
|
|
|
|
path: options.path,
|
|
|
|
testNumber: options.testNumber,
|
|
|
|
input,
|
|
|
|
output,
|
|
|
|
stdout,
|
2023-10-23 23:16:24 +02:00
|
|
|
isSuccess: stdout === output,
|
2022-09-22 16:16:21 +02:00
|
|
|
})
|
|
|
|
return test
|
|
|
|
} catch (error: any) {
|
|
|
|
throw new Error(
|
2023-10-23 23:16:24 +02:00
|
|
|
`solution: ${options.solution.path}\n${error.message as string}\n`,
|
2022-09-22 16:16:21 +02:00
|
|
|
)
|
|
|
|
}
|
2021-06-09 20:31:45 +02:00
|
|
|
}
|
|
|
|
}
|