From 34072d53b683805f449bf106d16788f171ca3522 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Tue, 30 Jun 2020 13:20:16 +0200
Subject: Rewrite goto implementation tests

---
 crates/ra_ide/src/display/navigation_target.rs |  10 +-
 crates/ra_ide/src/goto_implementation.rs       | 193 ++++++++++++++-----------
 crates/ra_ide/src/mock_analysis.rs             |  20 +--
 3 files changed, 119 insertions(+), 104 deletions(-)

(limited to 'crates/ra_ide/src')

diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 02f55e5ba..f8a466304 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -279,13 +279,17 @@ impl ToNav for hir::Module {
 impl ToNav for hir::ImplDef {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
         let src = self.source(db);
-        let frange = if let Some(item) = self.is_builtin_derive(db) {
+        let derive_attr = self.is_builtin_derive(db);
+        let frange = if let Some(item) = &derive_attr {
             original_range(db, item.syntax())
         } else {
             original_range(db, src.as_ref().map(|it| it.syntax()))
         };
-        let focus_range =
-            src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range);
+        let focus_range = if derive_attr.is_some() {
+            None
+        } else {
+            src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range)
+        };
 
         NavigationTarget::from_syntax(
             frange.file_id,
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs
index 0cec0657e..1882789c4 100644
--- a/crates/ra_ide/src/goto_implementation.rs
+++ b/crates/ra_ide/src/goto_implementation.rs
@@ -74,135 +74,152 @@ fn impls_for_trait(
 
 #[cfg(test)]
 mod tests {
-    use crate::mock_analysis::analysis_and_position;
+    use ra_db::FileRange;
 
-    fn check_goto(fixture: &str, expected: &[&str]) {
-        let (analysis, pos) = analysis_and_position(fixture);
+    use crate::mock_analysis::{analysis_and_position, MockAnalysis};
 
-        let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
-        assert_eq!(navs.len(), expected.len());
-        navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start()));
-        navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
+    fn check(ra_fixture: &str) {
+        let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
+        let annotations = mock.annotations();
+        let analysis = mock.analysis();
+
+        let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
+
+        let key = |frange: &FileRange| (frange.file_id, frange.range.start());
+
+        let mut expected = annotations
+            .into_iter()
+            .map(|(range, data)| {
+                assert!(data.is_empty());
+                range
+            })
+            .collect::<Vec<_>>();
+        expected.sort_by_key(key);
+
+        let mut actual = navs
+            .into_iter()
+            .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() })
+            .collect::<Vec<_>>();
+        actual.sort_by_key(key);
+
+        assert_eq!(expected, actual);
     }
 
     #[test]
     fn goto_implementation_works() {
-        check_goto(
-            "
-            //- /lib.rs
-            struct Foo<|>;
-            impl Foo {}
-            ",
-            &["impl IMPL_DEF FileId(1) 12..23"],
+        check(
+            r#"
+struct Foo<|>;
+impl Foo {}
+   //^^^
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_works_multiple_blocks() {
-        check_goto(
-            "
-            //- /lib.rs
-            struct Foo<|>;
-            impl Foo {}
-            impl Foo {}
-            ",
-            &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"],
+        check(
+            r#"
+struct Foo<|>;
+impl Foo {}
+   //^^^
+impl Foo {}
+   //^^^
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_works_multiple_mods() {
-        check_goto(
-            "
-            //- /lib.rs
-            struct Foo<|>;
-            mod a {
-                impl super::Foo {}
-            }
-            mod b {
-                impl super::Foo {}
-            }
-            ",
-            &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"],
+        check(
+            r#"
+struct Foo<|>;
+mod a {
+    impl super::Foo {}
+       //^^^^^^^^^^
+}
+mod b {
+    impl super::Foo {}
+       //^^^^^^^^^^
+}
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_works_multiple_files() {
-        check_goto(
-            "
-            //- /lib.rs
-            struct Foo<|>;
-            mod a;
-            mod b;
-            //- /a.rs
-            impl crate::Foo {}
-            //- /b.rs
-            impl crate::Foo {}
-            ",
-            &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"],
+        check(
+            r#"
+//- /lib.rs
+struct Foo<|>;
+mod a;
+mod b;
+//- /a.rs
+impl crate::Foo {}
+   //^^^^^^^^^^
+//- /b.rs
+impl crate::Foo {}
+   //^^^^^^^^^^
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_for_trait() {
-        check_goto(
-            "
-            //- /lib.rs
-            trait T<|> {}
-            struct Foo;
-            impl T for Foo {}
-            ",
-            &["impl IMPL_DEF FileId(1) 23..40"],
+        check(
+            r#"
+trait T<|> {}
+struct Foo;
+impl T for Foo {}
+         //^^^
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_for_trait_multiple_files() {
-        check_goto(
-            "
-            //- /lib.rs
-            trait T<|> {};
-            struct Foo;
-            mod a;
-            mod b;
-            //- /a.rs
-            impl crate::T for crate::Foo {}
-            //- /b.rs
-            impl crate::T for crate::Foo {}
-            ",
-            &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"],
+        check(
+            r#"
+//- /lib.rs
+trait T<|> {};
+struct Foo;
+mod a;
+mod b;
+//- /a.rs
+impl crate::T for crate::Foo {}
+                //^^^^^^^^^^
+//- /b.rs
+impl crate::T for crate::Foo {}
+                //^^^^^^^^^^
+            "#,
         );
     }
 
     #[test]
     fn goto_implementation_all_impls() {
-        check_goto(
-            "
-            //- /lib.rs
-            trait T {}
-            struct Foo<|>;
-            impl Foo {}
-            impl T for Foo {}
-            impl T for &Foo {}
-            ",
-            &[
-                "impl IMPL_DEF FileId(1) 23..34",
-                "impl IMPL_DEF FileId(1) 35..52",
-                "impl IMPL_DEF FileId(1) 53..71",
-            ],
+        check(
+            r#"
+//- /lib.rs
+trait T {}
+struct Foo<|>;
+impl Foo {}
+   //^^^
+impl T for Foo {}
+         //^^^
+impl T for &Foo {}
+         //^^^^
+"#,
         );
     }
 
     #[test]
     fn goto_implementation_to_builtin_derive() {
-        check_goto(
-            "
-            //- /lib.rs
-            #[derive(Copy)]
-            struct Foo<|>;
-            ",
-            &["impl IMPL_DEF FileId(1) 0..15"],
+        check(
+            r#"
+  #[derive(Copy)]
+//^^^^^^^^^^^^^^^
+struct Foo<|>;
+"#,
         );
     }
 }
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs
index 120d29aa0..db6d50694 100644
--- a/crates/ra_ide/src/mock_analysis.rs
+++ b/crates/ra_ide/src/mock_analysis.rs
@@ -10,8 +10,6 @@ use test_utils::{
 use crate::{
     Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
 };
-use ra_syntax::TextRange;
-use rustc_hash::FxHashMap;
 
 /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
 /// from a set of in-memory files.
@@ -81,27 +79,23 @@ impl MockAnalysis {
             .expect("no file in this mock");
         FileId(idx as u32 + 1)
     }
-    pub fn annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
+    pub fn annotations(&self) -> Vec<(FileRange, String)> {
         self.files
             .iter()
             .enumerate()
-            .filter_map(|(idx, fixture)| {
+            .flat_map(|(idx, fixture)| {
                 let file_id = FileId(idx as u32 + 1);
                 let annotations = extract_annotations(&fixture.text);
-                if annotations.is_empty() {
-                    return None;
-                }
-                Some((file_id, annotations))
+                annotations
+                    .into_iter()
+                    .map(move |(range, data)| (FileRange { file_id, range }, data))
             })
             .collect()
     }
     pub fn annotation(&self) -> (FileRange, String) {
-        let all = self.annotations();
+        let mut all = self.annotations();
         assert_eq!(all.len(), 1);
-        let (file_id, mut for_file) = all.into_iter().next().unwrap();
-        assert_eq!(for_file.len(), 1);
-        let (range, data) = for_file.pop().unwrap();
-        (FileRange { file_id, range}, data)
+        all.pop().unwrap()
     }
     pub fn analysis_host(self) -> AnalysisHost {
         let mut host = AnalysisHost::default();
-- 
cgit v1.2.3