diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs index 3a92b36e2f3..3f293f5d577 100644 --- a/crates/expect/src/lib.rs +++ b/crates/expect/src/lib.rs @@ -14,7 +14,7 @@ use stdx::{lines_with_ends, trim_indent}; const HELP: &str = " -You can update all `expect![[]]` tests by: +You can update all `expect![[]]` tests by running: env UPDATE_EXPECT=1 cargo test @@ -25,26 +25,37 @@ fn update_expect() -> bool { env::var("UPDATE_EXPECT").is_ok() } -/// expect![[""]] +/// expect![[r#"inline snapshot"#]] #[macro_export] macro_rules! expect { - [[$lit:literal]] => {$crate::Expect { + [[$data:literal]] => {$crate::Expect { position: $crate::Position { file: file!(), line: line!(), column: column!(), }, - data: $lit, + data: $data, }}; [[]] => { $crate::expect![[""]] }; } +/// expect_file!["/crates/foo/test_data/foo.rs"] +#[macro_export] +macro_rules! expect_file { + [$path:literal] => {$crate::ExpectFile { path: $path }}; +} + #[derive(Debug)] pub struct Expect { pub position: Position, pub data: &'static str, } +#[derive(Debug)] +pub struct ExpectFile { + pub path: &'static str, +} + #[derive(Debug)] pub struct Position { pub file: &'static str, @@ -64,7 +75,7 @@ pub fn assert_eq(&self, actual: &str) { if &trimmed == actual { return; } - Runtime::fail(self, &trimmed, actual); + Runtime::fail_expect(self, &trimmed, actual); } pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) { let actual = format!("{:#?}\n", actual); @@ -100,6 +111,25 @@ fn locate(&self, file: &str) -> Location { } } +impl ExpectFile { + pub fn assert_eq(&self, actual: &str) { + let expected = self.read(); + if actual == expected { + return; + } + Runtime::fail_file(self, &expected, actual); + } + fn read(&self) -> String { + fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n") + } + fn write(&self, contents: &str) { + fs::write(self.abs_path(), contents).unwrap() + } + fn abs_path(&self) -> PathBuf { + workspace_root().join(self.path) + } +} + #[derive(Default)] struct Runtime { help_printed: bool, @@ -108,7 +138,7 @@ struct Runtime { static RT: Lazy> = Lazy::new(Default::default); impl Runtime { - fn fail(expect: &Expect, expected: &str, actual: &str) { + fn fail_expect(expect: &Expect, expected: &str, actual: &str) { let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); if update_expect() { println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position); @@ -118,7 +148,21 @@ fn fail(expect: &Expect, expected: &str, actual: &str) { .update(expect, actual); return; } - let print_help = !mem::replace(&mut rt.help_printed, true); + rt.panic(expect.position.to_string(), expected, actual); + } + + fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) { + let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + if update_expect() { + println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path); + expect.write(actual); + return; + } + rt.panic(expect.path.to_string(), expected, actual); + } + + fn panic(&mut self, position: String, expected: &str, actual: &str) { + let print_help = !mem::replace(&mut self.help_printed, true); let help = if print_help { HELP } else { "" }; let diff = Changeset::new(actual, expected, "\n"); @@ -143,7 +187,7 @@ fn fail(expect: &Expect, expected: &str, actual: &str) { {} ---- ", - expect.position, help, expected, actual, diff + position, help, expected, actual, diff ); // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise. 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 b7fad97197f..f19628485db 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -1,6 +1,7 @@ use std::fs; -use test_utils::{assert_eq_text, project_dir, read_text}; +use expect::{expect_file, ExpectFile}; +use test_utils::project_dir; use crate::{mock_analysis::single_file, FileRange, TextRange}; @@ -91,7 +92,7 @@ fn and(self, other: Option) -> Option<(T, U)> { } "# .trim(), - "crates/ra_ide/src/snapshots/highlighting.html", + expect_file!["crates/ra_ide/src/snapshots/highlighting.html"], false, ); } @@ -114,7 +115,7 @@ fn bar() { } "# .trim(), - "crates/ra_ide/src/snapshots/rainbow_highlighting.html", + expect_file!["crates/ra_ide/src/snapshots/rainbow_highlighting.html"], true, ); } @@ -167,7 +168,7 @@ fn foo() { ); }"## .trim(), - "crates/ra_ide/src/snapshots/highlight_injection.html", + expect_file!["crates/ra_ide/src/snapshots/highlight_injection.html"], false, ); } @@ -250,7 +251,7 @@ fn main() { println!("{ничоси}", ничоси = 92); }"# .trim(), - "crates/ra_ide/src/snapshots/highlight_strings.html", + expect_file!["crates/ra_ide/src/snapshots/highlight_strings.html"], false, ); } @@ -278,7 +279,7 @@ fn main() { } "# .trim(), - "crates/ra_ide/src/snapshots/highlight_unsafe.html", + expect_file!["crates/ra_ide/src/snapshots/highlight_unsafe.html"], false, ); } @@ -354,7 +355,7 @@ macro_rules! noop { } "# .trim(), - "crates/ra_ide/src/snapshots/highlight_doctest.html", + expect_file!["crates/ra_ide/src/snapshots/highlight_doctest.html"], false, ); } @@ -362,11 +363,8 @@ macro_rules! noop { /// Highlights the code given by the `ra_fixture` argument, renders the /// result as HTML, and compares it with the HTML file given as `snapshot`. /// Note that the `snapshot` file is overwritten by the rendered HTML. -fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { +fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) { let (analysis, file_id) = single_file(ra_fixture); - let dst_file = project_dir().join(snapshot); let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); - let expected_html = &read_text(&dst_file); - fs::write(dst_file, &actual_html).unwrap(); - assert_eq_text!(expected_html, actual_html); + expect.assert_eq(actual_html) } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 25bcd80af8c..607a95682a7 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -415,7 +415,7 @@ pub(crate) fn handle_runnables( let source_file = snap.analysis.parse(file_id)?; algo::find_node_at_offset::(source_file.syntax(), offset) .and_then(|it| it.path()?.segment()?.name_ref()) - .map_or(false, |it| it.text() == "expect") + .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file") } None => false, };