aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/test/rust_diagnostics.test.ts
diff options
context:
space:
mode:
authorRyan Cumming <[email protected]>2019-06-26 11:14:18 +0100
committerRyan Cumming <[email protected]>2019-06-26 11:31:36 +0100
commitf82ceca0bd8de2a2b0b51c96c5c1678351a7a20a (patch)
tree89e70d9965f973615dc0dfe978db002d82bf7e25 /editors/code/src/test/rust_diagnostics.test.ts
parentafd18dbcb8147cb83de408b7da310ee187faf3df (diff)
Initial Visual Studio Code unit tests
As promised in #1439 this is an initial attempt at unit testing the VSCode extension. There are two separate parts to this: getting the test framework working and unit testing the code in #1439. The test framework nearly intact from the VSCode extension generator. The main thing missing was `test/index.ts` which acts as an entry point for Mocha. This was simply copied back in. I also needed to open the test VSCode instance inside a workspace as our file URI generation depends on a workspace being open. There are two ways to run the test framework: 1. Opening the extension's source in VSCode, pressing F5 and selecting the "Extensions Test" debug target. 2. Closing all copies of VSCode and running `npm test`. This is started from the command line but actually opens a temporary VSCode window to host the tests. This doesn't attempt to wire this up to CI. That requires running a headless X11 server which is a bit daunting. I'll assess the difficulty of that in a follow-up branch. This PR is at least helpful for local development without having to induce errors on a Rust project. For the actual tests this uses snapshots of `rustc` output from a real Rust project captured from the command line. Except for extracting the `message` object and reformatting they're copied verbatim into fixture JSON files. Only four different types of diagnostics are tested but they represent the main combinations of code actions and related information possible. They can be considered the happy path tests; as we encounter corner-cases we can introduce new tests fixtures.
Diffstat (limited to 'editors/code/src/test/rust_diagnostics.test.ts')
-rw-r--r--editors/code/src/test/rust_diagnostics.test.ts161
1 files changed, 161 insertions, 0 deletions
diff --git a/editors/code/src/test/rust_diagnostics.test.ts b/editors/code/src/test/rust_diagnostics.test.ts
new file mode 100644
index 000000000..5eb064b97
--- /dev/null
+++ b/editors/code/src/test/rust_diagnostics.test.ts
@@ -0,0 +1,161 @@
1import * as assert from 'assert';
2import * as fs from 'fs';
3import * as vscode from 'vscode';
4
5import {
6 MappedRustDiagnostic,
7 mapRustDiagnosticToVsCode,
8 RustDiagnostic
9} from '../utils/rust_diagnostics';
10
11function loadDiagnosticFixture(name: string): RustDiagnostic {
12 const jsonText = fs
13 .readFileSync(
14 // We're actually in our JavaScript output directory, climb out
15 `${__dirname}/../../src/test/fixtures/rust-diagnostics/${name}.json`
16 )
17 .toString();
18
19 return JSON.parse(jsonText);
20}
21
22function mapFixtureToVsCode(name: string): MappedRustDiagnostic {
23 const rd = loadDiagnosticFixture(name);
24 const mapResult = mapRustDiagnosticToVsCode(rd);
25
26 if (!mapResult) {
27 return assert.fail('Mapping unexpectedly failed');
28 }
29 return mapResult;
30}
31
32describe('mapRustDiagnosticToVsCode', () => {
33 it('should map an incompatible type for trait error', () => {
34 const { diagnostic, codeActions } = mapFixtureToVsCode('error/E0053');
35
36 assert.strictEqual(
37 diagnostic.severity,
38 vscode.DiagnosticSeverity.Error
39 );
40 assert.strictEqual(
41 diagnostic.message,
42 [
43 `method \`next\` has an incompatible type for trait`,
44 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``,
45 ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``
46 ].join('\n')
47 );
48 assert.strictEqual(diagnostic.code, 'E0053');
49 assert.strictEqual(diagnostic.tags, undefined);
50
51 // No related information
52 assert.deepStrictEqual(diagnostic.relatedInformation, []);
53
54 // There are no code actions available
55 assert.strictEqual(codeActions.length, 0);
56 });
57
58 it('should map an unused variable warning', () => {
59 const { diagnostic, codeActions } = mapFixtureToVsCode(
60 'warning/unused_variables'
61 );
62
63 assert.strictEqual(
64 diagnostic.severity,
65 vscode.DiagnosticSeverity.Warning
66 );
67 assert.strictEqual(
68 diagnostic.message,
69 [
70 'unused variable: `foo`',
71 '#[warn(unused_variables)] on by default'
72 ].join('\n')
73 );
74 assert.strictEqual(diagnostic.code, 'unused_variables');
75 assert.deepStrictEqual(diagnostic.tags, [
76 vscode.DiagnosticTag.Unnecessary
77 ]);
78
79 // No related information
80 assert.deepStrictEqual(diagnostic.relatedInformation, []);
81
82 // One code action available to prefix the variable
83 assert.strictEqual(codeActions.length, 1);
84 const [codeAction] = codeActions;
85 assert.strictEqual(
86 codeAction.title,
87 'consider prefixing with an underscore: `_foo`'
88 );
89 assert(codeAction.isPreferred);
90 });
91
92 it('should map a wrong number of parameters error', () => {
93 const { diagnostic, codeActions } = mapFixtureToVsCode('error/E0061');
94
95 assert.strictEqual(
96 diagnostic.severity,
97 vscode.DiagnosticSeverity.Error
98 );
99 assert.strictEqual(
100 diagnostic.message,
101 'this function takes 2 parameters but 3 parameters were supplied'
102 );
103 assert.strictEqual(diagnostic.code, 'E0061');
104 assert.strictEqual(diagnostic.tags, undefined);
105
106 // One related information for the original definition
107 const relatedInformation = diagnostic.relatedInformation;
108 if (!relatedInformation) {
109 return assert.fail('Related information unexpectedly undefined');
110 }
111 assert.strictEqual(relatedInformation.length, 1);
112 const [related] = relatedInformation;
113 assert.strictEqual(related.message, 'defined here');
114
115 // There are no actions available
116 assert.strictEqual(codeActions.length, 0);
117 });
118
119 it('should map a Clippy copy pass by ref warning', () => {
120 const { diagnostic, codeActions } = mapFixtureToVsCode(
121 'clippy/trivially_copy_pass_by_ref'
122 );
123
124 assert.strictEqual(
125 diagnostic.severity,
126 vscode.DiagnosticSeverity.Warning
127 );
128 assert.strictEqual(
129 diagnostic.message,
130 [
131 'this argument is passed by reference, but would be more efficient if passed by value',
132 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]',
133 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref'
134 ].join('\n')
135 );
136 assert.strictEqual(
137 diagnostic.code,
138 'clippy::trivially_copy_pass_by_ref'
139 );
140 assert.strictEqual(diagnostic.tags, undefined);
141
142 // One related information for the lint definition
143 const relatedInformation = diagnostic.relatedInformation;
144 if (!relatedInformation) {
145 return assert.fail('Related information unexpectedly undefined');
146 }
147 assert.strictEqual(relatedInformation.length, 1);
148 const [related] = relatedInformation;
149 assert.strictEqual(related.message, 'lint level defined here');
150
151 // One code action available to pass by value
152 assert.strictEqual(codeActions.length, 1);
153 const [codeAction] = codeActions;
154 assert.strictEqual(
155 codeAction.title,
156 'consider passing by value instead: `self`'
157 );
158 // Clippy does not mark this as machine applicable
159 assert.strictEqual(codeAction.isPreferred, false);
160 });
161});