diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index a7a5b8fb5a..4e858c9e1d 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -9926,3 +9926,99 @@ fn bar() { "#]], ); } + +#[test] +fn test_runnables_with_snapshot_tests() { + check_actions( + r#" +//- /lib.rs crate:foo deps:expect_test,insta,snapbox +use expect_test::expect; +use insta::assert_debug_snapshot; +use snapbox::Assert; + +#[test] +fn test$0() { + let actual = "new25"; + expect!["new25"].assert_eq(&actual); + Assert::new() + .action_env("SNAPSHOTS") + .eq(actual, snapbox::str!["new25"]); + assert_debug_snapshot!(actual); +} + +//- /lib.rs crate:expect_test +struct Expect; + +impl Expect { + fn assert_eq(&self, actual: &str) {} +} + +#[macro_export] +macro_rules! expect { + ($e:expr) => Expect; // dummy +} + +//- /lib.rs crate:insta +#[macro_export] +macro_rules! assert_debug_snapshot { + ($e:expr) => {}; // dummy +} + +//- /lib.rs crate:snapbox +pub struct Assert; + +impl Assert { + pub fn new() -> Self { Assert } + + pub fn action_env(&self, env: &str) -> &Self { self } + + pub fn eq(&self, actual: &str, expected: &str) {} +} + +#[macro_export] +macro_rules! str { + ($e:expr) => ""; // dummy +} + "#, + expect![[r#" + [ + Reference( + FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 92, + }, + ), + Runnable( + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 81..301, + focus_range: 92..96, + name: "test", + kind: Function, + }, + kind: Test { + test_id: Path( + "test", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + update_test: UpdateTest { + expect_test: true, + insta: true, + snapbox: true, + }, + }, + ), + ] + "#]], + ); +} diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 487cd6daeb..0a987b8eba 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -657,62 +657,58 @@ impl<'a, 'b> TestDefs<'a, 'b> { } fn expect_test(&self) -> bool { - self.find_macro("expect_test:expect") || self.find_macro("expect_test::expect_file") + self.find_macro("expect_test", &["expect", "expect_file"]) } fn insta(&self) -> bool { - self.find_macro("insta:assert_snapshot") - || self.find_macro("insta:assert_debug_snapshot") - || self.find_macro("insta:assert_display_snapshot") - || self.find_macro("insta:assert_json_snapshot") - || self.find_macro("insta:assert_yaml_snapshot") - || self.find_macro("insta:assert_ron_snapshot") - || self.find_macro("insta:assert_toml_snapshot") - || self.find_macro("insta:assert_csv_snapshot") - || self.find_macro("insta:assert_compact_json_snapshot") - || self.find_macro("insta:assert_compact_debug_snapshot") - || self.find_macro("insta:assert_binary_snapshot") + self.find_macro( + "insta", + &[ + "assert_snapshot", + "assert_debug_snapshot", + "assert_display_snapshot", + "assert_json_snapshot", + "assert_yaml_snapshot", + "assert_ron_snapshot", + "assert_toml_snapshot", + "assert_csv_snapshot", + "assert_compact_json_snapshot", + "assert_compact_debug_snapshot", + "assert_binary_snapshot", + ], + ) } fn snapbox(&self) -> bool { - self.find_macro("snapbox:assert_data_eq") - || self.find_macro("snapbox:file") - || self.find_macro("snapbox:str") + self.find_macro("snapbox", &["assert_data_eq", "file", "str"]) } - fn find_macro(&self, path: &str) -> bool { - let Some(hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(it))) = self.find_def(path) else { - return false; - }; - - Definition::Macro(it) - .usages(self.0) - .in_scope(&SearchScope::file_range(self.2)) - .at_least_one() - } - - fn find_def(&self, path: &str) -> Option { + fn find_macro(&self, crate_name: &str, paths: &[&str]) -> bool { let db = self.0.db; - let mut path = path.split(':'); - let item = path.next_back()?; - let krate = path.next()?; - let dep = self.1.dependencies(db).into_iter().find(|dep| dep.name.eq_ident(krate))?; + let Some(dep) = + self.1.dependencies(db).into_iter().find(|dep| dep.name.eq_ident(crate_name)) + else { + return false; + }; + let module = dep.krate.root_module(); + let scope = module.scope(db, None); - let mut module = dep.krate.root_module(); - for segment in path { - module = module.children(db).find_map(|child| { - let name = child.name(db)?; - if name.eq_ident(segment) { - Some(child) - } else { - None + paths + .iter() + .filter_map(|path| { + let (_, def) = scope.iter().find(|(name, _)| name.eq_ident(path))?; + match def { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(it)) => Some(it), + _ => None, } - })?; - } - - let (_, def) = module.scope(db, None).into_iter().find(|(name, _)| name.eq_ident(item))?; - Some(def) + }) + .any(|makro| { + Definition::Macro(*makro) + .usages(self.0) + .in_scope(&SearchScope::file_range(self.2)) + .at_least_one() + }) } }