Skip to content

Commit

Permalink
feat: implement custom test case feature through custom configuration…
Browse files Browse the repository at this point in the history
… file
  • Loading branch information
async3619 committed Oct 4, 2022
1 parent a6da797 commit 701dca4
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 15 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -4,3 +4,5 @@
/dist
/index.ts
/baekjoon_*.ts
/baekjoon_*.js
/.solv.yml
5 changes: 3 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "solv-cli",
"version": "1.1.2",
"version": "1.1.1",
"license": "MIT",
"publishConfig": {
"access": "public"
Expand Down Expand Up @@ -58,6 +58,7 @@
"prompts": "^2.4.2",
"replace-ext": "^2.0.0",
"uuid": "^9.0.0",
"vm2": "^3.9.11"
"vm2": "^3.9.11",
"yaml": "^2.1.2"
}
}
15 changes: 13 additions & 2 deletions src/index.ts
Expand Up @@ -3,12 +3,14 @@ import * as path from "path";
import * as fs from "fs-extra";
import * as chokidar from "chokidar";
import * as prompts from "prompts";
import * as yaml from "yaml";

import { program, ActionParameters } from "@caporal/core";

import { TARGET_PROVIDERS } from "./providers";
import { breakLine, clearConsole, drawLine, drawLogo } from "./cli";
import logger from "./logger";
import { Config } from "./types";

import { truncate } from "./utils/truncate";
import { runChallenge } from "./utils/runChallenge";
Expand Down Expand Up @@ -45,6 +47,15 @@ async function main({ args, options: { source } }: ActionParameters) {
logger.info(`use following url: ${targetUrl}`);
logger.info(`use following source code path: ${targetPath}`);

let config: Config | null = null;
const configFilePath = path.join(process.cwd(), ".solv.yml");
if (fs.existsSync(configFilePath)) {
logger.info(`use custom configuration file: ${configFilePath}`);

const configData = await fs.readFile(path.join(process.cwd(), ".solv.yml")).then(res => res.toString());
config = yaml.parse(configData);
}

if (fs.existsSync(targetPath)) {
const { overwrite } = await prompts({
type: "confirm",
Expand All @@ -70,15 +81,15 @@ async function main({ args, options: { source } }: ActionParameters) {
logger.info(` - for more information, you can visit: ${targetUrl}`);
logger.info(`now start watching changes of '${targetPath}' ...`);

await runChallenge(challenge, targetPath);
await runChallenge(challenge, targetPath, config);
const watcher = chokidar.watch(targetPath);

watcher
.on("change", () => {
clearConsole();
logger.info("File change detected, now trying to transpile and execute:");

runChallenge(challenge, targetPath).then();
runChallenge(challenge, targetPath, config).then();
})
.on("delete", () => {
logger.error(`'${targetPath}' seems to be deleted.`);
Expand Down
16 changes: 16 additions & 0 deletions src/types.ts
Expand Up @@ -14,3 +14,19 @@ export interface Challenge {
provider: BaseProvider;
initialCode?: string;
}

export interface InputOutput {
isCustom?: boolean;
input: InputType;
output: string;
}

interface ConfigCaseItem {
provider: string;
id: number | string;
items: InputOutput[];
}

export interface Config {
cases: ConfigCaseItem[];
}
7 changes: 5 additions & 2 deletions src/utils/TestCaseFailedError.ts
Expand Up @@ -2,8 +2,11 @@ export class TestCaseFailedError extends Error {
public constructor(
public readonly testCaseIndex: number,
public readonly result: [string, string],
customMessage?: string,
customMessage: string | undefined,
isCustom: boolean,
) {
super(customMessage || `Output was not matched with test case #${testCaseIndex + 1}`);
super(
customMessage || `Output was not matched with ${isCustom ? "custom " : ""}test case #${testCaseIndex + 1}`,
);
}
}
52 changes: 43 additions & 9 deletions src/utils/runChallenge.ts
Expand Up @@ -2,7 +2,7 @@ import * as Listr from "listr";
import * as chalk from "chalk";

import { breakLine, drawLine } from "../cli";
import { Challenge, InputType } from "../types";
import { Challenge, Config, InputOutput, InputType } from "../types";

import { BaseProvider } from "../providers/base";

Expand Down Expand Up @@ -30,6 +30,7 @@ async function runTestCase(
output: string,
targetPath: string,
provider: BaseProvider,
isCustom = false,
) {
try {
const data = await transpileAndRun(input, output, targetPath, provider);
Expand All @@ -38,28 +39,61 @@ async function runTestCase(
}

if (data[0] !== output) {
throw new TestCaseFailedError(index, data);
throw new TestCaseFailedError(index, data, undefined, isCustom);
}
} catch (e) {
if (e instanceof TestCaseFailedError) {
throw e;
} else if (e instanceof Error) {
throw new TestCaseFailedError(index, [(e as any).stderr || e.stack, ""], "Test case failed with an error");
throw new TestCaseFailedError(
index,
[(e as any).stderr || e.stack, ""],
"Test case failed with an error",
isCustom,
);
}
}
}

export async function runChallenge(challenge: Challenge, targetPath: string) {
export async function runChallenge(challenge: Challenge, targetPath: string, config: Config | null) {
breakLine();

const items = challenge.input.map<InputOutput>((input, i) => ({
input,
output: challenge.output[i],
}));

const customCases: InputOutput[] = [];
if (config) {
const cases = config.cases
.filter(
({ id, provider }) =>
id.toString() === challenge.id.toString() &&
challenge.provider.getName().toLowerCase() === provider,
)
.map(p => p.items)
.flat();

customCases.push(
...cases.map<InputOutput>(({ input, output }) => ({
input,
output,
isCustom: true,
})),
);
}

let currentTestCaseIndex = 0;
const instance = new Listr(
challenge.input.map((_, index) => ({
const instance = new Listr([
...customCases.map(({ input, output, isCustom }, index) => ({
title: `Running with custom test case #${index + 1}`,
task: () => runTestCase(index, input, output, targetPath, challenge.provider, isCustom),
})),
...items.map(({ input, output, isCustom }, index) => ({
title: `Running with test case #${index + 1}`,
task: () =>
runTestCase(index, challenge.input[index], challenge.output[index], targetPath, challenge.provider),
task: () => runTestCase(index, input, output, targetPath, challenge.provider, isCustom),
})),
);
]);

try {
await instance.run();
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Expand Up @@ -4903,6 +4903,11 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==

yaml@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.2.tgz#eb0f535eb309811b60276a9cc8c02af4355db420"
integrity sha512-VSdf2/K3FqAetooKQv45Hcu6sA00aDgWZeGcG6V9IYJnVLTnb6988Tie79K5nx2vK7cEpf+yW8Oy+7iPAbdiHA==

yargs-parser@^20.2.2, yargs-parser@^20.2.3:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
Expand Down

0 comments on commit 701dca4

Please sign in to comment.