Skip to content

Commit

Permalink
runTestCase c, c++, java, js, rust, python 지원 맥북테스트 완료
Browse files Browse the repository at this point in the history
  • Loading branch information
dltkdgns00 committed Mar 14, 2024
1 parent c307bfc commit 7f03a77
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 6 deletions.
Binary file removed .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ dist
node_modules
.vscode-test/
*.vsix
.DS_Store
*/.DS_Store
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
"command": "BOJ-EX.createProblem",
"title": "BOJ: Create Problem File"
},
{
"command": "BOJ-EX.runTestCase",
"title": "BOJ: Run TestCase"
},
{
"command": "BOJ-EX.pushToGithub",
"title": "BOJ: Push to Github"
Expand Down
168 changes: 168 additions & 0 deletions src/commands/runTestCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import * as vscode from "vscode";
import { searchProblem } from "../libs/searchProblem";
import { getProbNum } from "../libs/getProbNum";
import { spawn, execSync } from "child_process";
import * as path from "path";
import * as fs from "fs";

export async function runTestCase(context: vscode.ExtensionContext) {
const outputChannel = vscode.window.createOutputChannel("Test Cases");
try {
const problemNumber = getProbNum();

if (!problemNumber) {
vscode.window.showErrorMessage("Problem number not found.");
return;
}

const sp = await searchProblem(problemNumber, context);

if (!sp.sampleInputs || !sp.sampleOutputs) {
vscode.window.showErrorMessage(
"Sample inputs or outputs not found."
);
return;
}

const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage("No editor found.");
return;
}

const filePath = editor.document.uri.fsPath;

const config = vscode.workspace.getConfiguration("BOJ");
const extension = config.get<string>("extension", "");

const maxWidth = 40;

const preMessage1 = centerText(
` ${problemNumber}. ${sp.title} `,
maxWidth
);
const preMessage2 = `문제링크: https://boj.kr/${problemNumber}`;

outputChannel.appendLine(preMessage1);
outputChannel.appendLine(preMessage2);
outputChannel.appendLine(``);

const createOutputMessage = (
testCaseIndex,
result,
expected,
actual
) => {
const passedMessage = `✅ Test Case #${testCaseIndex + 1}: Passed`;
const failedMessage = `❌ Test Case #${
testCaseIndex + 1
}: Failed\n${centerText(
` Expected `,
maxWidth
)}\n${expected}${centerText(` Actual `, maxWidth)}\n${actual}`;

return result ? passedMessage : failedMessage;
};

const runTest = (input, expectedOutput, testCaseIndex) => {
return new Promise<void>((resolve, reject) => {
const processIO = getProcessIO(extension, filePath);
let outputData = "";

processIO!.stdout.on("data", (data) => {
outputData += data.toString();
});

processIO!.stderr.on("data", (data) => {
console.error(`에러: ${data}`);
reject(new Error(data.toString()));
});

processIO!.on("close", (code) => {
const actualOutput = outputData.trim();
const isPassed = actualOutput === expectedOutput.trim();
const message = createOutputMessage(
testCaseIndex,
isPassed,
expectedOutput,
actualOutput
);
outputChannel.appendLine(message);

resolve();
});

processIO!.on("error", (err) => {
console.error(`에러: ${err}`);
reject(err);
});

processIO!.stdin.write(input);
processIO!.stdin.end();
});
};

for (let i = 0; i < sp.sampleInputs.length; i++) {
await runTest(sp.sampleInputs[i], sp.sampleOutputs[i], i);
}

const postMessage1 = centerText(` 채점 종료 `, maxWidth);
const postMessage2 = `결과 창은 1분 뒤에 닫힙니다.`;

outputChannel.appendLine(``);
outputChannel.appendLine(postMessage1);
outputChannel.appendLine(postMessage2);

outputChannel.show(true);
setTimeout(() => {
outputChannel.dispose();
}, 60000);
} catch (error) {
vscode.window.showErrorMessage(
"테스트 케이스 실행 중 오류가 발생했습니다. 직접 실행해서 오류를 확인해주세요."
);
}
}

function centerText(text, maxWidth) {
const padding = Math.max(0, maxWidth - text.length);
const paddingLeft = Math.floor(padding / 2);
const paddingRight = padding - paddingLeft;
return "-".repeat(paddingLeft) + text + "-".repeat(paddingRight);
}

function getProcessIO(extension: string, filePath: string) {
if (extension === "c") {
const objectFileURL = filePath.replace(/\.[^/.]+$/, "");
execSync(`gcc "${filePath}" -o "${objectFileURL}"`);
return spawn(`${objectFileURL}`);
} else if (extension === "cpp") {
const objectFileURL = filePath.slice(0, filePath.length - 4);
execSync(`g++ -std=c++17 "${filePath}" -o "${objectFileURL}"`);
return spawn(`${objectFileURL}`);
} else if (extension === "java") {
const dirName = path.dirname(filePath);
return spawn(`java`, ["-cp", dirName, filePath]);
} else if (extension === "js") {
return spawn("node", [filePath]);
} else if (extension === "rs") {
const fileName = path.basename(filePath, ".rs");
const crateName = fileName.replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase();
const objectFileURL = path.join(".", `${crateName}.out`);
const dirName = path.dirname(filePath);
const options = {
cwd: path.dirname(filePath),
env: {
...process.env,
RUSTC_FLAGS: "-D tempdir=/tmp",
},
};
execSync(
`rustc --crate-name "${crateName}" "${filePath}" -o "${objectFileURL}"`,
options
);
return spawn(`${dirName}/${objectFileURL}`);
} else if (extension === "py") {
return spawn("python3", [filePath]);
}
}
9 changes: 9 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createProblem } from "./commands/createProblem";
import { pushToGithub } from "./commands/pushToGithub";
import { makeWorkflow } from "./libs/makeWorkflow";
import { showManual } from "./commands/showManual";
import { runTestCase } from "./commands/runTestCase";
import { getProbNum } from "./libs/getProbNum";

export function activate(context: vscode.ExtensionContext) {
// 확장프로그램이 처음 실행될 때, 설정이 되어있지 않으면 설정창을 띄워준다.
Expand Down Expand Up @@ -79,6 +81,13 @@ export function activate(context: vscode.ExtensionContext) {
})
);

// runTestCase 커맨드 등록
context.subscriptions.push(
vscode.commands.registerCommand("BOJ-EX.runTestCase", () => {
runTestCase(context);
})
);

// pushToGithub 커맨드 등록
context.subscriptions.push(
vscode.commands.registerCommand("BOJ-EX.pushToGithub", () => {
Expand Down
21 changes: 21 additions & 0 deletions src/libs/getProbNum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as vscode from "vscode";
import * as path from "path";

export function getProbNum(): string | null {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage("No editor found.");
return null;
}

const filePath = editor.document.uri.fsPath;
const dirName = path.basename(path.dirname(filePath));

const match = dirName.match(/^(\d+)/);
if (match) {
return match[1];
} else {
vscode.window.showErrorMessage("Problem number not found.");
return null;
}
}
24 changes: 18 additions & 6 deletions src/libs/searchProblem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import * as vscode from "vscode";
import axios from "axios";
import * as cheerio from "cheerio";

export async function searchProblem(
problemNumber: string,
context: vscode.ExtensionContext
): Promise<{
interface ProblemData {
title: string;
info: string | null;
description: string;
Expand All @@ -17,7 +14,18 @@ export async function searchProblem(
sampleExplains: string[] | null;
hint: string | null;
source: string | null;
}> {
}

export async function searchProblem(
problemNumber: string,
context: vscode.ExtensionContext
): Promise<ProblemData> {
const cacheKey = `problem-${problemNumber}`;
const cachedData = context.globalState.get<ProblemData>(cacheKey);
if (cachedData) {
return cachedData;
}

const response = await axios.get(
`https://www.acmicpc.net/problem/${problemNumber}`,
{
Expand Down Expand Up @@ -89,7 +97,7 @@ export async function searchProblem(
// 출처 추출
const source = $("#source").html();

return {
const problemData: ProblemData = {
title,
info,
description,
Expand All @@ -102,4 +110,8 @@ export async function searchProblem(
hint,
source,
};

await context.globalState.update(cacheKey, problemData);

return problemData;
}

0 comments on commit 7f03a77

Please sign in to comment.