Skip to content

Commit 2552002

Browse files
Converted test recorder for bulk recordings (#169)
* Converted test recorded for bulk recordings * File name in camel case * Added spoken form to test suit * Added test recordings for actions * Innumerate test cases with same name * Remove breakpoint test * Added exception
1 parent 3e617af commit 2552002

26 files changed

+712
-70
lines changed

src/TestCaseRecorder.ts

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import { walkDirsSync } from "./test/suite/walkSync";
66

77
export class TestCaseRecorder {
88
active: boolean = false;
9-
outPath: string | null = null;
10-
spokenForm: string | null = null;
119
workspacePath: string | null;
1210
workSpaceFolder: string | null;
1311
fixtureRoot: string | null;
@@ -28,23 +26,19 @@ export class TestCaseRecorder {
2826
: null;
2927
}
3028

31-
start(): Promise<void> {
32-
this.active = true;
33-
return this.promptSpokenForm();
29+
async start(): Promise<boolean> {
30+
this.active = await this.promptSubdirectory();
31+
return this.active;
3432
}
3533

36-
async finish(testCase: TestCase): Promise<string | null> {
34+
stop() {
3735
this.active = false;
38-
const outPath = await this.promptSubdirectory();
39-
const fixture = testCase.toYaml();
40-
41-
if (outPath) {
42-
this.writeToFile(outPath, fixture);
43-
} else {
44-
this.showFixture(fixture);
45-
}
36+
}
4637

47-
return outPath;
38+
async finish(testCase: TestCase): Promise<void> {
39+
const outPath = this.calculateFilePath(testCase);
40+
const fixture = testCase.toYaml();
41+
await this.writeToFile(outPath, fixture);
4842
}
4943

5044
private async writeToFile(outPath: string, fixture: string) {
@@ -59,39 +53,13 @@ export class TestCaseRecorder {
5953
});
6054
}
6155

62-
private async showFixture(fixture: string) {
63-
const document = await vscode.workspace.openTextDocument({
64-
language: "yaml",
65-
content: fixture,
66-
});
67-
await vscode.window.showTextDocument(document, {
68-
viewColumn: vscode.ViewColumn.Beside,
69-
});
70-
}
71-
72-
private async promptSpokenForm(): Promise<void> {
73-
const result = await vscode.window.showInputBox({
74-
prompt: "Talon Command",
75-
ignoreFocusOut: true,
76-
validateInput: (input) => (input.trim().length > 0 ? null : "Required"),
77-
});
78-
79-
// Inputs return undefined when a user cancels by hitting 'escape'
80-
if (result === undefined) {
81-
this.active = false;
82-
return;
83-
}
84-
85-
this.spokenForm = result;
86-
}
87-
88-
private async promptSubdirectory(): Promise<string | null> {
56+
private async promptSubdirectory(): Promise<boolean> {
8957
if (
9058
this.workspacePath == null ||
9159
this.fixtureRoot == null ||
9260
this.workSpaceFolder !== "cursorless-vscode"
9361
) {
94-
return null;
62+
throw new Error("Can't prompt for subdirectory");
9563
}
9664

9765
const subdirectories = walkDirsSync(this.fixtureRoot).concat("/");
@@ -103,16 +71,16 @@ export class TestCaseRecorder {
10371
]);
10472

10573
if (subdirectorySelection === undefined) {
106-
return null;
74+
return false;
10775
} else if (subdirectorySelection === createNewSubdirectory) {
10876
return this.promptNewSubdirectory();
10977
} else {
11078
this.fixtureSubdirectory = subdirectorySelection;
111-
return this.promptFileName();
79+
return true;
11280
}
11381
}
11482

115-
private async promptNewSubdirectory(): Promise<string | null> {
83+
private async promptNewSubdirectory(): Promise<boolean> {
11684
if (this.fixtureRoot == null) {
11785
throw new Error("Missing fixture root. Not in cursorless workspace?");
11886
}
@@ -128,32 +96,43 @@ export class TestCaseRecorder {
12896
}
12997

13098
this.fixtureSubdirectory = subdirectory;
131-
return this.promptFileName();
99+
return true;
132100
}
133101

134-
private async promptFileName(): Promise<string | null> {
102+
private calculateFilePath(testCase: TestCase): string {
135103
if (this.fixtureRoot == null) {
136104
throw new Error("Missing fixture root. Not in cursorless workspace?");
137105
}
138106

139-
const filename = await vscode.window.showInputBox({
140-
prompt: "Fixture Filename",
141-
});
142-
143-
if (filename === undefined || this.fixtureSubdirectory == null) {
144-
return this.promptSubdirectory(); // go back a prompt
145-
}
146-
147107
const targetDirectory = path.join(
148108
this.fixtureRoot,
149-
this.fixtureSubdirectory
109+
this.fixtureSubdirectory!
150110
);
151111

152112
if (!fs.existsSync(targetDirectory)) {
153113
fs.mkdirSync(targetDirectory);
154114
}
155115

156-
this.outPath = path.join(targetDirectory, `${filename}.yml`);
157-
return this.outPath;
116+
let filename = camelize(testCase.spokenForm);
117+
let filePath = path.join(targetDirectory, `${filename}.yml`);
118+
119+
let i = 2;
120+
while (fs.existsSync(filePath)) {
121+
filename += i++;
122+
filePath = path.join(targetDirectory, `${filename}.yml`);
123+
}
124+
125+
return filePath;
158126
}
159127
}
128+
129+
function camelize(str: string) {
130+
return str
131+
.split(" ")
132+
.map((str, index) => (index === 0 ? str : capitalize(str)))
133+
.join("");
134+
}
135+
136+
function capitalize(str: string) {
137+
return str.charAt(0).toUpperCase() + str.slice(1);
138+
}

src/extension.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,33 @@ export async function activate(context: vscode.ExtensionContext) {
7979
const graph = makeGraph(graphConstructors);
8080
const thatMark = new ThatMark();
8181
const testCaseRecorder = new TestCaseRecorder(context);
82+
8283
const cursorlessRecordTestCaseDisposable = vscode.commands.registerCommand(
8384
"cursorless.recordTestCase",
8485
async () => {
85-
console.log("Recording test case for next command");
86-
testCaseRecorder.start();
86+
if (testCaseRecorder.active) {
87+
vscode.window.showInformationMessage("Stopped recording test cases");
88+
testCaseRecorder.stop();
89+
} else {
90+
if (await testCaseRecorder.start()) {
91+
vscode.window.showInformationMessage(
92+
"Recording test cases for following commands"
93+
);
94+
}
95+
}
8796
}
8897
);
98+
8999
const cursorlessCommandDisposable = vscode.commands.registerCommand(
90100
"cursorless.command",
91101
async (
102+
spokenForm: string,
92103
actionName: ActionType,
93104
partialTargets: PartialTarget[],
94105
...extraArgs: any[]
95106
) => {
96107
try {
108+
console.debug(`spokenForm: ${spokenForm}`);
97109
console.debug(`action: ${actionName}`);
98110
console.debug(`partialTargets:`);
99111
console.debug(JSON.stringify(partialTargets, null, 3));
@@ -109,14 +121,9 @@ export async function activate(context: vscode.ExtensionContext) {
109121

110122
const isPaste = actionName === "paste";
111123

112-
var clipboardContents: string | undefined;
113-
114-
if (isPaste) {
115-
clipboardContents = await Clipboard.readText();
116-
// clipboardContents = "hello";
117-
// clipboardContents = "hello\n";
118-
// clipboardContents = "\nhello\n";
119-
}
124+
const clipboardContents = isPaste
125+
? await Clipboard.readText()
126+
: undefined;
120127

121128
const inferenceContext = {
122129
selectionContents,
@@ -151,7 +158,7 @@ export async function activate(context: vscode.ExtensionContext) {
151158
targets,
152159
thatMark: thatMark,
153160
navigationMap: graph.navigationMap!,
154-
spokenForm: testCaseRecorder.spokenForm ?? "",
161+
spokenForm,
155162
};
156163
testCase = new TestCase(command, context);
157164
await testCase.recordInitialState();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
spokenForm: bring made
2+
languageId: typescript
3+
command:
4+
actionName: bring
5+
partialTargets:
6+
- type: primitive
7+
mark: {type: decoratedSymbol, symbolColor: default, character: m}
8+
- type: primitive
9+
mark: {type: cursor}
10+
selectionType: token
11+
position: contents
12+
modifier: {type: identity}
13+
insideOutsideType: inside
14+
extraArgs: []
15+
marks:
16+
default.m:
17+
start: {line: 0, character: 6}
18+
end: {line: 0, character: 21}
19+
initialState:
20+
documentContents: "const myVariableValue = \"hello\";\r\n"
21+
selections:
22+
- anchor: {line: 1, character: 0}
23+
active: {line: 1, character: 0}
24+
finalState:
25+
documentContents: "const myVariableValue = \"hello\";\r\nmyVariableValue"
26+
selections:
27+
- anchor: {line: 1, character: 15}
28+
active: {line: 1, character: 15}
29+
thatMark:
30+
- anchor: {line: 1, character: 15}
31+
active: {line: 1, character: 0}
32+
returnValue: null
33+
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: null}, {type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
spokenForm: bring made to cap
2+
languageId: typescript
3+
command:
4+
actionName: bring
5+
partialTargets:
6+
- type: primitive
7+
mark: {type: decoratedSymbol, symbolColor: default, character: m}
8+
- type: primitive
9+
mark: {type: decoratedSymbol, symbolColor: default, character: c}
10+
extraArgs: []
11+
marks:
12+
default.m:
13+
start: {line: 0, character: 6}
14+
end: {line: 0, character: 21}
15+
default.c:
16+
start: {line: 0, character: 0}
17+
end: {line: 0, character: 5}
18+
initialState:
19+
documentContents: "const myVariableValue = \"hello\";\r\n"
20+
selections:
21+
- anchor: {line: 1, character: 0}
22+
active: {line: 1, character: 0}
23+
finalState:
24+
documentContents: "myVariableValue myVariableValue = \"hello\";\r\n"
25+
selections:
26+
- anchor: {line: 1, character: 0}
27+
active: {line: 1, character: 0}
28+
thatMark:
29+
- anchor: {line: 0, character: 0}
30+
active: {line: 0, character: 15}
31+
returnValue: null
32+
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: null}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: c}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: null}]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
spokenForm: carve made
2+
languageId: typescript
3+
command:
4+
actionName: cut
5+
partialTargets:
6+
- type: primitive
7+
mark: {type: decoratedSymbol, symbolColor: default, character: m}
8+
extraArgs: []
9+
marks:
10+
default.m:
11+
start: {line: 0, character: 6}
12+
end: {line: 0, character: 21}
13+
initialState:
14+
documentContents: "const myVariableValue = \"hello\";\r\n"
15+
selections:
16+
- anchor: {line: 1, character: 0}
17+
active: {line: 1, character: 0}
18+
finalState:
19+
documentContents: "const = \"hello\";\r\n"
20+
selections:
21+
- anchor: {line: 1, character: 0}
22+
active: {line: 1, character: 0}
23+
thatMark:
24+
- anchor: {line: 0, character: 6}
25+
active: {line: 0, character: 6}
26+
returnValue: null
27+
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: null}]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
spokenForm: chuck made
2+
languageId: typescript
3+
command:
4+
actionName: delete
5+
partialTargets:
6+
- type: primitive
7+
mark: {type: decoratedSymbol, symbolColor: default, character: m}
8+
extraArgs: []
9+
marks:
10+
default.m:
11+
start: {line: 0, character: 6}
12+
end: {line: 0, character: 21}
13+
initialState:
14+
documentContents: "const myVariableValue = \"hello\";\r\n"
15+
selections:
16+
- anchor: {line: 1, character: 0}
17+
active: {line: 1, character: 0}
18+
finalState:
19+
documentContents: "const = \"hello\";\r\n"
20+
selections:
21+
- anchor: {line: 1, character: 0}
22+
active: {line: 1, character: 0}
23+
thatMark:
24+
- anchor: {line: 0, character: 6}
25+
active: {line: 0, character: 6}
26+
returnValue: null
27+
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: outside}]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
spokenForm: clear made
2+
languageId: typescript
3+
command:
4+
actionName: clear
5+
partialTargets:
6+
- type: primitive
7+
mark: {type: decoratedSymbol, symbolColor: default, character: m}
8+
extraArgs: []
9+
marks:
10+
default.m:
11+
start: {line: 0, character: 6}
12+
end: {line: 0, character: 21}
13+
initialState:
14+
documentContents: "const myVariableValue = \"hello\";\r\n"
15+
selections:
16+
- anchor: {line: 1, character: 0}
17+
active: {line: 1, character: 0}
18+
finalState:
19+
documentContents: "const = \"hello\";\r\n"
20+
selections:
21+
- anchor: {line: 0, character: 6}
22+
active: {line: 0, character: 6}
23+
thatMark:
24+
- anchor: {line: 0, character: 6}
25+
active: {line: 0, character: 6}
26+
returnValue: null
27+
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}]

0 commit comments

Comments
 (0)