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