aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-28 12:47:12 +0100
committerAleksey Kladov <[email protected]>2018-08-28 12:47:12 +0100
commit748a4cacd24d9ecdca995e66117a10a1562e7d5d (patch)
tree4640f14c4c4417743815f9792058df30feac70dd /crates
parent6c41a205a908eb94f139f968f803e728fc3418c6 (diff)
Reorganize tests
Diffstat (limited to 'crates')
-rw-r--r--crates/libeditor/src/code_actions.rs49
-rw-r--r--crates/libeditor/src/completion.rs52
-rw-r--r--crates/libeditor/src/extend_selection.rs55
-rw-r--r--crates/libeditor/src/lib.rs70
-rw-r--r--crates/libeditor/src/symbols.rs42
-rw-r--r--crates/libeditor/src/test_utils.rs20
-rw-r--r--crates/libeditor/src/typing.rs129
-rw-r--r--crates/libeditor/tests/test.rs369
8 files changed, 417 insertions, 369 deletions
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs
index cd5146d87..ca159c658 100644
--- a/crates/libeditor/src/code_actions.rs
+++ b/crates/libeditor/src/code_actions.rs
@@ -128,3 +128,52 @@ impl PushDisplay for String {
128 write!(self, "{}", item).unwrap() 128 write!(self, "{}", item).unwrap()
129 } 129 }
130} 130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use test_utils::check_action;
136
137 #[test]
138 fn test_swap_comma() {
139 check_action(
140 "fn foo(x: i32,<|> y: Result<(), ()>) {}",
141 "fn foo(y: Result<(), ()>,<|> x: i32) {}",
142 |file, off| flip_comma(file, off).map(|f| f()),
143 )
144 }
145
146 #[test]
147 fn test_add_derive() {
148 check_action(
149 "struct Foo { a: i32, <|>}",
150 "#[derive(<|>)]\nstruct Foo { a: i32, }",
151 |file, off| add_derive(file, off).map(|f| f()),
152 );
153 check_action(
154 "struct Foo { <|> a: i32, }",
155 "#[derive(<|>)]\nstruct Foo { a: i32, }",
156 |file, off| add_derive(file, off).map(|f| f()),
157 );
158 check_action(
159 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
160 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
161 |file, off| add_derive(file, off).map(|f| f()),
162 );
163 }
164
165 #[test]
166 fn test_add_impl() {
167 check_action(
168 "struct Foo {<|>}\n",
169 "struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
170 |file, off| add_impl(file, off).map(|f| f()),
171 );
172 check_action(
173 "struct Foo<T: Clone> {<|>}",
174 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
175 |file, off| add_impl(file, off).map(|f| f()),
176 );
177 }
178
179}
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs
index cea2d14d1..c6ce62661 100644
--- a/crates/libeditor/src/completion.rs
+++ b/crates/libeditor/src/completion.rs
@@ -37,3 +37,55 @@ fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> {
37 }) 37 })
38 .collect() 38 .collect()
39} 39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use test_utils::{assert_eq_dbg, extract_offset};
45
46 fn do_check(code: &str, expected_completions: &str) {
47 let (off, code) = extract_offset(&code);
48 let file = File::parse(&code);
49 let completions = scope_completion(&file, off).unwrap();
50 assert_eq_dbg(expected_completions, &completions);
51 }
52
53 #[test]
54 fn test_completion_let_scope() {
55 do_check(r"
56 fn quux(x: i32) {
57 let y = 92;
58 1 + <|>;
59 let z = ();
60 }
61 ", r#"[CompletionItem { name: "y" },
62 CompletionItem { name: "x" }]"#);
63 }
64
65 #[test]
66 fn test_completion_if_let_scope() {
67 do_check(r"
68 fn quux() {
69 if let Some(x) = foo() {
70 let y = 92;
71 };
72 if let Some(a) = bar() {
73 let b = 62;
74 1 + <|>
75 }
76 }
77 ", r#"[CompletionItem { name: "b" },
78 CompletionItem { name: "a" }]"#);
79 }
80
81 #[test]
82 fn test_completion_for_scope() {
83 do_check(r"
84 fn quux() {
85 for x in &[1, 2, 3] {
86 <|>
87 }
88 }
89 ", r#"[CompletionItem { name: "x" }]"#);
90 }
91}
diff --git a/crates/libeditor/src/extend_selection.rs b/crates/libeditor/src/extend_selection.rs
index 154f89671..30cff6558 100644
--- a/crates/libeditor/src/extend_selection.rs
+++ b/crates/libeditor/src/extend_selection.rs
@@ -64,3 +64,58 @@ fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef {
64 } 64 }
65 res 65 res
66} 66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use test_utils::extract_offset;
72
73 fn do_check(before: &str, afters: &[&str]) {
74 let (cursor, before) = extract_offset(before);
75 let file = File::parse(&before);
76 let mut range = TextRange::offset_len(cursor, 0.into());
77 for &after in afters {
78 range = extend_selection(&file, range)
79 .unwrap();
80 let actual = &before[range];
81 assert_eq!(after, actual);
82 }
83 }
84
85 #[test]
86 fn test_extend_selection_arith() {
87 do_check(
88 r#"fn foo() { <|>1 + 1 }"#,
89 &["1", "1 + 1", "{ 1 + 1 }"],
90 );
91 }
92
93 #[test]
94 fn test_extend_selection_start_of_the_lind() {
95 do_check(
96 r#"
97impl S {
98<|> fn foo() {
99
100 }
101}"#,
102 &["fn foo() {\n\n }"]
103 );
104 }
105
106 #[test]
107 fn test_extend_selection_comments() {
108 do_check(
109 r#"
110fn bar(){}
111
112// fn foo() {
113// 1 + <|>1
114// }
115
116// fn foo(){}
117 "#,
118 &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"]
119 );
120 }
121}
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
index 34056b3c0..b2e2c4782 100644
--- a/crates/libeditor/src/lib.rs
+++ b/crates/libeditor/src/lib.rs
@@ -1,6 +1,9 @@
1extern crate libsyntax2; 1extern crate libsyntax2;
2extern crate superslice; 2extern crate superslice;
3extern crate itertools; 3extern crate itertools;
4#[cfg(test)]
5#[macro_use]
6extern crate test_utils as _test_utils;
4 7
5mod extend_selection; 8mod extend_selection;
6mod symbols; 9mod symbols;
@@ -10,6 +13,8 @@ mod code_actions;
10mod typing; 13mod typing;
11mod completion; 14mod completion;
12mod scope; 15mod scope;
16#[cfg(test)]
17mod test_utils;
13 18
14use libsyntax2::{ 19use libsyntax2::{
15 File, TextUnit, TextRange, SyntaxNodeRef, 20 File, TextUnit, TextRange, SyntaxNodeRef,
@@ -154,3 +159,68 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
154 .filter_map(N::cast) 159 .filter_map(N::cast)
155 .next() 160 .next()
156} 161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use test_utils::{assert_eq_dbg, extract_offset, add_cursor};
167
168 #[test]
169 fn test_highlighting() {
170 let file = File::parse(r#"
171// comment
172fn main() {}
173 println!("Hello, {}!", 92);
174"#);
175 let hls = highlight(&file);
176 assert_eq_dbg(
177 r#"[HighlightedRange { range: [1; 11), tag: "comment" },
178 HighlightedRange { range: [12; 14), tag: "keyword" },
179 HighlightedRange { range: [15; 19), tag: "function" },
180 HighlightedRange { range: [29; 36), tag: "text" },
181 HighlightedRange { range: [38; 50), tag: "string" },
182 HighlightedRange { range: [52; 54), tag: "literal" }]"#,
183 &hls,
184 );
185 }
186
187 #[test]
188 fn test_runnables() {
189 let file = File::parse(r#"
190fn main() {}
191
192#[test]
193fn test_foo() {}
194
195#[test]
196#[ignore]
197fn test_foo() {}
198"#);
199 let runnables = runnables(&file);
200 assert_eq_dbg(
201 r#"[Runnable { range: [1; 13), kind: Bin },
202 Runnable { range: [15; 39), kind: Test { name: "test_foo" } },
203 Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#,
204 &runnables,
205 )
206 }
207
208 #[test]
209 fn test_matching_brace() {
210 fn do_check(before: &str, after: &str) {
211 let (pos, before) = extract_offset(before);
212 let file = File::parse(&before);
213 let new_pos = match matching_brace(&file, pos) {
214 None => pos,
215 Some(pos) => pos,
216 };
217 let actual = add_cursor(&before, new_pos);
218 assert_eq_text!(after, &actual);
219 }
220
221 do_check(
222 "struct Foo { a: i32, }<|>",
223 "struct Foo <|>{ a: i32, }",
224 );
225 }
226}
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs
index 98a35dcdf..28b86c004 100644
--- a/crates/libeditor/src/symbols.rs
+++ b/crates/libeditor/src/symbols.rs
@@ -123,3 +123,45 @@ fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
123 }) 123 })
124 .accept(node)? 124 .accept(node)?
125} 125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use test_utils::assert_eq_dbg;
131
132 #[test]
133 fn test_file_structure() {
134 let file = File::parse(r#"
135struct Foo {
136 x: i32
137}
138
139mod m {
140 fn bar() {}
141}
142
143enum E { X, Y(i32) }
144type T = ();
145static S: i32 = 92;
146const C: i32 = 92;
147
148impl E {}
149
150impl fmt::Debug for E {}
151"#);
152 let symbols = file_structure(&file);
153 assert_eq_dbg(
154 r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF },
155 StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF },
156 StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE },
157 StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF },
158 StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF },
159 StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF },
160 StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF },
161 StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF },
162 StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM },
163 StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#,
164 &symbols,
165 )
166 }
167}
diff --git a/crates/libeditor/src/test_utils.rs b/crates/libeditor/src/test_utils.rs
new file mode 100644
index 000000000..475f560fa
--- /dev/null
+++ b/crates/libeditor/src/test_utils.rs
@@ -0,0 +1,20 @@
1use libsyntax2::{File, TextUnit};
2pub use _test_utils::*;
3use ActionResult;
4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<ActionResult>> (
6 before: &str,
7 after: &str,
8 f: F,
9) {
10 let (before_cursor_pos, before) = extract_offset(before);
11 let file = File::parse(&before);
12 let result = f(&file, before_cursor_pos).expect("code action is not applicable");
13 let actual = result.edit.apply(&before);
14 let actual_cursor_pos = match result.cursor_position {
15 None => result.edit.apply_to_offset(before_cursor_pos).unwrap(),
16 Some(off) => off,
17 };
18 let actual = add_cursor(&actual, actual_cursor_pos);
19 assert_eq_text!(after, &actual);
20}
diff --git a/crates/libeditor/src/typing.rs b/crates/libeditor/src/typing.rs
index daa57983f..952caf7f6 100644
--- a/crates/libeditor/src/typing.rs
+++ b/crates/libeditor/src/typing.rs
@@ -163,3 +163,132 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
163 } 163 }
164 " " 164 " "
165} 165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use test_utils::{check_action, extract_range, extract_offset};
171
172 fn check_join_lines(before: &str, after: &str) {
173 check_action(before, after, |file, offset| {
174 let range = TextRange::offset_len(offset, 0.into());
175 let res = join_lines(file, range);
176 Some(res)
177 })
178 }
179
180 #[test]
181 fn test_join_lines_comma() {
182 check_join_lines(r"
183fn foo() {
184 <|>foo(1,
185 )
186}
187", r"
188fn foo() {
189 <|>foo(1)
190}
191");
192 }
193
194 #[test]
195 fn test_join_lines_lambda_block() {
196 check_join_lines(r"
197pub fn reparse(&self, edit: &AtomEdit) -> File {
198 <|>self.incremental_reparse(edit).unwrap_or_else(|| {
199 self.full_reparse(edit)
200 })
201}
202", r"
203pub fn reparse(&self, edit: &AtomEdit) -> File {
204 <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
205}
206");
207 }
208
209 #[test]
210 fn test_join_lines_block() {
211 check_join_lines(r"
212fn foo() {
213 foo(<|>{
214 92
215 })
216}", r"
217fn foo() {
218 foo(<|>92)
219}");
220 }
221
222 #[test]
223 fn test_join_lines_selection() {
224 fn do_check(before: &str, after: &str) {
225 let (sel, before) = extract_range(before);
226 let file = File::parse(&before);
227 let result = join_lines(&file, sel);
228 let actual = result.edit.apply(&before);
229 assert_eq_text!(after, &actual);
230 }
231
232 do_check(r"
233fn foo() {
234 <|>foo(1,
235 2,
236 3,
237 <|>)
238}
239 ", r"
240fn foo() {
241 foo(1, 2, 3)
242}
243 ");
244
245 do_check(r"
246struct Foo <|>{
247 f: u32,
248}<|>
249 ", r"
250struct Foo { f: u32 }
251 ");
252 }
253
254 #[test]
255 fn test_on_eq_typed() {
256 fn do_check(before: &str, after: &str) {
257 let (offset, before) = extract_offset(before);
258 let file = File::parse(&before);
259 let result = on_eq_typed(&file, offset).unwrap();
260 let actual = result.edit.apply(&before);
261 assert_eq_text!(after, &actual);
262 }
263
264 // do_check(r"
265 // fn foo() {
266 // let foo =<|>
267 // }
268 // ", r"
269 // fn foo() {
270 // let foo =;
271 // }
272 // ");
273 do_check(r"
274fn foo() {
275 let foo =<|> 1 + 1
276}
277", r"
278fn foo() {
279 let foo = 1 + 1;
280}
281");
282 // do_check(r"
283 // fn foo() {
284 // let foo =<|>
285 // let bar = 1;
286 // }
287 // ", r"
288 // fn foo() {
289 // let foo =;
290 // let bar = 1;
291 // }
292 // ");
293 }
294}
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs
deleted file mode 100644
index 440afe92d..000000000
--- a/crates/libeditor/tests/test.rs
+++ /dev/null
@@ -1,369 +0,0 @@
1extern crate libeditor;
2extern crate libsyntax2;
3#[macro_use]
4extern crate test_utils;
5
6use test_utils::{assert_eq_dbg, add_cursor, extract_offset, extract_range};
7use libsyntax2::{File, TextUnit, TextRange};
8use libeditor::{
9 ActionResult,
10 highlight, runnables, extend_selection, file_structure,
11 flip_comma, add_derive, add_impl, matching_brace,
12 join_lines, on_eq_typed, scope_completion,
13};
14
15#[test]
16fn test_extend_selection() {
17 fn do_check(before: &str, afters: &[&str]) {
18 let (cursor, before) = extract_offset(before);
19 let file = file(&before);
20 let mut range = TextRange::offset_len(cursor, 0.into());
21 for &after in afters {
22 range = extend_selection(&file, range)
23 .unwrap();
24 let actual = &before[range];
25 assert_eq!(after, actual);
26 }
27 }
28
29 do_check(
30 r#"fn foo() { <|>1 + 1 }"#,
31 &["1", "1 + 1", "{ 1 + 1 }"],
32 );
33
34 do_check(
35 r#"
36impl S {
37<|> fn foo() {
38
39 }
40}"#,
41 &["fn foo() {\n\n }"]
42 );
43 do_check(
44 r#"
45fn bar(){}
46
47// fn foo() {
48// 1 + <|>1
49// }
50
51// fn foo(){}
52"#,
53 &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"]
54 );
55}
56
57#[test]
58fn test_highlighting() {
59 let file = file(r#"
60// comment
61fn main() {}
62 println!("Hello, {}!", 92);
63"#);
64 let hls = highlight(&file);
65 assert_eq_dbg(
66 r#"[HighlightedRange { range: [1; 11), tag: "comment" },
67 HighlightedRange { range: [12; 14), tag: "keyword" },
68 HighlightedRange { range: [15; 19), tag: "function" },
69 HighlightedRange { range: [29; 36), tag: "text" },
70 HighlightedRange { range: [38; 50), tag: "string" },
71 HighlightedRange { range: [52; 54), tag: "literal" }]"#,
72 &hls,
73 );
74}
75
76#[test]
77fn test_runnables() {
78 let file = file(r#"
79fn main() {}
80
81#[test]
82fn test_foo() {}
83
84#[test]
85#[ignore]
86fn test_foo() {}
87"#);
88 let runnables = runnables(&file);
89 assert_eq_dbg(
90 r#"[Runnable { range: [1; 13), kind: Bin },
91 Runnable { range: [15; 39), kind: Test { name: "test_foo" } },
92 Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#,
93 &runnables,
94 )
95}
96
97#[test]
98fn test_file_structure() {
99 let file = file(r#"
100struct Foo {
101 x: i32
102}
103
104mod m {
105 fn bar() {}
106}
107
108enum E { X, Y(i32) }
109type T = ();
110static S: i32 = 92;
111const C: i32 = 92;
112
113impl E {}
114
115impl fmt::Debug for E {}
116"#);
117 let symbols = file_structure(&file);
118 assert_eq_dbg(
119 r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF },
120 StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF },
121 StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE },
122 StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF },
123 StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF },
124 StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF },
125 StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF },
126 StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF },
127 StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM },
128 StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#,
129 &symbols,
130 )
131}
132
133#[test]
134fn test_swap_comma() {
135 check_action(
136 "fn foo(x: i32,<|> y: Result<(), ()>) {}",
137 "fn foo(y: Result<(), ()>,<|> x: i32) {}",
138 |file, off| flip_comma(file, off).map(|f| f()),
139 )
140}
141
142#[test]
143fn test_add_derive() {
144 check_action(
145 "struct Foo { a: i32, <|>}",
146 "#[derive(<|>)]\nstruct Foo { a: i32, }",
147 |file, off| add_derive(file, off).map(|f| f()),
148 );
149 check_action(
150 "struct Foo { <|> a: i32, }",
151 "#[derive(<|>)]\nstruct Foo { a: i32, }",
152 |file, off| add_derive(file, off).map(|f| f()),
153 );
154 check_action(
155 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
156 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
157 |file, off| add_derive(file, off).map(|f| f()),
158 );
159}
160
161#[test]
162fn test_add_impl() {
163 check_action(
164 "struct Foo {<|>}\n",
165 "struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
166 |file, off| add_impl(file, off).map(|f| f()),
167 );
168 check_action(
169 "struct Foo<T: Clone> {<|>}",
170 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
171 |file, off| add_impl(file, off).map(|f| f()),
172 );
173}
174
175#[test]
176fn test_matching_brace() {
177 fn do_check(before: &str, after: &str) {
178 let (pos, before) = extract_offset(before);
179 let file = file(&before);
180 let new_pos = match matching_brace(&file, pos) {
181 None => pos,
182 Some(pos) => pos,
183 };
184 let actual = add_cursor(&before, new_pos);
185 assert_eq_text!(after, &actual);
186 }
187
188 do_check(
189 "struct Foo { a: i32, }<|>",
190 "struct Foo <|>{ a: i32, }",
191 );
192}
193
194#[test]
195fn test_join_lines_cursor() {
196 fn do_check(before: &str, after: &str) {
197 check_action(before, after, |file, offset| {
198 let range = TextRange::offset_len(offset, 0.into());
199 let res = join_lines(file, range);
200 Some(res)
201 })
202 }
203
204 do_check(r"
205fn foo() {
206 <|>foo(1,
207 )
208}
209", r"
210fn foo() {
211 <|>foo(1)
212}
213");
214 do_check(r"
215pub fn reparse(&self, edit: &AtomEdit) -> File {
216 <|>self.incremental_reparse(edit).unwrap_or_else(|| {
217 self.full_reparse(edit)
218 })
219}
220", r"
221pub fn reparse(&self, edit: &AtomEdit) -> File {
222 <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
223}
224");
225 do_check(r"
226fn foo() {
227 foo(<|>{
228 92
229 })
230}", r"
231fn foo() {
232 foo(<|>92)
233}");
234}
235
236#[test]
237fn test_join_lines_selection() {
238 fn do_check(before: &str, after: &str) {
239 let (sel, before) = extract_range(before);
240 let file = file(&before);
241 let result = join_lines(&file, sel);
242 let actual = result.edit.apply(&before);
243 assert_eq_text!(after, &actual);
244 }
245
246 do_check(r"
247fn foo() {
248 <|>foo(1,
249 2,
250 3,
251 <|>)
252}
253", r"
254fn foo() {
255 foo(1, 2, 3)
256}
257");
258
259 do_check(r"
260struct Foo <|>{
261 f: u32,
262}<|>
263", r"
264struct Foo { f: u32 }
265");
266}
267
268#[test]
269fn test_on_eq_typed() {
270 fn do_check(before: &str, after: &str) {
271 let (offset, before) = extract_offset(before);
272 let file = file(&before);
273 let result = on_eq_typed(&file, offset).unwrap();
274 let actual = result.edit.apply(&before);
275 assert_eq_text!(after, &actual);
276 }
277
278// do_check(r"
279// fn foo() {
280// let foo =<|>
281// }
282// ", r"
283// fn foo() {
284// let foo =;
285// }
286// ");
287 do_check(r"
288fn foo() {
289 let foo =<|> 1 + 1
290}
291", r"
292fn foo() {
293 let foo = 1 + 1;
294}
295");
296// do_check(r"
297// fn foo() {
298// let foo =<|>
299// let bar = 1;
300// }
301// ", r"
302// fn foo() {
303// let foo =;
304// let bar = 1;
305// }
306// ");
307
308}
309
310#[test]
311fn test_completion() {
312 fn do_check(code: &str, expected_completions: &str) {
313 let (off, code) = extract_offset(&code);
314 let file = file(&code);
315 let completions = scope_completion(&file, off).unwrap();
316 assert_eq_dbg(expected_completions, &completions);
317 }
318
319 do_check(r"
320fn quux(x: i32) {
321 let y = 92;
322 1 + <|>;
323 let z = ();
324}
325", r#"[CompletionItem { name: "y" },
326 CompletionItem { name: "x" }]"#);
327
328 do_check(r"
329fn quux() {
330 if let Some(x) = foo() {
331 let y = 92;
332 };
333 if let Some(a) = bar() {
334 let b = 62;
335 1 + <|>
336 }
337}
338", r#"[CompletionItem { name: "b" },
339 CompletionItem { name: "a" }]"#);
340
341 do_check(r"
342fn quux() {
343 for x in &[1, 2, 3] {
344 <|>
345 }
346}
347", r#"[CompletionItem { name: "x" }]"#);
348}
349
350fn file(text: &str) -> File {
351 File::parse(text)
352}
353
354fn check_action<F: Fn(&File, TextUnit) -> Option<ActionResult>>(
355 before: &str,
356 after: &str,
357 f: F,
358) {
359 let (before_cursor_pos, before) = extract_offset(before);
360 let file = file(&before);
361 let result = f(&file, before_cursor_pos).expect("code action is not applicable");
362 let actual = result.edit.apply(&before);
363 let actual_cursor_pos = match result.cursor_position {
364 None => result.edit.apply_to_offset(before_cursor_pos).unwrap(),
365 Some(off) => off,
366 };
367 let actual = add_cursor(&actual, actual_cursor_pos);
368 assert_eq_text!(after, &actual);
369}