aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/expect/src/lib.rs60
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs22
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
3 files changed, 63 insertions, 21 deletions
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
index 3a92b36e2..3f293f5d5 100644
--- a/crates/expect/src/lib.rs
+++ b/crates/expect/src/lib.rs
@@ -14,7 +14,7 @@ use once_cell::sync::Lazy;
14use stdx::{lines_with_ends, trim_indent}; 14use stdx::{lines_with_ends, trim_indent};
15 15
16const HELP: &str = " 16const HELP: &str = "
17You can update all `expect![[]]` tests by: 17You can update all `expect![[]]` tests by running:
18 18
19 env UPDATE_EXPECT=1 cargo test 19 env UPDATE_EXPECT=1 cargo test
20 20
@@ -25,20 +25,26 @@ fn update_expect() -> bool {
25 env::var("UPDATE_EXPECT").is_ok() 25 env::var("UPDATE_EXPECT").is_ok()
26} 26}
27 27
28/// expect![[""]] 28/// expect![[r#"inline snapshot"#]]
29#[macro_export] 29#[macro_export]
30macro_rules! expect { 30macro_rules! expect {
31 [[$lit:literal]] => {$crate::Expect { 31 [[$data:literal]] => {$crate::Expect {
32 position: $crate::Position { 32 position: $crate::Position {
33 file: file!(), 33 file: file!(),
34 line: line!(), 34 line: line!(),
35 column: column!(), 35 column: column!(),
36 }, 36 },
37 data: $lit, 37 data: $data,
38 }}; 38 }};
39 [[]] => { $crate::expect![[""]] }; 39 [[]] => { $crate::expect![[""]] };
40} 40}
41 41
42/// expect_file!["/crates/foo/test_data/foo.rs"]
43#[macro_export]
44macro_rules! expect_file {
45 [$path:literal] => {$crate::ExpectFile { path: $path }};
46}
47
42#[derive(Debug)] 48#[derive(Debug)]
43pub struct Expect { 49pub struct Expect {
44 pub position: Position, 50 pub position: Position,
@@ -46,6 +52,11 @@ pub struct Expect {
46} 52}
47 53
48#[derive(Debug)] 54#[derive(Debug)]
55pub struct ExpectFile {
56 pub path: &'static str,
57}
58
59#[derive(Debug)]
49pub struct Position { 60pub struct Position {
50 pub file: &'static str, 61 pub file: &'static str,
51 pub line: u32, 62 pub line: u32,
@@ -64,7 +75,7 @@ impl Expect {
64 if &trimmed == actual { 75 if &trimmed == actual {
65 return; 76 return;
66 } 77 }
67 Runtime::fail(self, &trimmed, actual); 78 Runtime::fail_expect(self, &trimmed, actual);
68 } 79 }
69 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) { 80 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
70 let actual = format!("{:#?}\n", actual); 81 let actual = format!("{:#?}\n", actual);
@@ -100,6 +111,25 @@ impl Expect {
100 } 111 }
101} 112}
102 113
114impl ExpectFile {
115 pub fn assert_eq(&self, actual: &str) {
116 let expected = self.read();
117 if actual == expected {
118 return;
119 }
120 Runtime::fail_file(self, &expected, actual);
121 }
122 fn read(&self) -> String {
123 fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
124 }
125 fn write(&self, contents: &str) {
126 fs::write(self.abs_path(), contents).unwrap()
127 }
128 fn abs_path(&self) -> PathBuf {
129 workspace_root().join(self.path)
130 }
131}
132
103#[derive(Default)] 133#[derive(Default)]
104struct Runtime { 134struct Runtime {
105 help_printed: bool, 135 help_printed: bool,
@@ -108,7 +138,7 @@ struct Runtime {
108static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default); 138static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);
109 139
110impl Runtime { 140impl Runtime {
111 fn fail(expect: &Expect, expected: &str, actual: &str) { 141 fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
112 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); 142 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
113 if update_expect() { 143 if update_expect() {
114 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position); 144 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
@@ -118,7 +148,21 @@ impl Runtime {
118 .update(expect, actual); 148 .update(expect, actual);
119 return; 149 return;
120 } 150 }
121 let print_help = !mem::replace(&mut rt.help_printed, true); 151 rt.panic(expect.position.to_string(), expected, actual);
152 }
153
154 fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
155 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
156 if update_expect() {
157 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path);
158 expect.write(actual);
159 return;
160 }
161 rt.panic(expect.path.to_string(), expected, actual);
162 }
163
164 fn panic(&mut self, position: String, expected: &str, actual: &str) {
165 let print_help = !mem::replace(&mut self.help_printed, true);
122 let help = if print_help { HELP } else { "" }; 166 let help = if print_help { HELP } else { "" };
123 167
124 let diff = Changeset::new(actual, expected, "\n"); 168 let diff = Changeset::new(actual, expected, "\n");
@@ -143,7 +187,7 @@ impl Runtime {
143{} 187{}
144---- 188----
145", 189",
146 expect.position, help, expected, actual, diff 190 position, help, expected, actual, diff
147 ); 191 );
148 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise. 192 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
149 panic::resume_unwind(Box::new(())); 193 panic::resume_unwind(Box::new(()));
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index b7fad9719..f19628485 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,7 @@
1use std::fs; 1use std::fs;
2 2
3use test_utils::{assert_eq_text, project_dir, read_text}; 3use expect::{expect_file, ExpectFile};
4use test_utils::project_dir;
4 5
5use crate::{mock_analysis::single_file, FileRange, TextRange}; 6use crate::{mock_analysis::single_file, FileRange, TextRange};
6 7
@@ -91,7 +92,7 @@ impl<T> Option<T> {
91} 92}
92"# 93"#
93 .trim(), 94 .trim(),
94 "crates/ra_ide/src/snapshots/highlighting.html", 95 expect_file!["crates/ra_ide/src/snapshots/highlighting.html"],
95 false, 96 false,
96 ); 97 );
97} 98}
@@ -114,7 +115,7 @@ fn bar() {
114} 115}
115"# 116"#
116 .trim(), 117 .trim(),
117 "crates/ra_ide/src/snapshots/rainbow_highlighting.html", 118 expect_file!["crates/ra_ide/src/snapshots/rainbow_highlighting.html"],
118 true, 119 true,
119 ); 120 );
120} 121}
@@ -167,7 +168,7 @@ fn main() {
167 ); 168 );
168}"## 169}"##
169 .trim(), 170 .trim(),
170 "crates/ra_ide/src/snapshots/highlight_injection.html", 171 expect_file!["crates/ra_ide/src/snapshots/highlight_injection.html"],
171 false, 172 false,
172 ); 173 );
173} 174}
@@ -250,7 +251,7 @@ fn main() {
250 println!("{ничоси}", ничоси = 92); 251 println!("{ничоси}", ничоси = 92);
251}"# 252}"#
252 .trim(), 253 .trim(),
253 "crates/ra_ide/src/snapshots/highlight_strings.html", 254 expect_file!["crates/ra_ide/src/snapshots/highlight_strings.html"],
254 false, 255 false,
255 ); 256 );
256} 257}
@@ -278,7 +279,7 @@ fn main() {
278} 279}
279"# 280"#
280 .trim(), 281 .trim(),
281 "crates/ra_ide/src/snapshots/highlight_unsafe.html", 282 expect_file!["crates/ra_ide/src/snapshots/highlight_unsafe.html"],
282 false, 283 false,
283 ); 284 );
284} 285}
@@ -354,7 +355,7 @@ macro_rules! noop {
354} 355}
355"# 356"#
356 .trim(), 357 .trim(),
357 "crates/ra_ide/src/snapshots/highlight_doctest.html", 358 expect_file!["crates/ra_ide/src/snapshots/highlight_doctest.html"],
358 false, 359 false,
359 ); 360 );
360} 361}
@@ -362,11 +363,8 @@ macro_rules! noop {
362/// Highlights the code given by the `ra_fixture` argument, renders the 363/// 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/// 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/// Note that the `snapshot` file is overwritten by the rendered HTML.
365fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { 366fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
366 let (analysis, file_id) = single_file(ra_fixture); 367 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(); 368 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
369 let expected_html = &read_text(&dst_file); 369 expect.assert_eq(actual_html)
370 fs::write(dst_file, &actual_html).unwrap();
371 assert_eq_text!(expected_html, actual_html);
372} 370}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 25bcd80af..607a95682 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -415,7 +415,7 @@ pub(crate) fn handle_runnables(
415 let source_file = snap.analysis.parse(file_id)?; 415 let source_file = snap.analysis.parse(file_id)?;
416 algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset) 416 algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
417 .and_then(|it| it.path()?.segment()?.name_ref()) 417 .and_then(|it| it.path()?.segment()?.name_ref())
418 .map_or(false, |it| it.text() == "expect") 418 .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
419 } 419 }
420 None => false, 420 None => false,
421 }; 421 };