Skip to content

Commit

Permalink
support test solution (#16)
Browse files Browse the repository at this point in the history
* support test solution

* escape the line seperator

* update readme
  • Loading branch information
jdneo authored Mar 5, 2018
1 parent 5b4bff1 commit f58422f
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ All notable changes to the "leetcode" extension will be documented in this file.

Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

## [0.3.0]
### Added
- Test current solution file [(#15)](https://github.com/jdneo/vscode-leetcode/issues/15)

## [0.2.1]
### Fixed
- Fix the wrong icon bug in LeetCode Explorer [(#9)](https://github.com/jdneo/vscode-leetcode/issues/9)
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Solve LeetCode problems in VS Code.
- Switch and create session
- Show problems in explorer
- Search problems by keywords
- Test solutions by customized test case
- Submit solutions to LeetCode

### Sign In and Sign Out
Expand All @@ -32,6 +33,9 @@ Solve LeetCode problems in VS Code.
### Search Problems by Keywords
![SearchProblem](resources/gif/searchproblem.gif)

### Test solutions by customized test case
![TestSolution](resources/gif/testsolution.gif)

### Submit Solutions to LeetCode
![SubmitSolution](resources/gif/solveproblem.gif)

Expand All @@ -43,6 +47,7 @@ This extension provides several commands in the Command Palette (F1 or Ctrl + Sh
- **LeetCode: Create new session** - Create a new session
- **LeetCode: Refresh** - Refresh the LeetCode Explorer
- **LeetCode: Search Problem** - Search for problems by keywords
- **LeetCode: Test Current File** - Test the solution by customized test case
- **LeetCode: Submit** - Submit the solution to LeetCode

## Known Issues:
Expand All @@ -68,6 +73,7 @@ This extension is based on [@skygragon](https://github.com/skygragon)'s [leetcod
- 切换及创建 session
- 在 Explorer 中展示题目
- 根据关键字搜索题目
- 用自定义测试用例测试答案
- 向 LeetCode 提交答案

### 登入及登出
Expand All @@ -82,6 +88,9 @@ This extension is based on [@skygragon](https://github.com/skygragon)'s [leetcod
### 根据关键字搜索题目
![SearchProblem](resources/gif/searchproblem.gif)

### 用自定义测试用例测试答案
![TestSolution](resources/gif/testsolution.gif)

### 向 LeetCode 提交答案
![SubmitSolution](resources/gif/solveproblem.gif)

Expand All @@ -93,6 +102,7 @@ This extension is based on [@skygragon](https://github.com/skygragon)'s [leetcod
- **LeetCode: Create new session** - 创建一个新的答题进度存档
- **LeetCode: Refresh** - 刷新左侧题目列表视图
- **LeetCode: Search Problem** - 根据关键字搜索题目
- **LeetCode: Test Current File** - 用自定义测试用例测试答案
- **LeetCode: Submit** - 提交答案到 LeetCode

## 已知问题
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-leetcode",
"displayName": "LeetCode",
"description": "Solve LeetCode problems in VS Code",
"version": "0.2.1",
"version": "0.3.0",
"author": "Sheng Chen",
"publisher": "shengchen",
"icon": "resources/LeetCode.png",
Expand Down Expand Up @@ -32,6 +32,7 @@
"onCommand:leetcode.refreshExplorer",
"onCommand:leetcode.showProblem",
"onCommand:leetcode.searchProblem",
"onCommand:leetcode.testSolution",
"onCommand:leetcode.submitSolution",
"onView:leetCodeExplorer"
],
Expand Down Expand Up @@ -78,6 +79,11 @@
"category": "LeetCode",
"icon": "resources/search.png"
},
{
"command": "leetcode.testSolution",
"title": "Test Current File",
"category": "LeetCode"
},
{
"command": "leetcode.submitSolution",
"title": "Submit",
Expand Down
Binary file added resources/gif/testsolution.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/commands/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export async function listProblems(channel: vscode.OutputChannel): Promise<IProb
}
return problems.reverse();
} catch (error) {
await promptForOpenOutputChannel("Failed to list problems. Please open the output channel for details", DialogType.error, channel);
await promptForOpenOutputChannel("Failed to list problems. Please open the output channel for details.", DialogType.error, channel);
return [];
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/commands/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import * as vscode from "vscode";
import { leetCodeManager } from "../leetCodeManager";
import { IQuickItemEx, leetCodeBinaryPath } from "../shared";
import * as cp from "../utils/cpUtils";
import { executeCommand } from "../utils/cpUtils";
import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";

export async function getSessionList(channel: vscode.OutputChannel): Promise<ISession[]> {
Expand All @@ -12,7 +12,7 @@ export async function getSessionList(channel: vscode.OutputChannel): Promise<ISe
promptForSignIn();
return [];
}
const result: string = await cp.executeCommand(channel, "node", [leetCodeBinaryPath, "session"]);
const result: string = await executeCommand(channel, "node", [leetCodeBinaryPath, "session"]);
const lines: string[] = result.split("\n");
const sessions: ISession[] = [];
const reg: RegExp = /(.?)\s*(\d+)\s+(.*)\s+(\d+ \(\s*\d+\.\d+ %\))\s+(\d+ \(\s*\d+\.\d+ %\))/;
Expand Down Expand Up @@ -41,11 +41,11 @@ export async function selectSession(channel: vscode.OutputChannel): Promise<void
return;
}
try {
await cp.executeCommand(channel, "node", [leetCodeBinaryPath, "session", "-e", choice.value]);
await executeCommand(channel, "node", [leetCodeBinaryPath, "session", "-e", choice.value]);
vscode.window.showInformationMessage(`Successfully switched to session '${choice.label}'.`);
await vscode.commands.executeCommand("leetcode.refreshExplorer");
} catch (error) {
await promptForOpenOutputChannel("Failed to switch session. Please open the output channel for details", DialogType.error, channel);
await promptForOpenOutputChannel("Failed to switch session. Please open the output channel for details.", DialogType.error, channel);
}
}

Expand All @@ -67,7 +67,7 @@ async function parseSessionsToPicks(channel: vscode.OutputChannel): Promise<Arra
});
resolve(picks);
} catch (error) {
return await promptForOpenOutputChannel("Failed to list sessions. Please open the output channel for details", DialogType.error, channel);
return await promptForOpenOutputChannel("Failed to list sessions. Please open the output channel for details.", DialogType.error, channel);
}
});
}
Expand All @@ -81,10 +81,10 @@ export async function createSession(channel: vscode.OutputChannel): Promise<void
return;
}
try {
await cp.executeCommand(channel, "node", [leetCodeBinaryPath, "session", "-c", session]);
await executeCommand(channel, "node", [leetCodeBinaryPath, "session", "-c", session]);
vscode.window.showInformationMessage("New session created, you can switch to it by clicking the status bar.");
} catch (error) {
await promptForOpenOutputChannel("Failed to create session. Please open the output channel for details", DialogType.error, channel);
await promptForOpenOutputChannel("Failed to create session. Please open the output channel for details.", DialogType.error, channel);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/commands/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async function showProblemInternal(channel: vscode.OutputChannel, id: string): P
if (match && match.length >= 2) {
await vscode.window.showTextDocument(vscode.Uri.file(match[1].trim()), { preview: false });
} else {
throw new Error("Failed to fetch the problem information");
throw new Error("Failed to fetch the problem information.");
}

if (!defaultLanguage && leetCodeConfig.get<boolean>("showSetDefaultLanguageHint")) {
Expand All @@ -72,7 +72,7 @@ async function showProblemInternal(channel: vscode.OutputChannel, id: string): P
}
}
} catch (error) {
await promptForOpenOutputChannel("Failed to fetch the problem information. Please open the output channel for details", DialogType.error, channel);
await promptForOpenOutputChannel("Failed to fetch the problem information. Please open the output channel for details.", DialogType.error, channel);
}
}

Expand Down
12 changes: 3 additions & 9 deletions src/commands/submit.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"use strict";

import * as fse from "fs-extra";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { leetCodeManager } from "../leetCodeManager";
import { leetCodeBinaryPath } from "../shared";
import { executeCommand } from "../utils/cpUtils";
import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
import { DialogType, promptForOpenOutputChannel, promptForSignIn, showResultFile } from "../utils/uiUtils";

export async function submitSolution(channel: vscode.OutputChannel): Promise<void> {
if (!leetCodeManager.getUser()) {
Expand All @@ -25,11 +22,8 @@ export async function submitSolution(channel: vscode.OutputChannel): Promise<voi
const filePath: string = textEditor.document.uri.fsPath;
try {
const result: string = await executeCommand(channel, "node", [leetCodeBinaryPath, "submit", filePath]);
const resultPath: string = path.join(os.homedir(), ".leetcode", "Result");
await fse.ensureFile(resultPath);
await fse.writeFile(resultPath, result);
await vscode.window.showTextDocument(vscode.Uri.file(resultPath));
await showResultFile(result);
} catch (error) {
await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details", DialogType.error, channel);
await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error, channel);
}
}
86 changes: 86 additions & 0 deletions src/commands/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use strict";

import * as fse from "fs-extra";
import * as vscode from "vscode";
import { leetCodeManager } from "../leetCodeManager";
import { IQuickItemEx, leetCodeBinaryPath, UserStatus } from "../shared";
import { executeCommand } from "../utils/cpUtils";
import { DialogType, promptForOpenOutputChannel, showFileSelectDialog, showResultFile } from "../utils/uiUtils";

export async function testSolution(channel: vscode.OutputChannel): Promise<void> {
try {
if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
return;
}

const activeText: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (!activeText) {
vscode.window.showErrorMessage("Please open a LeetCode solution file first.");
return;
}

const filePath = activeText.document.uri.fsPath;
const picks: Array<IQuickItemEx<string>> = [];
picks.push(
{
label: "$(three-bars) Default test cases",
description: "",
detail: "Test with the default cases",
value: ":default",
},
{
label: "$(pencil) Write directly...",
description: "",
detail: "Write test cases in input box",
value: ":direct",
},
{
label: "$(file-text) Browse...",
description: "",
detail: "Test with the writen cases in file",
value: ":file",
},
);
const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(picks);
if (!choice) {
return;
}

let result: string | undefined;
switch (choice.value) {
case ":default":
result = await executeCommand(channel, "node", [leetCodeBinaryPath, "test", filePath]);
break;
case ":direct":
const testString: string | undefined = await vscode.window.showInputBox({
prompt: "Enter the test cases.",
validateInput: (s: string) => s && s.trim() ? undefined : "Test case must not be empty.",
placeHolder: "Example: [1,2,3]\\n4",
ignoreFocusOut: true,
});
if (testString) {
result = await executeCommand(channel, "node", [leetCodeBinaryPath, "test", filePath, "-t", `"${testString.replace(/"/g, "")}"`]);
}
break;
case ":file":
const testFile: vscode.Uri[] | undefined = await showFileSelectDialog();
if (testFile && testFile.length) {
const input: string = await fse.readFile(testFile[0].fsPath, "utf-8");
if (input.trim()) {
result = await executeCommand(channel, "node", [leetCodeBinaryPath, "test", filePath, "-t", `"${input.replace(/"/g, "").replace(/\r?\n/g, "\\n")}"`]);
} else {
vscode.window.showErrorMessage("The selected test file must not be empty.");
}
}
break;
default:
break;
}
if (!result) {
return;
}
await showResultFile(result);
} catch (error) {
await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error, channel);
}
}
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as vscode from "vscode";
import * as session from "./commands/session";
import * as show from "./commands/show";
import * as submit from "./commands/submit";
import * as test from "./commands/test";
import { LeetCodeNode, LeetCodeTreeDataProvider } from "./leetCodeExplorer";
import { leetCodeManager } from "./leetCodeManager";
import { leetCodeStatusBarItem } from "./leetCodeStatusBarItem";
Expand All @@ -26,6 +27,7 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(channel, node)),
vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem(channel)),
vscode.commands.registerCommand("leetcode.refreshExplorer", () => leetCodeTreeDataProvider.refresh()),
vscode.commands.registerCommand("leetcode.testSolution", () => test.testSolution(channel)),
vscode.commands.registerCommand("leetcode.submitSolution", () => submit.submitSolution(channel)),
);

Expand Down
22 changes: 22 additions & 0 deletions src/utils/uiUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"use strict";

import * as fse from "fs-extra";
import * as opn from "opn";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";

export namespace DialogOptions {
Expand Down Expand Up @@ -51,6 +54,25 @@ export async function promptForSignIn(): Promise<void> {
}
}

export async function showFileSelectDialog(): Promise<vscode.Uri[] | undefined> {
const defaultUri: vscode.Uri | undefined = vscode.workspace.rootPath ? vscode.Uri.file(vscode.workspace.rootPath) : undefined;
const options: vscode.OpenDialogOptions = {
defaultUri,
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
openLabel: "Select",
};
return await vscode.window.showOpenDialog(options);
}

export async function showResultFile(result: string): Promise<void> {
const resultPath: string = path.join(os.homedir(), ".leetcode", "Result");
await fse.ensureFile(resultPath);
await fse.writeFile(resultPath, result);
await vscode.window.showTextDocument(vscode.Uri.file(resultPath));
}

export enum DialogType {
info = "info",
warning = "warning",
Expand Down

0 comments on commit f58422f

Please sign in to comment.