aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
diff options
context:
space:
mode:
authorRyan Cumming <[email protected]>2019-06-27 12:30:23 +0100
committerRyan Cumming <[email protected]>2019-06-29 08:39:36 +0100
commitabc0784e57610a0cceca63301489918015418df6 (patch)
tree05aec9fef88f31cee82e3507903a1dbcd6b4d30d /editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
parent0e1912de528b5092c10eedaf94c43c67d5f86f1a (diff)
Fix `cargo watch` code action filtering
There are two issues with the implementation of `provideCodeActions` introduced in #1439: 1. We're returning the code action based on the file its diagnostic is in; not the file the suggested fix is in. I'm not sure how often fixes are suggested cross-file but it's something we should handle. 2. We're not filtering code actions based on the passed range. The means if there is any suggestion in a file we'll show an action for every line of the file. I naively thought that VS Code would filter for us but that was wrong. Unfortunately the VS Code `CodeAction` object is very complex - it can handle edits across multiple files, run commands, etc. This makes it complex to check them for equality or see if any of their edits intersects with a specified range. To make it easier to work with suggestions this introduces a `SuggestedFix` model object and a `SuggestFixCollection` code action provider. This is a layer between the raw Rust JSON and VS Code's `CodeAction`s. I was reluctant to introduce another layer of abstraction here but my attempt to work directly with VS Code's model objects was worse.
Diffstat (limited to 'editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts')
-rw-r--r--editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts125
1 files changed, 125 insertions, 0 deletions
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
new file mode 100644
index 000000000..f0328893e
--- /dev/null
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
@@ -0,0 +1,125 @@
1import * as assert from 'assert';
2import * as vscode from 'vscode';
3
4import SuggestedFix from '../../../utils/diagnostics/SuggestedFix';
5import SuggestedFixCollection from '../../../utils/diagnostics/SuggestedFixCollection';
6
7const uri1 = vscode.Uri.file('/file/1');
8const uri2 = vscode.Uri.file('/file/2');
9
10const mockDocument1 = ({
11 uri: uri1
12} as unknown) as vscode.TextDocument;
13
14const mockDocument2 = ({
15 uri: uri2
16} as unknown) as vscode.TextDocument;
17
18const range1 = new vscode.Range(
19 new vscode.Position(1, 2),
20 new vscode.Position(3, 4)
21);
22const range2 = new vscode.Range(
23 new vscode.Position(5, 6),
24 new vscode.Position(7, 8)
25);
26
27const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic');
28const diagnostic2 = new vscode.Diagnostic(range2, 'Second diagnostic');
29
30// This is a mutable object so return a fresh instance every time
31function suggestion1(): SuggestedFix {
32 return new SuggestedFix(
33 'Replace me!',
34 new vscode.Location(uri1, range1),
35 'With this!'
36 );
37}
38
39describe('SuggestedFixCollection', () => {
40 it('should add a suggestion then return it as a code action', () => {
41 const suggestedFixes = new SuggestedFixCollection();
42 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
43
44 // Specify the document and range that exactly matches
45 const codeActions = suggestedFixes.provideCodeActions(
46 mockDocument1,
47 range1
48 );
49
50 assert.strictEqual(codeActions.length, 1);
51 const [codeAction] = codeActions;
52 assert.strictEqual(codeAction.title, suggestion1().title);
53
54 const { diagnostics } = codeAction;
55 if (!diagnostics) {
56 return assert.fail('Diagnostics unexpectedly missing');
57 }
58
59 assert.strictEqual(diagnostics.length, 1);
60 assert.strictEqual(diagnostics[0], diagnostic1);
61 });
62
63 it('should not return code actions for different ranges', () => {
64 const suggestedFixes = new SuggestedFixCollection();
65 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
66
67 const codeActions = suggestedFixes.provideCodeActions(
68 mockDocument1,
69 range2
70 );
71
72 assert(!codeActions || codeActions.length === 0);
73 });
74
75 it('should not return code actions for different documents', () => {
76 const suggestedFixes = new SuggestedFixCollection();
77 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
78
79 const codeActions = suggestedFixes.provideCodeActions(
80 mockDocument2,
81 range1
82 );
83
84 assert(!codeActions || codeActions.length === 0);
85 });
86
87 it('should not return code actions that have been cleared', () => {
88 const suggestedFixes = new SuggestedFixCollection();
89 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
90 suggestedFixes.clear();
91
92 const codeActions = suggestedFixes.provideCodeActions(
93 mockDocument1,
94 range1
95 );
96
97 assert(!codeActions || codeActions.length === 0);
98 });
99
100 it('should merge identical suggestions together', () => {
101 const suggestedFixes = new SuggestedFixCollection();
102
103 // Add the same suggestion for two diagnostics
104 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic1);
105 suggestedFixes.addSuggestedFixForDiagnostic(suggestion1(), diagnostic2);
106
107 const codeActions = suggestedFixes.provideCodeActions(
108 mockDocument1,
109 range1
110 );
111
112 assert.strictEqual(codeActions.length, 1);
113 const [codeAction] = codeActions;
114 const { diagnostics } = codeAction;
115
116 if (!diagnostics) {
117 return assert.fail('Diagnostics unexpectedly missing');
118 }
119
120 // We should be associated with both diagnostics
121 assert.strictEqual(diagnostics.length, 2);
122 assert.strictEqual(diagnostics[0], diagnostic1);
123 assert.strictEqual(diagnostics[1], diagnostic2);
124 });
125});