diff options
author | Igor Aleksanov <[email protected]> | 2020-08-14 05:34:07 +0100 |
---|---|---|
committer | Igor Aleksanov <[email protected]> | 2020-08-14 05:34:07 +0100 |
commit | c26c911ec1e6c2ad1dcb7d155a6a1d528839ad1a (patch) | |
tree | 7cff36c38234be0afb65273146d8247083a5cfeb /crates/ide/src/syntax_highlighting/tests.rs | |
parent | 3c018bf84de5c693b5ee1c6bec0fed3b201c2060 (diff) | |
parent | f1f73649a686dc6e6449afc35e0fa6fed00e225d (diff) |
Merge branch 'master' into add-disable-diagnostics
Diffstat (limited to 'crates/ide/src/syntax_highlighting/tests.rs')
-rw-r--r-- | crates/ide/src/syntax_highlighting/tests.rs | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs new file mode 100644 index 000000000..94f37d773 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -0,0 +1,445 @@ | |||
1 | use std::fs; | ||
2 | |||
3 | use expect::{expect_file, ExpectFile}; | ||
4 | use test_utils::project_dir; | ||
5 | |||
6 | use crate::{mock_analysis::single_file, FileRange, TextRange}; | ||
7 | |||
8 | #[test] | ||
9 | fn test_highlighting() { | ||
10 | check_highlighting( | ||
11 | r#" | ||
12 | use inner::{self as inner_mod}; | ||
13 | mod inner {} | ||
14 | |||
15 | #[derive(Clone, Debug)] | ||
16 | struct Foo { | ||
17 | pub x: i32, | ||
18 | pub y: i32, | ||
19 | } | ||
20 | |||
21 | trait Bar { | ||
22 | fn bar(&self) -> i32; | ||
23 | } | ||
24 | |||
25 | impl Bar for Foo { | ||
26 | fn bar(&self) -> i32 { | ||
27 | self.x | ||
28 | } | ||
29 | } | ||
30 | |||
31 | impl Foo { | ||
32 | fn baz(mut self) -> i32 { | ||
33 | self.x | ||
34 | } | ||
35 | |||
36 | fn qux(&mut self) { | ||
37 | self.x = 0; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | static mut STATIC_MUT: i32 = 0; | ||
42 | |||
43 | fn foo<'a, T>() -> T { | ||
44 | foo::<'a, i32>() | ||
45 | } | ||
46 | |||
47 | macro_rules! def_fn { | ||
48 | ($($tt:tt)*) => {$($tt)*} | ||
49 | } | ||
50 | |||
51 | def_fn! { | ||
52 | fn bar() -> u32 { | ||
53 | 100 | ||
54 | } | ||
55 | } | ||
56 | |||
57 | macro_rules! noop { | ||
58 | ($expr:expr) => { | ||
59 | $expr | ||
60 | } | ||
61 | } | ||
62 | |||
63 | // comment | ||
64 | fn main() { | ||
65 | println!("Hello, {}!", 92); | ||
66 | |||
67 | let mut vec = Vec::new(); | ||
68 | if true { | ||
69 | let x = 92; | ||
70 | vec.push(Foo { x, y: 1 }); | ||
71 | } | ||
72 | unsafe { | ||
73 | vec.set_len(0); | ||
74 | STATIC_MUT = 1; | ||
75 | } | ||
76 | |||
77 | for e in vec { | ||
78 | // Do nothing | ||
79 | } | ||
80 | |||
81 | noop!(noop!(1)); | ||
82 | |||
83 | let mut x = 42; | ||
84 | let y = &mut x; | ||
85 | let z = &y; | ||
86 | |||
87 | let Foo { x: z, y } = Foo { x: z, y }; | ||
88 | |||
89 | y; | ||
90 | } | ||
91 | |||
92 | enum Option<T> { | ||
93 | Some(T), | ||
94 | None, | ||
95 | } | ||
96 | use Option::*; | ||
97 | |||
98 | impl<T> Option<T> { | ||
99 | fn and<U>(self, other: Option<U>) -> Option<(T, U)> { | ||
100 | match other { | ||
101 | None => unimplemented!(), | ||
102 | Nope => Nope, | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | "# | ||
107 | .trim(), | ||
108 | expect_file!["crates/ide/test_data/highlighting.html"], | ||
109 | false, | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn test_rainbow_highlighting() { | ||
115 | check_highlighting( | ||
116 | r#" | ||
117 | fn main() { | ||
118 | let hello = "hello"; | ||
119 | let x = hello.to_string(); | ||
120 | let y = hello.to_string(); | ||
121 | |||
122 | let x = "other color please!"; | ||
123 | let y = x.to_string(); | ||
124 | } | ||
125 | |||
126 | fn bar() { | ||
127 | let mut hello = "hello"; | ||
128 | } | ||
129 | "# | ||
130 | .trim(), | ||
131 | expect_file!["crates/ide/test_data/rainbow_highlighting.html"], | ||
132 | true, | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn accidentally_quadratic() { | ||
138 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); | ||
139 | let src = fs::read_to_string(file).unwrap(); | ||
140 | |||
141 | let (analysis, file_id) = single_file(&src); | ||
142 | |||
143 | // let t = std::time::Instant::now(); | ||
144 | let _ = analysis.highlight(file_id).unwrap(); | ||
145 | // eprintln!("elapsed: {:?}", t.elapsed()); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn test_ranges() { | ||
150 | let (analysis, file_id) = single_file( | ||
151 | r#" | ||
152 | #[derive(Clone, Debug)] | ||
153 | struct Foo { | ||
154 | pub x: i32, | ||
155 | pub y: i32, | ||
156 | } | ||
157 | "#, | ||
158 | ); | ||
159 | |||
160 | // The "x" | ||
161 | let highlights = &analysis | ||
162 | .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }) | ||
163 | .unwrap(); | ||
164 | |||
165 | assert_eq!(&highlights[0].highlight.to_string(), "field.declaration"); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn test_flattening() { | ||
170 | check_highlighting( | ||
171 | r##" | ||
172 | fn fixture(ra_fixture: &str) {} | ||
173 | |||
174 | fn main() { | ||
175 | fixture(r#" | ||
176 | trait Foo { | ||
177 | fn foo() { | ||
178 | println!("2 + 2 = {}", 4); | ||
179 | } | ||
180 | }"# | ||
181 | ); | ||
182 | }"## | ||
183 | .trim(), | ||
184 | expect_file!["crates/ide/test_data/highlight_injection.html"], | ||
185 | false, | ||
186 | ); | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn ranges_sorted() { | ||
191 | let (analysis, file_id) = single_file( | ||
192 | r#" | ||
193 | #[foo(bar = "bar")] | ||
194 | macro_rules! test {} | ||
195 | }"# | ||
196 | .trim(), | ||
197 | ); | ||
198 | let _ = analysis.highlight(file_id).unwrap(); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn test_string_highlighting() { | ||
203 | // The format string detection is based on macro-expansion, | ||
204 | // thus, we have to copy the macro definition from `std` | ||
205 | check_highlighting( | ||
206 | r#" | ||
207 | macro_rules! println { | ||
208 | ($($arg:tt)*) => ({ | ||
209 | $crate::io::_print($crate::format_args_nl!($($arg)*)); | ||
210 | }) | ||
211 | } | ||
212 | #[rustc_builtin_macro] | ||
213 | macro_rules! format_args_nl { | ||
214 | ($fmt:expr) => {{ /* compiler built-in */ }}; | ||
215 | ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; | ||
216 | } | ||
217 | |||
218 | fn main() { | ||
219 | // from https://doc.rust-lang.org/std/fmt/index.html | ||
220 | println!("Hello"); // => "Hello" | ||
221 | println!("Hello, {}!", "world"); // => "Hello, world!" | ||
222 | println!("The number is {}", 1); // => "The number is 1" | ||
223 | println!("{:?}", (3, 4)); // => "(3, 4)" | ||
224 | println!("{value}", value=4); // => "4" | ||
225 | println!("{} {}", 1, 2); // => "1 2" | ||
226 | println!("{:04}", 42); // => "0042" with leading zerosV | ||
227 | println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2" | ||
228 | println!("{argument}", argument = "test"); // => "test" | ||
229 | println!("{name} {}", 1, name = 2); // => "2 1" | ||
230 | println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" | ||
231 | println!("{{{}}}", 2); // => "{2}" | ||
232 | println!("Hello {:5}!", "x"); | ||
233 | println!("Hello {:1$}!", "x", 5); | ||
234 | println!("Hello {1:0$}!", 5, "x"); | ||
235 | println!("Hello {:width$}!", "x", width = 5); | ||
236 | println!("Hello {:<5}!", "x"); | ||
237 | println!("Hello {:-<5}!", "x"); | ||
238 | println!("Hello {:^5}!", "x"); | ||
239 | println!("Hello {:>5}!", "x"); | ||
240 | println!("Hello {:+}!", 5); | ||
241 | println!("{:#x}!", 27); | ||
242 | println!("Hello {:05}!", 5); | ||
243 | println!("Hello {:05}!", -5); | ||
244 | println!("{:#010x}!", 27); | ||
245 | println!("Hello {0} is {1:.5}", "x", 0.01); | ||
246 | println!("Hello {1} is {2:.0$}", 5, "x", 0.01); | ||
247 | println!("Hello {0} is {2:.1$}", "x", 5, 0.01); | ||
248 | println!("Hello {} is {:.*}", "x", 5, 0.01); | ||
249 | println!("Hello {} is {2:.*}", "x", 5, 0.01); | ||
250 | println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); | ||
251 | println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); | ||
252 | println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); | ||
253 | println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); | ||
254 | println!("Hello {{}}"); | ||
255 | println!("{{ Hello"); | ||
256 | |||
257 | println!(r"Hello, {}!", "world"); | ||
258 | |||
259 | // escape sequences | ||
260 | println!("Hello\nWorld"); | ||
261 | println!("\u{48}\x65\x6C\x6C\x6F World"); | ||
262 | |||
263 | println!("{\x41}", A = 92); | ||
264 | println!("{ничоси}", ничоси = 92); | ||
265 | }"# | ||
266 | .trim(), | ||
267 | expect_file!["crates/ide/test_data/highlight_strings.html"], | ||
268 | false, | ||
269 | ); | ||
270 | } | ||
271 | |||
272 | #[test] | ||
273 | fn test_unsafe_highlighting() { | ||
274 | check_highlighting( | ||
275 | r#" | ||
276 | unsafe fn unsafe_fn() {} | ||
277 | |||
278 | union Union { | ||
279 | a: u32, | ||
280 | b: f32, | ||
281 | } | ||
282 | |||
283 | struct HasUnsafeFn; | ||
284 | |||
285 | impl HasUnsafeFn { | ||
286 | unsafe fn unsafe_method(&self) {} | ||
287 | } | ||
288 | |||
289 | struct TypeForStaticMut { | ||
290 | a: u8 | ||
291 | } | ||
292 | |||
293 | static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; | ||
294 | |||
295 | #[repr(packed)] | ||
296 | struct Packed { | ||
297 | a: u16, | ||
298 | } | ||
299 | |||
300 | trait DoTheAutoref { | ||
301 | fn calls_autoref(&self); | ||
302 | } | ||
303 | |||
304 | impl DoTheAutoref for u16 { | ||
305 | fn calls_autoref(&self) {} | ||
306 | } | ||
307 | |||
308 | fn main() { | ||
309 | let x = &5 as *const _ as *const usize; | ||
310 | let u = Union { b: 0 }; | ||
311 | unsafe { | ||
312 | // unsafe fn and method calls | ||
313 | unsafe_fn(); | ||
314 | let b = u.b; | ||
315 | match u { | ||
316 | Union { b: 0 } => (), | ||
317 | Union { a } => (), | ||
318 | } | ||
319 | HasUnsafeFn.unsafe_method(); | ||
320 | |||
321 | // unsafe deref | ||
322 | let y = *x; | ||
323 | |||
324 | // unsafe access to a static mut | ||
325 | let a = global_mut.a; | ||
326 | |||
327 | // unsafe ref of packed fields | ||
328 | let packed = Packed { a: 0 }; | ||
329 | let a = &packed.a; | ||
330 | let ref a = packed.a; | ||
331 | let Packed { ref a } = packed; | ||
332 | let Packed { a: ref _a } = packed; | ||
333 | |||
334 | // unsafe auto ref of packed field | ||
335 | packed.a.calls_autoref(); | ||
336 | } | ||
337 | } | ||
338 | "# | ||
339 | .trim(), | ||
340 | expect_file!["crates/ide/test_data/highlight_unsafe.html"], | ||
341 | false, | ||
342 | ); | ||
343 | } | ||
344 | |||
345 | #[test] | ||
346 | fn test_highlight_doctest() { | ||
347 | check_highlighting( | ||
348 | r#" | ||
349 | /// ``` | ||
350 | /// let _ = "early doctests should not go boom"; | ||
351 | /// ``` | ||
352 | struct Foo { | ||
353 | bar: bool, | ||
354 | } | ||
355 | |||
356 | impl Foo { | ||
357 | pub const bar: bool = true; | ||
358 | |||
359 | /// Constructs a new `Foo`. | ||
360 | /// | ||
361 | /// # Examples | ||
362 | /// | ||
363 | /// ``` | ||
364 | /// # #![allow(unused_mut)] | ||
365 | /// let mut foo: Foo = Foo::new(); | ||
366 | /// ``` | ||
367 | pub const fn new() -> Foo { | ||
368 | Foo { bar: true } | ||
369 | } | ||
370 | |||
371 | /// `bar` method on `Foo`. | ||
372 | /// | ||
373 | /// # Examples | ||
374 | /// | ||
375 | /// ``` | ||
376 | /// use x::y; | ||
377 | /// | ||
378 | /// let foo = Foo::new(); | ||
379 | /// | ||
380 | /// // calls bar on foo | ||
381 | /// assert!(foo.bar()); | ||
382 | /// | ||
383 | /// let bar = foo.bar || Foo::bar; | ||
384 | /// | ||
385 | /// /* multi-line | ||
386 | /// comment */ | ||
387 | /// | ||
388 | /// let multi_line_string = "Foo | ||
389 | /// bar | ||
390 | /// "; | ||
391 | /// | ||
392 | /// ``` | ||
393 | /// | ||
394 | /// ```rust,no_run | ||
395 | /// let foobar = Foo::new().bar(); | ||
396 | /// ``` | ||
397 | /// | ||
398 | /// ```sh | ||
399 | /// echo 1 | ||
400 | /// ``` | ||
401 | pub fn foo(&self) -> bool { | ||
402 | true | ||
403 | } | ||
404 | } | ||
405 | |||
406 | /// ``` | ||
407 | /// noop!(1); | ||
408 | /// ``` | ||
409 | macro_rules! noop { | ||
410 | ($expr:expr) => { | ||
411 | $expr | ||
412 | } | ||
413 | } | ||
414 | "# | ||
415 | .trim(), | ||
416 | expect_file!["crates/ide/test_data/highlight_doctest.html"], | ||
417 | false, | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | #[test] | ||
422 | fn test_extern_crate() { | ||
423 | check_highlighting( | ||
424 | r#" | ||
425 | //- /main.rs | ||
426 | extern crate std; | ||
427 | extern crate alloc as abc; | ||
428 | //- /std/lib.rs | ||
429 | pub struct S; | ||
430 | //- /alloc/lib.rs | ||
431 | pub struct A | ||
432 | "#, | ||
433 | expect_file!["crates/ide/test_data/highlight_extern_crate.html"], | ||
434 | false, | ||
435 | ); | ||
436 | } | ||
437 | |||
438 | /// Highlights the code given by the `ra_fixture` argument, renders the | ||
439 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | ||
440 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | ||
441 | fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) { | ||
442 | let (analysis, file_id) = single_file(ra_fixture); | ||
443 | let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); | ||
444 | expect.assert_eq(actual_html) | ||
445 | } | ||