Skip to content

Commit 65c838f

Browse files
committed
unit test for variable extraction #220
1 parent de2b0a1 commit 65c838f

4 files changed

Lines changed: 362 additions & 20 deletions

File tree

src/client/providers/simpleRefactorProvider.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,48 +10,50 @@ interface RenameResponse {
1010
results: [{ diff: string }];
1111
}
1212

13-
let pythonOutputChannel: vscode.OutputChannel;
14-
let extensionContext: vscode.ExtensionContext;
15-
1613
export function activateSimplePythonRefactorProvider(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel) {
17-
pythonOutputChannel = outputChannel;
18-
extensionContext = context;
1914
let disposable = vscode.commands.registerCommand('python.refactorExtractVariable', () => {
2015
extractVariable(context.extensionPath,
2116
vscode.window.activeTextEditor,
22-
vscode.window.activeTextEditor.selection);
17+
vscode.window.activeTextEditor.selection,
18+
outputChannel);
2319
});
2420
context.subscriptions.push(disposable);
2521

2622
disposable = vscode.commands.registerCommand('python.refactorExtractMethod', () => {
2723
extractMethod(context.extensionPath,
2824
vscode.window.activeTextEditor,
29-
vscode.window.activeTextEditor.selection);
25+
vscode.window.activeTextEditor.selection,
26+
outputChannel);
3027
});
3128
context.subscriptions.push(disposable);
3229
}
3330

34-
function extractVariable(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range): Promise<any> {
31+
// Exported for unit testing
32+
export function extractVariable(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range,
33+
outputChannel: vscode.OutputChannel, workspaceRoot: string = vscode.workspace.rootPath, renameAfterExtration: boolean = true): Promise<any> {
3534
let newName = 'newvariable' + new Date().getMilliseconds().toString();
36-
let proxy = new RefactorProxy(extensionContext);
35+
let proxy = new RefactorProxy(extensionDir, workspaceRoot);
3736
let rename = proxy.extractVariable<RenameResponse>(textEditor.document, newName, textEditor.document.uri.fsPath, range).then(response => {
3837
return response.results[0].diff;
3938
});
4039

41-
return extractName(extensionDir, textEditor, range, newName, rename);
40+
return extractName(extensionDir, textEditor, range, newName, rename, outputChannel, renameAfterExtration);
4241
}
4342

44-
function extractMethod(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range): Promise<any> {
43+
// Exported for unit testing
44+
export function extractMethod(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range,
45+
outputChannel: vscode.OutputChannel, workspaceRoot: string = vscode.workspace.rootPath, renameAfterExtration: boolean = true): Promise<any> {
4546
let newName = 'newmethod' + new Date().getMilliseconds().toString();
46-
let proxy = new RefactorProxy(extensionContext);
47+
let proxy = new RefactorProxy(extensionDir, workspaceRoot);
4748
let rename = proxy.extractMethod<RenameResponse>(textEditor.document, newName, textEditor.document.uri.fsPath, range).then(response => {
4849
return response.results[0].diff;
4950
});
5051

51-
return extractName(extensionDir, textEditor, range, newName, rename);
52+
return extractName(extensionDir, textEditor, range, newName, rename, outputChannel, renameAfterExtration);
5253
}
5354

54-
function extractName(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range, newName: string, renameResponse: Promise<string>): Promise<any> {
55+
function extractName(extensionDir: string, textEditor: vscode.TextEditor, range: vscode.Range, newName: string,
56+
renameResponse: Promise<string>, outputChannel: vscode.OutputChannel, renameAfterExtration: boolean = true): Promise<any> {
5557
let changeStartsAtLine = -1;
5658
return renameResponse.then(diff => {
5759
if (diff.length === 0) {
@@ -69,7 +71,7 @@ function extractName(extensionDir: string, textEditor: vscode.TextEditor, range:
6971
});
7072
});
7173
}).then(done => {
72-
if (done && changeStartsAtLine >= 0) {
74+
if (done && changeStartsAtLine >= 0 && renameAfterExtration) {
7375
let newWordPosition: vscode.Position;
7476
for (let lineNumber = changeStartsAtLine; lineNumber < textEditor.document.lineCount; lineNumber++) {
7577
let line = textEditor.document.lineAt(lineNumber);
@@ -96,8 +98,8 @@ function extractName(extensionDir: string, textEditor: vscode.TextEditor, range:
9698
if (typeof error === 'object' && error.message) {
9799
errorMessage = `Refactor failed, ${error.message}`;
98100
}
99-
pythonOutputChannel.appendLine('#'.repeat(10) + 'Refactor Output' + '#'.repeat(10));
100-
pythonOutputChannel.appendLine('Error in refactoring:\n' + errorMessage);
101+
outputChannel.appendLine('#'.repeat(10) + 'Refactor Output' + '#'.repeat(10));
102+
outputChannel.appendLine('Error in refactoring:\n' + errorMessage);
101103
console.error(error);
102104
vscode.window.showErrorMessage(errorMessage);
103105
});

src/client/refactor/proxy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ export class RefactorProxy extends vscode.Disposable {
2020
private _initializeReject: (reason?: any) => void;
2121
static pythonPath: string;
2222
private _settings: PythonSettings;
23-
constructor(context: vscode.ExtensionContext) {
23+
constructor(extensionDir: string, private workspaceRoot: string = vscode.workspace.rootPath) {
2424
super(() => { });
25-
this._extensionDir = context.extensionPath;
25+
this._extensionDir = extensionDir;
2626
this._settings = PythonSettings.getInstance();
2727
vscode.workspace.onDidChangeConfiguration(() => {
2828
RefactorProxy.pythonPath = '';
@@ -93,7 +93,7 @@ export class RefactorProxy extends vscode.Disposable {
9393
private initialize(pythonPath: string): Promise<string> {
9494
return new Promise<any>((resolve, reject) => {
9595
this._initializeReject = reject;
96-
this._process = child_process.spawn(pythonPath, ['-u', 'refactor.py', vscode.workspace.rootPath, path.join(vscode.workspace.rootPath, '.vscode', 'rope')],
96+
this._process = child_process.spawn(pythonPath, ['-u', 'refactor.py', this.workspaceRoot, path.join(this.workspaceRoot, '.vscode', 'rope')],
9797
{
9898
cwd: path.join(this._extensionDir, 'pythonFiles')
9999
});
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import * as assert from 'assert';
2+
3+
// You can import and use all API from the \'vscode\' module
4+
// as well as import your extension to test it
5+
import * as vscode from 'vscode';
6+
import * as path from 'path';
7+
import * as settings from '../client/common/configSettings';
8+
import * as fs from 'fs-extra';
9+
import {initialize} from './initialize';
10+
import {execPythonFile} from '../client/common/utils';
11+
import {extractVariable, extractMethod} from '../client/providers/simpleRefactorProvider';
12+
13+
let EXTENSION_DIR = path.join(__dirname, '..', '..');
14+
let pythonSettings = settings.PythonSettings.getInstance();
15+
16+
const refactorSourceFile = path.join(__dirname, '..', '..', 'src', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py');
17+
const refactorTargetFile = path.join(__dirname, '..', '..', 'out', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py');
18+
let isPython3 = true;
19+
class MockOutputChannel implements vscode.OutputChannel {
20+
constructor(name: string) {
21+
this.name = name;
22+
this.output = '';
23+
}
24+
name: string;
25+
output: string;
26+
append(value: string) {
27+
this.output += value;
28+
}
29+
appendLine(value: string) { this.append(value); this.append('\n'); }
30+
clear() { }
31+
show(preservceFocus?: boolean): void;
32+
show(column?: vscode.ViewColumn, preserveFocus?: boolean): void;
33+
show(x?: any, y?: any): void { }
34+
hide() { }
35+
dispose() { }
36+
}
37+
suiteSetup(done => {
38+
fs.copySync(refactorSourceFile, refactorTargetFile, { clobber: true });
39+
initialize().then(() => {
40+
new Promise<string>(resolve => {
41+
// Support for travis
42+
let version = process.env['TRAVIS_PYTHON_VERSION'];
43+
if (typeof version === 'string') {
44+
return resolve(version);
45+
}
46+
// Support for local tests
47+
execPythonFile('python', ['--version'], __dirname, true).then(resolve);
48+
}).then(version => {
49+
isPython3 = version.indexOf('3.') >= 0;
50+
done();
51+
});
52+
});
53+
});
54+
suiteTeardown(done => {
55+
// deleteFile(targetPythonFileToLint).then(done, done);
56+
done();
57+
});
58+
59+
suite('Simple Refactor', () => {
60+
setup(() => {
61+
if (fs.existsSync(refactorTargetFile)) {
62+
fs.unlinkSync(refactorTargetFile);
63+
}
64+
fs.copySync(refactorSourceFile, refactorTargetFile, { clobber: true });
65+
});
66+
teardown(() => {
67+
if (vscode.window.activeTextEditor) {
68+
return vscode.commands.executeCommand('workbench.action.closeActiveEditor');
69+
}
70+
});
71+
72+
test('Extract Variable', () => {
73+
let ch = new MockOutputChannel('Lint');
74+
let textDocument: vscode.TextDocument;
75+
let textEditor: vscode.TextEditor;
76+
let rangeOfTextToExtract = new vscode.Range(new vscode.Position(234, 29), new vscode.Position(234, 38));
77+
return vscode.workspace.openTextDocument(refactorTargetFile).then(document => {
78+
textDocument = document;
79+
return vscode.window.showTextDocument(textDocument);
80+
}).then(editor => {
81+
editor.selections = [new vscode.Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end)];
82+
editor.selection = new vscode.Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end);
83+
textEditor = editor;
84+
return;
85+
}).then(() => {
86+
return extractVariable(EXTENSION_DIR, textEditor, rangeOfTextToExtract, ch, path.dirname(refactorTargetFile), false).then(() => {
87+
assert.equal(textDocument.lineAt(234).text.trim().indexOf('newvariable'), 0, 'New Variable not created');
88+
assert.equal(textDocument.lineAt(234).text.trim().endsWith('= "STARTED"'), true, 'Started Text Assigned to variable');
89+
assert.equal(textDocument.lineAt(235).text.indexOf('(newvariable') >= 0, true, 'New Variable not being used');
90+
}).catch(error => {
91+
assert.fail(error, null, 'Variable extraction failed');
92+
});
93+
});
94+
});
95+
});

0 commit comments

Comments
 (0)