Skip to content

Commit 8e4c559

Browse files
authored
Merge pull request #18829 from amcasey/JsExtractTests
Improve Extract* unit test coverage and correctness
2 parents 7959bd0 + a73a553 commit 8e4c559

19 files changed

+446
-30
lines changed

src/harness/unittests/extractTestHelpers.ts

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -98,35 +98,41 @@ namespace ts {
9898
}
9999

100100
export function testExtractSymbol(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage) {
101-
it(caption, () => {
102-
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}.ts`, () => {
103-
const t = extractTest(text);
104-
const selectionRange = t.ranges.get("selection");
105-
if (!selectionRange) {
106-
throw new Error(`Test ${caption} does not specify selection range`);
107-
}
108-
const f = {
109-
path: "/a.ts",
110-
content: t.source
111-
};
112-
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
113-
const projectService = projectSystem.createProjectService(host);
114-
projectService.openClientFile(f.path);
115-
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
116-
const sourceFile = program.getSourceFile(f.path);
117-
const context: RefactorContext = {
118-
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
119-
newLineCharacter,
120-
program,
121-
file: sourceFile,
122-
startPosition: selectionRange.start,
123-
endPosition: selectionRange.end,
124-
rulesProvider: getRuleProvider()
125-
};
126-
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
127-
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
128-
const infos = refactor.extractSymbol.getAvailableActions(context);
129-
const actions = find(infos, info => info.description === description.message).actions;
101+
const t = extractTest(text);
102+
const selectionRange = t.ranges.get("selection");
103+
if (!selectionRange) {
104+
throw new Error(`Test ${caption} does not specify selection range`);
105+
}
106+
107+
[Extension.Ts, Extension.Js].forEach(extension =>
108+
it(`${caption} [${extension}]`, () => runBaseline(extension)));
109+
110+
function runBaseline(extension: Extension) {
111+
const path = "/a" + extension;
112+
const program = makeProgram({ path, content: t.source });
113+
114+
if (hasSyntacticDiagnostics(program)) {
115+
// Don't bother generating JS baselines for inputs that aren't valid JS.
116+
assert.equal(Extension.Js, extension);
117+
return;
118+
}
119+
120+
const sourceFile = program.getSourceFile(path);
121+
const context: RefactorContext = {
122+
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
123+
newLineCharacter,
124+
program,
125+
file: sourceFile,
126+
startPosition: selectionRange.start,
127+
endPosition: selectionRange.end,
128+
rulesProvider: getRuleProvider()
129+
};
130+
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
131+
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
132+
const infos = refactor.extractSymbol.getAvailableActions(context);
133+
const actions = find(infos, info => info.description === description.message).actions;
134+
135+
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, () => {
130136
const data: string[] = [];
131137
data.push(`// ==ORIGINAL==`);
132138
data.push(sourceFile.text);
@@ -137,10 +143,26 @@ namespace ts {
137143
const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges);
138144
const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + newText.slice(renameLocation);
139145
data.push(newTextWithRename);
146+
147+
const diagProgram = makeProgram({ path, content: newText });
148+
assert.isFalse(hasSyntacticDiagnostics(diagProgram));
140149
}
141150
return data.join(newLineCharacter);
142151
});
143-
});
152+
}
153+
154+
function makeProgram(f: {path: string, content: string }) {
155+
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
156+
const projectService = projectSystem.createProjectService(host);
157+
projectService.openClientFile(f.path);
158+
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
159+
return program;
160+
}
161+
162+
function hasSyntacticDiagnostics(program: Program) {
163+
const diags = program.getSyntacticDiagnostics();
164+
return length(diags) > 0;
165+
}
144166
}
145167

146168
export function testExtractSymbolFailed(caption: string, text: string, description: DiagnosticMessage) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ==ORIGINAL==
2+
for (let i = 0; i < 10; i++) {
3+
for (let j = 0; j < 10; j++) {
4+
let x = 1;
5+
}
6+
}
7+
// ==SCOPE::Extract to constant in global scope==
8+
const newLocal = 1;
9+
10+
for (let i = 0; i < 10; i++) {
11+
for (let j = 0; j < 10; j++) {
12+
let x = /*RENAME*/newLocal;
13+
}
14+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// ==ORIGINAL==
2+
class C {
3+
x = 1;
4+
}
5+
// ==SCOPE::Extract to constant in global scope==
6+
const newLocal = 1;
7+
8+
class C {
9+
x = /*RENAME*/newLocal;
10+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// ==ORIGINAL==
2+
class C {
3+
a = 1;
4+
b = 2;
5+
M1() { }
6+
M2() { }
7+
M3() {
8+
let x = 1;
9+
}
10+
}
11+
// ==SCOPE::Extract to constant in method 'M3==
12+
class C {
13+
a = 1;
14+
b = 2;
15+
M1() { }
16+
M2() { }
17+
M3() {
18+
const newLocal = 1;
19+
20+
let x = /*RENAME*/newLocal;
21+
}
22+
}
23+
// ==SCOPE::Extract to constant in global scope==
24+
const newLocal = 1;
25+
26+
class C {
27+
a = 1;
28+
b = 2;
29+
M1() { }
30+
M2() { }
31+
M3() {
32+
let x = /*RENAME*/newLocal;
33+
}
34+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// ==ORIGINAL==
2+
"hello";
3+
// ==SCOPE::Extract to constant in global scope==
4+
const /*RENAME*/newLocal = "hello";
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// ==ORIGINAL==
2+
"hello";
3+
// ==SCOPE::Extract to constant in global scope==
4+
const /*RENAME*/newLocal = "hello";
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// ==ORIGINAL==
2+
function F() {
3+
let x = 1;
4+
}
5+
// ==SCOPE::Extract to constant in function 'F'==
6+
function F() {
7+
const newLocal = 1;
8+
9+
let x = /*RENAME*/newLocal;
10+
}
11+
// ==SCOPE::Extract to constant in global scope==
12+
const newLocal = 1;
13+
14+
function F() {
15+
let x = /*RENAME*/newLocal;
16+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// ==ORIGINAL==
2+
class C {
3+
M() {
4+
let x = 1;
5+
}
6+
}
7+
// ==SCOPE::Extract to constant in method 'M==
8+
class C {
9+
M() {
10+
const newLocal = 1;
11+
12+
let x = /*RENAME*/newLocal;
13+
}
14+
}
15+
// ==SCOPE::Extract to constant in global scope==
16+
const newLocal = 1;
17+
18+
class C {
19+
M() {
20+
let x = /*RENAME*/newLocal;
21+
}
22+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// ==ORIGINAL==
2+
function F() {
3+
let w = 1;
4+
let x = w + 1;
5+
}
6+
// ==SCOPE::Extract to constant in function 'F'==
7+
function F() {
8+
let w = 1;
9+
const newLocal = w + 1;
10+
11+
let x = /*RENAME*/newLocal;
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// ==ORIGINAL==
2+
let x = 1;
3+
// ==SCOPE::Extract to constant in global scope==
4+
const newLocal = 1;
5+
6+
let x = /*RENAME*/newLocal;

0 commit comments

Comments
 (0)