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