diff options
Diffstat (limited to 'editors/code/src/test')
7 files changed, 704 insertions, 0 deletions
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/clippy/trivially_copy_pass_by_ref.json b/editors/code/src/test/fixtures/rust-diagnostics/clippy/trivially_copy_pass_by_ref.json new file mode 100644 index 000000000..d874e99bc --- /dev/null +++ b/editors/code/src/test/fixtures/rust-diagnostics/clippy/trivially_copy_pass_by_ref.json | |||
@@ -0,0 +1,110 @@ | |||
1 | { | ||
2 | "message": "this argument is passed by reference, but would be more efficient if passed by value", | ||
3 | "code": { | ||
4 | "code": "clippy::trivially_copy_pass_by_ref", | ||
5 | "explanation": null | ||
6 | }, | ||
7 | "level": "warning", | ||
8 | "spans": [ | ||
9 | { | ||
10 | "file_name": "compiler/mir/tagset.rs", | ||
11 | "byte_start": 941, | ||
12 | "byte_end": 946, | ||
13 | "line_start": 42, | ||
14 | "line_end": 42, | ||
15 | "column_start": 24, | ||
16 | "column_end": 29, | ||
17 | "is_primary": true, | ||
18 | "text": [ | ||
19 | { | ||
20 | "text": " pub fn is_disjoint(&self, other: Self) -> bool {", | ||
21 | "highlight_start": 24, | ||
22 | "highlight_end": 29 | ||
23 | } | ||
24 | ], | ||
25 | "label": null, | ||
26 | "suggested_replacement": null, | ||
27 | "suggestion_applicability": null, | ||
28 | "expansion": null | ||
29 | } | ||
30 | ], | ||
31 | "children": [ | ||
32 | { | ||
33 | "message": "lint level defined here", | ||
34 | "code": null, | ||
35 | "level": "note", | ||
36 | "spans": [ | ||
37 | { | ||
38 | "file_name": "compiler/lib.rs", | ||
39 | "byte_start": 8, | ||
40 | "byte_end": 19, | ||
41 | "line_start": 1, | ||
42 | "line_end": 1, | ||
43 | "column_start": 9, | ||
44 | "column_end": 20, | ||
45 | "is_primary": true, | ||
46 | "text": [ | ||
47 | { | ||
48 | "text": "#![warn(clippy::all)]", | ||
49 | "highlight_start": 9, | ||
50 | "highlight_end": 20 | ||
51 | } | ||
52 | ], | ||
53 | "label": null, | ||
54 | "suggested_replacement": null, | ||
55 | "suggestion_applicability": null, | ||
56 | "expansion": null | ||
57 | } | ||
58 | ], | ||
59 | "children": [], | ||
60 | "rendered": null | ||
61 | }, | ||
62 | { | ||
63 | "message": "#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]", | ||
64 | "code": null, | ||
65 | "level": "note", | ||
66 | "spans": [], | ||
67 | "children": [], | ||
68 | "rendered": null | ||
69 | }, | ||
70 | { | ||
71 | "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", | ||
72 | "code": null, | ||
73 | "level": "help", | ||
74 | "spans": [], | ||
75 | "children": [], | ||
76 | "rendered": null | ||
77 | }, | ||
78 | { | ||
79 | "message": "consider passing by value instead", | ||
80 | "code": null, | ||
81 | "level": "help", | ||
82 | "spans": [ | ||
83 | { | ||
84 | "file_name": "compiler/mir/tagset.rs", | ||
85 | "byte_start": 941, | ||
86 | "byte_end": 946, | ||
87 | "line_start": 42, | ||
88 | "line_end": 42, | ||
89 | "column_start": 24, | ||
90 | "column_end": 29, | ||
91 | "is_primary": true, | ||
92 | "text": [ | ||
93 | { | ||
94 | "text": " pub fn is_disjoint(&self, other: Self) -> bool {", | ||
95 | "highlight_start": 24, | ||
96 | "highlight_end": 29 | ||
97 | } | ||
98 | ], | ||
99 | "label": null, | ||
100 | "suggested_replacement": "self", | ||
101 | "suggestion_applicability": "Unspecified", | ||
102 | "expansion": null | ||
103 | } | ||
104 | ], | ||
105 | "children": [], | ||
106 | "rendered": null | ||
107 | } | ||
108 | ], | ||
109 | "rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n" | ||
110 | } | ||
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/error/E0053.json b/editors/code/src/test/fixtures/rust-diagnostics/error/E0053.json new file mode 100644 index 000000000..ea5c976d1 --- /dev/null +++ b/editors/code/src/test/fixtures/rust-diagnostics/error/E0053.json | |||
@@ -0,0 +1,42 @@ | |||
1 | { | ||
2 | "message": "method `next` has an incompatible type for trait", | ||
3 | "code": { | ||
4 | "code": "E0053", | ||
5 | "explanation": "\nThe parameters of any trait method must match between a trait implementation\nand the trait definition.\n\nHere are a couple examples of this error:\n\n```compile_fail,E0053\ntrait Foo {\n fn foo(x: u16);\n fn bar(&self);\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n // error, expected u16, found i16\n fn foo(x: i16) { }\n\n // error, types differ in mutability\n fn bar(&mut self) { }\n}\n```\n" | ||
6 | }, | ||
7 | "level": "error", | ||
8 | "spans": [ | ||
9 | { | ||
10 | "file_name": "compiler/ty/list_iter.rs", | ||
11 | "byte_start": 1307, | ||
12 | "byte_end": 1350, | ||
13 | "line_start": 52, | ||
14 | "line_end": 52, | ||
15 | "column_start": 5, | ||
16 | "column_end": 48, | ||
17 | "is_primary": true, | ||
18 | "text": [ | ||
19 | { | ||
20 | "text": " fn next(&self) -> Option<&'list ty::Ref<M>> {", | ||
21 | "highlight_start": 5, | ||
22 | "highlight_end": 48 | ||
23 | } | ||
24 | ], | ||
25 | "label": "types differ in mutability", | ||
26 | "suggested_replacement": null, | ||
27 | "suggestion_applicability": null, | ||
28 | "expansion": null | ||
29 | } | ||
30 | ], | ||
31 | "children": [ | ||
32 | { | ||
33 | "message": "expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`", | ||
34 | "code": null, | ||
35 | "level": "note", | ||
36 | "spans": [], | ||
37 | "children": [], | ||
38 | "rendered": null | ||
39 | } | ||
40 | ], | ||
41 | "rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref<M>> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`\n\n" | ||
42 | } | ||
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/error/E0061.json b/editors/code/src/test/fixtures/rust-diagnostics/error/E0061.json new file mode 100644 index 000000000..3154d1098 --- /dev/null +++ b/editors/code/src/test/fixtures/rust-diagnostics/error/E0061.json | |||
@@ -0,0 +1,114 @@ | |||
1 | { | ||
2 | "message": "this function takes 2 parameters but 3 parameters were supplied", | ||
3 | "code": { | ||
4 | "code": "E0061", | ||
5 | "explanation": "\nThe number of arguments passed to a function must match the number of arguments\nspecified in the function signature.\n\nFor example, a function like:\n\n```\nfn f(a: u16, b: &str) {}\n```\n\nMust always be called with exactly two arguments, e.g., `f(2, \"test\")`.\n\nNote that Rust does not have a notion of optional function arguments or\nvariadic functions (except for its C-FFI).\n" | ||
6 | }, | ||
7 | "level": "error", | ||
8 | "spans": [ | ||
9 | { | ||
10 | "file_name": "compiler/ty/select.rs", | ||
11 | "byte_start": 8787, | ||
12 | "byte_end": 9241, | ||
13 | "line_start": 219, | ||
14 | "line_end": 231, | ||
15 | "column_start": 5, | ||
16 | "column_end": 6, | ||
17 | "is_primary": false, | ||
18 | "text": [ | ||
19 | { | ||
20 | "text": " pub fn add_evidence(", | ||
21 | "highlight_start": 5, | ||
22 | "highlight_end": 25 | ||
23 | }, | ||
24 | { | ||
25 | "text": " &mut self,", | ||
26 | "highlight_start": 1, | ||
27 | "highlight_end": 19 | ||
28 | }, | ||
29 | { | ||
30 | "text": " target_poly: &ty::Ref<ty::Poly>,", | ||
31 | "highlight_start": 1, | ||
32 | "highlight_end": 41 | ||
33 | }, | ||
34 | { | ||
35 | "text": " evidence_poly: &ty::Ref<ty::Poly>,", | ||
36 | "highlight_start": 1, | ||
37 | "highlight_end": 43 | ||
38 | }, | ||
39 | { | ||
40 | "text": " ) {", | ||
41 | "highlight_start": 1, | ||
42 | "highlight_end": 8 | ||
43 | }, | ||
44 | { | ||
45 | "text": " match target_poly {", | ||
46 | "highlight_start": 1, | ||
47 | "highlight_end": 28 | ||
48 | }, | ||
49 | { | ||
50 | "text": " ty::Ref::Var(tvar, _) => self.add_var_evidence(tvar, evidence_poly),", | ||
51 | "highlight_start": 1, | ||
52 | "highlight_end": 81 | ||
53 | }, | ||
54 | { | ||
55 | "text": " ty::Ref::Fixed(target_ty) => {", | ||
56 | "highlight_start": 1, | ||
57 | "highlight_end": 43 | ||
58 | }, | ||
59 | { | ||
60 | "text": " let evidence_ty = evidence_poly.resolve_to_ty();", | ||
61 | "highlight_start": 1, | ||
62 | "highlight_end": 65 | ||
63 | }, | ||
64 | { | ||
65 | "text": " self.add_evidence_ty(target_ty, evidence_poly, evidence_ty)", | ||
66 | "highlight_start": 1, | ||
67 | "highlight_end": 76 | ||
68 | }, | ||
69 | { | ||
70 | "text": " }", | ||
71 | "highlight_start": 1, | ||
72 | "highlight_end": 14 | ||
73 | }, | ||
74 | { | ||
75 | "text": " }", | ||
76 | "highlight_start": 1, | ||
77 | "highlight_end": 10 | ||
78 | }, | ||
79 | { | ||
80 | "text": " }", | ||
81 | "highlight_start": 1, | ||
82 | "highlight_end": 6 | ||
83 | } | ||
84 | ], | ||
85 | "label": "defined here", | ||
86 | "suggested_replacement": null, | ||
87 | "suggestion_applicability": null, | ||
88 | "expansion": null | ||
89 | }, | ||
90 | { | ||
91 | "file_name": "compiler/ty/select.rs", | ||
92 | "byte_start": 4045, | ||
93 | "byte_end": 4057, | ||
94 | "line_start": 104, | ||
95 | "line_end": 104, | ||
96 | "column_start": 18, | ||
97 | "column_end": 30, | ||
98 | "is_primary": true, | ||
99 | "text": [ | ||
100 | { | ||
101 | "text": " self.add_evidence(target_fixed, evidence_fixed, false);", | ||
102 | "highlight_start": 18, | ||
103 | "highlight_end": 30 | ||
104 | } | ||
105 | ], | ||
106 | "label": "expected 2 parameters", | ||
107 | "suggested_replacement": null, | ||
108 | "suggestion_applicability": null, | ||
109 | "expansion": null | ||
110 | } | ||
111 | ], | ||
112 | "children": [], | ||
113 | "rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref<ty::Poly>,\n222 | | evidence_poly: &ty::Ref<ty::Poly>,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n" | ||
114 | } | ||
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/warning/unused_variables.json b/editors/code/src/test/fixtures/rust-diagnostics/warning/unused_variables.json new file mode 100644 index 000000000..d1e2be722 --- /dev/null +++ b/editors/code/src/test/fixtures/rust-diagnostics/warning/unused_variables.json | |||
@@ -0,0 +1,72 @@ | |||
1 | { | ||
2 | "message": "unused variable: `foo`", | ||
3 | "code": { | ||
4 | "code": "unused_variables", | ||
5 | "explanation": null | ||
6 | }, | ||
7 | "level": "warning", | ||
8 | "spans": [ | ||
9 | { | ||
10 | "file_name": "driver/subcommand/repl.rs", | ||
11 | "byte_start": 9228, | ||
12 | "byte_end": 9231, | ||
13 | "line_start": 291, | ||
14 | "line_end": 291, | ||
15 | "column_start": 9, | ||
16 | "column_end": 12, | ||
17 | "is_primary": true, | ||
18 | "text": [ | ||
19 | { | ||
20 | "text": " let foo = 42;", | ||
21 | "highlight_start": 9, | ||
22 | "highlight_end": 12 | ||
23 | } | ||
24 | ], | ||
25 | "label": null, | ||
26 | "suggested_replacement": null, | ||
27 | "suggestion_applicability": null, | ||
28 | "expansion": null | ||
29 | } | ||
30 | ], | ||
31 | "children": [ | ||
32 | { | ||
33 | "message": "#[warn(unused_variables)] on by default", | ||
34 | "code": null, | ||
35 | "level": "note", | ||
36 | "spans": [], | ||
37 | "children": [], | ||
38 | "rendered": null | ||
39 | }, | ||
40 | { | ||
41 | "message": "consider prefixing with an underscore", | ||
42 | "code": null, | ||
43 | "level": "help", | ||
44 | "spans": [ | ||
45 | { | ||
46 | "file_name": "driver/subcommand/repl.rs", | ||
47 | "byte_start": 9228, | ||
48 | "byte_end": 9231, | ||
49 | "line_start": 291, | ||
50 | "line_end": 291, | ||
51 | "column_start": 9, | ||
52 | "column_end": 12, | ||
53 | "is_primary": true, | ||
54 | "text": [ | ||
55 | { | ||
56 | "text": " let foo = 42;", | ||
57 | "highlight_start": 9, | ||
58 | "highlight_end": 12 | ||
59 | } | ||
60 | ], | ||
61 | "label": null, | ||
62 | "suggested_replacement": "_foo", | ||
63 | "suggestion_applicability": "MachineApplicable", | ||
64 | "expansion": null | ||
65 | } | ||
66 | ], | ||
67 | "children": [], | ||
68 | "rendered": null | ||
69 | } | ||
70 | ], | ||
71 | "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" | ||
72 | } | ||
diff --git a/editors/code/src/test/index.ts b/editors/code/src/test/index.ts new file mode 100644 index 000000000..6e565c254 --- /dev/null +++ b/editors/code/src/test/index.ts | |||
@@ -0,0 +1,22 @@ | |||
1 | // | ||
2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING | ||
3 | // | ||
4 | // This file is providing the test runner to use when running extension tests. | ||
5 | // By default the test runner in use is Mocha based. | ||
6 | // | ||
7 | // You can provide your own test runner if you want to override it by exporting | ||
8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension | ||
9 | // host can call to run the tests. The test runner is expected to use console.log | ||
10 | // to report the results back to the caller. When the tests are finished, return | ||
11 | // a possible error to the callback or null if none. | ||
12 | |||
13 | import * as testRunner from 'vscode/lib/testrunner'; | ||
14 | |||
15 | // You can directly control Mocha options by uncommenting the following lines | ||
16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info | ||
17 | testRunner.configure({ | ||
18 | ui: 'bdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) | ||
19 | useColors: true // colored output from test results | ||
20 | }); | ||
21 | |||
22 | module.exports = testRunner; | ||
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..f27c58fe2 --- /dev/null +++ b/editors/code/src/test/rust_diagnostics.test.ts | |||
@@ -0,0 +1,162 @@ | |||
1 | import * as assert from 'assert'; | ||
2 | import * as fs from 'fs'; | ||
3 | import * as vscode from 'vscode'; | ||
4 | |||
5 | import { | ||
6 | MappedRustDiagnostic, | ||
7 | mapRustDiagnosticToVsCode, | ||
8 | RustDiagnostic | ||
9 | } from '../utils/rust_diagnostics'; | ||
10 | |||
11 | function 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 | |||
22 | function 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 | |||
32 | describe('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(diagnostic.source, 'rustc'); | ||
41 | assert.strictEqual( | ||
42 | diagnostic.message, | ||
43 | [ | ||
44 | `method \`next\` has an incompatible type for trait`, | ||
45 | `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``, | ||
46 | ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\`` | ||
47 | ].join('\n') | ||
48 | ); | ||
49 | assert.strictEqual(diagnostic.code, 'E0053'); | ||
50 | assert.strictEqual(diagnostic.tags, undefined); | ||
51 | |||
52 | // No related information | ||
53 | assert.deepStrictEqual(diagnostic.relatedInformation, []); | ||
54 | |||
55 | // There are no code actions available | ||
56 | assert.strictEqual(codeActions.length, 0); | ||
57 | }); | ||
58 | |||
59 | it('should map an unused variable warning', () => { | ||
60 | const { diagnostic, codeActions } = mapFixtureToVsCode( | ||
61 | 'warning/unused_variables' | ||
62 | ); | ||
63 | |||
64 | assert.strictEqual( | ||
65 | diagnostic.severity, | ||
66 | vscode.DiagnosticSeverity.Warning | ||
67 | ); | ||
68 | assert.strictEqual( | ||
69 | diagnostic.message, | ||
70 | [ | ||
71 | 'unused variable: `foo`', | ||
72 | '#[warn(unused_variables)] on by default' | ||
73 | ].join('\n') | ||
74 | ); | ||
75 | assert.strictEqual(diagnostic.code, 'unused_variables'); | ||
76 | assert.strictEqual(diagnostic.source, 'rustc'); | ||
77 | assert.deepStrictEqual(diagnostic.tags, [ | ||
78 | vscode.DiagnosticTag.Unnecessary | ||
79 | ]); | ||
80 | |||
81 | // No related information | ||
82 | assert.deepStrictEqual(diagnostic.relatedInformation, []); | ||
83 | |||
84 | // One code action available to prefix the variable | ||
85 | assert.strictEqual(codeActions.length, 1); | ||
86 | const [codeAction] = codeActions; | ||
87 | assert.strictEqual( | ||
88 | codeAction.title, | ||
89 | 'consider prefixing with an underscore: `_foo`' | ||
90 | ); | ||
91 | assert(codeAction.isPreferred); | ||
92 | }); | ||
93 | |||
94 | it('should map a wrong number of parameters error', () => { | ||
95 | const { diagnostic, codeActions } = mapFixtureToVsCode('error/E0061'); | ||
96 | |||
97 | assert.strictEqual( | ||
98 | diagnostic.severity, | ||
99 | vscode.DiagnosticSeverity.Error | ||
100 | ); | ||
101 | assert.strictEqual( | ||
102 | diagnostic.message, | ||
103 | 'this function takes 2 parameters but 3 parameters were supplied' | ||
104 | ); | ||
105 | assert.strictEqual(diagnostic.code, 'E0061'); | ||
106 | assert.strictEqual(diagnostic.source, 'rustc'); | ||
107 | assert.strictEqual(diagnostic.tags, undefined); | ||
108 | |||
109 | // One related information for the original definition | ||
110 | const relatedInformation = diagnostic.relatedInformation; | ||
111 | if (!relatedInformation) { | ||
112 | return assert.fail('Related information unexpectedly undefined'); | ||
113 | } | ||
114 | assert.strictEqual(relatedInformation.length, 1); | ||
115 | const [related] = relatedInformation; | ||
116 | assert.strictEqual(related.message, 'defined here'); | ||
117 | |||
118 | // There are no actions available | ||
119 | assert.strictEqual(codeActions.length, 0); | ||
120 | }); | ||
121 | |||
122 | it('should map a Clippy copy pass by ref warning', () => { | ||
123 | const { diagnostic, codeActions } = mapFixtureToVsCode( | ||
124 | 'clippy/trivially_copy_pass_by_ref' | ||
125 | ); | ||
126 | |||
127 | assert.strictEqual( | ||
128 | diagnostic.severity, | ||
129 | vscode.DiagnosticSeverity.Warning | ||
130 | ); | ||
131 | assert.strictEqual(diagnostic.source, 'clippy'); | ||
132 | assert.strictEqual( | ||
133 | diagnostic.message, | ||
134 | [ | ||
135 | 'this argument is passed by reference, but would be more efficient if passed by value', | ||
136 | '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]', | ||
137 | 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref' | ||
138 | ].join('\n') | ||
139 | ); | ||
140 | assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref'); | ||
141 | assert.strictEqual(diagnostic.tags, undefined); | ||
142 | |||
143 | // One related information for the lint definition | ||
144 | const relatedInformation = diagnostic.relatedInformation; | ||
145 | if (!relatedInformation) { | ||
146 | return assert.fail('Related information unexpectedly undefined'); | ||
147 | } | ||
148 | assert.strictEqual(relatedInformation.length, 1); | ||
149 | const [related] = relatedInformation; | ||
150 | assert.strictEqual(related.message, 'lint level defined here'); | ||
151 | |||
152 | // One code action available to pass by value | ||
153 | assert.strictEqual(codeActions.length, 1); | ||
154 | const [codeAction] = codeActions; | ||
155 | assert.strictEqual( | ||
156 | codeAction.title, | ||
157 | 'consider passing by value instead: `self`' | ||
158 | ); | ||
159 | // Clippy does not mark this as machine applicable | ||
160 | assert.strictEqual(codeAction.isPreferred, false); | ||
161 | }); | ||
162 | }); | ||
diff --git a/editors/code/src/test/vscode_diagnostics.test.ts b/editors/code/src/test/vscode_diagnostics.test.ts new file mode 100644 index 000000000..9c5d812fa --- /dev/null +++ b/editors/code/src/test/vscode_diagnostics.test.ts | |||
@@ -0,0 +1,182 @@ | |||
1 | import * as assert from 'assert'; | ||
2 | import * as vscode from 'vscode'; | ||
3 | |||
4 | import { | ||
5 | areCodeActionsEqual, | ||
6 | areDiagnosticsEqual | ||
7 | } from '../utils/vscode_diagnostics'; | ||
8 | |||
9 | const uri = vscode.Uri.file('/file/1'); | ||
10 | |||
11 | const range1 = new vscode.Range( | ||
12 | new vscode.Position(1, 2), | ||
13 | new vscode.Position(3, 4) | ||
14 | ); | ||
15 | |||
16 | const range2 = new vscode.Range( | ||
17 | new vscode.Position(5, 6), | ||
18 | new vscode.Position(7, 8) | ||
19 | ); | ||
20 | |||
21 | describe('areDiagnosticsEqual', () => { | ||
22 | it('should treat identical diagnostics as equal', () => { | ||
23 | const diagnostic1 = new vscode.Diagnostic( | ||
24 | range1, | ||
25 | 'Hello, world!', | ||
26 | vscode.DiagnosticSeverity.Error | ||
27 | ); | ||
28 | |||
29 | const diagnostic2 = new vscode.Diagnostic( | ||
30 | range1, | ||
31 | 'Hello, world!', | ||
32 | vscode.DiagnosticSeverity.Error | ||
33 | ); | ||
34 | |||
35 | assert(areDiagnosticsEqual(diagnostic1, diagnostic2)); | ||
36 | }); | ||
37 | |||
38 | it('should treat diagnostics with different sources as inequal', () => { | ||
39 | const diagnostic1 = new vscode.Diagnostic( | ||
40 | range1, | ||
41 | 'Hello, world!', | ||
42 | vscode.DiagnosticSeverity.Error | ||
43 | ); | ||
44 | diagnostic1.source = 'rustc'; | ||
45 | |||
46 | const diagnostic2 = new vscode.Diagnostic( | ||
47 | range1, | ||
48 | 'Hello, world!', | ||
49 | vscode.DiagnosticSeverity.Error | ||
50 | ); | ||
51 | diagnostic2.source = 'clippy'; | ||
52 | |||
53 | assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); | ||
54 | }); | ||
55 | |||
56 | it('should treat diagnostics with different ranges as inequal', () => { | ||
57 | const diagnostic1 = new vscode.Diagnostic( | ||
58 | range1, | ||
59 | 'Hello, world!', | ||
60 | vscode.DiagnosticSeverity.Error | ||
61 | ); | ||
62 | |||
63 | const diagnostic2 = new vscode.Diagnostic( | ||
64 | range2, | ||
65 | 'Hello, world!', | ||
66 | vscode.DiagnosticSeverity.Error | ||
67 | ); | ||
68 | |||
69 | assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); | ||
70 | }); | ||
71 | |||
72 | it('should treat diagnostics with different messages as inequal', () => { | ||
73 | const diagnostic1 = new vscode.Diagnostic( | ||
74 | range1, | ||
75 | 'Hello, world!', | ||
76 | vscode.DiagnosticSeverity.Error | ||
77 | ); | ||
78 | |||
79 | const diagnostic2 = new vscode.Diagnostic( | ||
80 | range1, | ||
81 | 'Goodbye!, world!', | ||
82 | vscode.DiagnosticSeverity.Error | ||
83 | ); | ||
84 | |||
85 | assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); | ||
86 | }); | ||
87 | |||
88 | it('should treat diagnostics with different severities as inequal', () => { | ||
89 | const diagnostic1 = new vscode.Diagnostic( | ||
90 | range1, | ||
91 | 'Hello, world!', | ||
92 | vscode.DiagnosticSeverity.Warning | ||
93 | ); | ||
94 | |||
95 | const diagnostic2 = new vscode.Diagnostic( | ||
96 | range1, | ||
97 | 'Hello, world!', | ||
98 | vscode.DiagnosticSeverity.Error | ||
99 | ); | ||
100 | |||
101 | assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); | ||
102 | }); | ||
103 | }); | ||
104 | |||
105 | describe('areCodeActionsEqual', () => { | ||
106 | it('should treat identical actions as equal', () => { | ||
107 | const codeAction1 = new vscode.CodeAction( | ||
108 | 'Fix me!', | ||
109 | vscode.CodeActionKind.QuickFix | ||
110 | ); | ||
111 | |||
112 | const codeAction2 = new vscode.CodeAction( | ||
113 | 'Fix me!', | ||
114 | vscode.CodeActionKind.QuickFix | ||
115 | ); | ||
116 | |||
117 | const edit = new vscode.WorkspaceEdit(); | ||
118 | edit.replace(uri, range1, 'Replace with this'); | ||
119 | codeAction1.edit = edit; | ||
120 | codeAction2.edit = edit; | ||
121 | |||
122 | assert(areCodeActionsEqual(codeAction1, codeAction2)); | ||
123 | }); | ||
124 | |||
125 | it('should treat actions with different types as inequal', () => { | ||
126 | const codeAction1 = new vscode.CodeAction( | ||
127 | 'Fix me!', | ||
128 | vscode.CodeActionKind.Refactor | ||
129 | ); | ||
130 | |||
131 | const codeAction2 = new vscode.CodeAction( | ||
132 | 'Fix me!', | ||
133 | vscode.CodeActionKind.QuickFix | ||
134 | ); | ||
135 | |||
136 | const edit = new vscode.WorkspaceEdit(); | ||
137 | edit.replace(uri, range1, 'Replace with this'); | ||
138 | codeAction1.edit = edit; | ||
139 | codeAction2.edit = edit; | ||
140 | |||
141 | assert(!areCodeActionsEqual(codeAction1, codeAction2)); | ||
142 | }); | ||
143 | |||
144 | it('should treat actions with different titles as inequal', () => { | ||
145 | const codeAction1 = new vscode.CodeAction( | ||
146 | 'Fix me!', | ||
147 | vscode.CodeActionKind.Refactor | ||
148 | ); | ||
149 | |||
150 | const codeAction2 = new vscode.CodeAction( | ||
151 | 'Do something different!', | ||
152 | vscode.CodeActionKind.Refactor | ||
153 | ); | ||
154 | |||
155 | const edit = new vscode.WorkspaceEdit(); | ||
156 | edit.replace(uri, range1, 'Replace with this'); | ||
157 | codeAction1.edit = edit; | ||
158 | codeAction2.edit = edit; | ||
159 | |||
160 | assert(!areCodeActionsEqual(codeAction1, codeAction2)); | ||
161 | }); | ||
162 | |||
163 | it('should treat actions with different edits as inequal', () => { | ||
164 | const codeAction1 = new vscode.CodeAction( | ||
165 | 'Fix me!', | ||
166 | vscode.CodeActionKind.Refactor | ||
167 | ); | ||
168 | const edit1 = new vscode.WorkspaceEdit(); | ||
169 | edit1.replace(uri, range1, 'Replace with this'); | ||
170 | codeAction1.edit = edit1; | ||
171 | |||
172 | const codeAction2 = new vscode.CodeAction( | ||
173 | 'Fix me!', | ||
174 | vscode.CodeActionKind.Refactor | ||
175 | ); | ||
176 | const edit2 = new vscode.WorkspaceEdit(); | ||
177 | edit2.replace(uri, range1, 'Replace with this other thing'); | ||
178 | codeAction2.edit = edit2; | ||
179 | |||
180 | assert(!areCodeActionsEqual(codeAction1, codeAction2)); | ||
181 | }); | ||
182 | }); | ||