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