]> git.lizzy.rs Git - rust.git/commitdiff
(T): make typification tests more data driven
authorAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 29 Jun 2020 12:21:57 +0000 (14:21 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 29 Jun 2020 15:23:01 +0000 (17:23 +0200)
crates/ra_hir_ty/src/test_db.rs
crates/ra_hir_ty/src/tests.rs
crates/ra_hir_ty/src/tests/never_type.rs
crates/ra_hir_ty/src/tests/simple.rs
crates/test_utils/src/lib.rs

index 9c2c6959ddc9d36b5328f56d9f678588a42d3b50..0481a7b12a46c7cff48b4c38cc68ca5d5b8942ef 100644 (file)
@@ -154,6 +154,19 @@ pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) {
         });
         (buf, count)
     }
+
+    pub fn all_files(&self) -> Vec<FileId> {
+        let mut res = Vec::new();
+        let crate_graph = self.crate_graph();
+        for krate in crate_graph.iter() {
+            let crate_def_map = self.crate_def_map(krate);
+            for (module_id, _) in crate_def_map.modules.iter() {
+                let file_id = crate_def_map[module_id].origin.file_id();
+                res.extend(file_id)
+            }
+        }
+        res
+    }
 }
 
 impl TestDB {
index 2a85ce85d6de433fcf632c94102944a862b0c0ce..4d0dc301151881e43dd47bcbb00d1dc2c910220e 100644 (file)
@@ -28,6 +28,7 @@
     SyntaxNode,
 };
 use stdx::format_to;
+use test_utils::extract_annotations;
 
 use crate::{
     db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
 // against snapshots of the expected results using insta. Use cargo-insta to
 // update the snapshots.
 
+fn check_types(ra_fixture: &str) {
+    let db = TestDB::with_files(ra_fixture);
+    let mut checked_one = false;
+    for file_id in db.all_files() {
+        let text = db.parse(file_id).syntax_node().to_string();
+        let annotations = extract_annotations(&text);
+        for (offset, expected) in annotations {
+            let actual = type_at_pos(&db, FilePosition { file_id, offset });
+            assert_eq!(expected, actual);
+            checked_one = true;
+        }
+    }
+    assert!(checked_one, "no `//^` annotations found");
+}
+
 fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
     type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
 }
index ab9a990f59b0b85cdece7ad3da9c53d772be114f..64d421d405719322f89b7dd1d03edb258f8219d4 100644 (file)
@@ -1,99 +1,91 @@
 use insta::assert_snapshot;
 
-use super::{infer_with_mismatches, type_at};
+use super::{check_types, infer_with_mismatches};
 
 #[test]
 fn infer_never1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test() {
     let t = return;
-    t<|>;
-}
+    t;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn infer_never2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { a } else { loop {} };
-    a<|>;
-}
+    a;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn infer_never3() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { loop {} } else { a };
-    a<|>;
+    a;
+  //^ !
 }
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn never_type_in_generic_args() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
-}
+    a;
+} //^ Option<!>
 "#,
     );
-    assert_eq!(t, "Option<!>");
 }
 
 #[test]
 fn never_type_can_be_reinferred1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { loop {} } else { a };
-    a<|>;
+    a;
+  //^ ()
     if false { a };
 }
 "#,
     );
-    assert_eq!(t, "()");
 }
 
 #[test]
 fn never_type_can_be_reinferred2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
+    a;
+  //^ Option<i32>
     match 42 {
         42 => a,
         _ => Option::Some(42),
@@ -101,19 +93,18 @@ fn test() {
 }
 "#,
     );
-    assert_eq!(t, "Option<i32>");
 }
 
 #[test]
 fn never_type_can_be_reinferred3() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
+    a;
+  //^ Option<&str>
     match 42 {
         42 => a,
         _ => Option::Some("str"),
@@ -121,82 +112,72 @@ fn test() {
 }
 "#,
     );
-    assert_eq!(t, "Option<&str>");
 }
 
 #[test]
 fn match_no_arm() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Void {}
 
 fn test(a: Void) {
     let t = match a {};
-    t<|>;
-}
+    t;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn match_unknown_arm() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: Option) {
     let t = match 0 {
         _ => unknown,
     };
-    t<|>;
-}
+    t;
+} //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn if_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test() {
     let i = if true {
         loop {}
     } else {
         3.0
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn if_else_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(input: bool) {
     let i = if input {
         2.0
     } else {
         return
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_first_arm_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         1 => return,
@@ -204,18 +185,16 @@ fn test(a: i32) {
         3 => loop {},
         _ => 3.0,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_second_arm_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         1 => 3.0,
@@ -223,45 +202,40 @@ fn test(a: i32) {
         3 => 3.0,
         _ => return,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_all_arms_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         2 => return,
         _ => loop {},
     };
-    i<|>;
-}
+    i;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn match_no_never_arms() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         2 => 2.0,
         _ => 3.0,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
index 5e3f2bd3c8e12b68249586ef6907057681a58482..de63f4ccea9c8dd41f7031dbf2f71d24dd9c894d 100644 (file)
@@ -1,19 +1,17 @@
-use super::{infer, type_at, type_at_pos};
-use crate::test_db::TestDB;
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
+
+use super::{check_types, infer};
 
 #[test]
 fn infer_box() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
-
 fn test() {
     let x = box 1;
     let t = (x, box x, box &1, box [1]);
-    t<|>;
-}
+    t;
+} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)
 
 //- /std.rs crate:std
 #[prelude_import] use prelude::*;
@@ -25,29 +23,24 @@ pub struct Box<T: ?Sized> {
         inner: *mut T,
     }
 }
-
 "#,
     );
-    assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_adt_self() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 enum Nat { Succ(Self), Demo(Nat), Zero }
 
 fn test() {
     let foo: Nat = Nat::Zero;
     if let Nat::Succ(x) = foo {
-        x<|>
-    }
+        x
+    } //^ Nat
 }
-
 "#,
     );
-    assert_eq!("Nat", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -93,7 +86,7 @@ fn foo() {
 
 #[test]
 fn infer_ranges() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
 fn test() {
@@ -105,8 +98,8 @@ fn test() {
     let f = 'a'..='z';
 
     let t = (a, b, c, d, e, f);
-    t<|>;
-}
+    t;
+} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
 
 //- /core.rs crate:core
 #[prelude_import] use prelude::*;
@@ -135,29 +128,22 @@ pub struct RangeToInclusive<Idx> {
 }
 "#,
     );
-    assert_eq!(
-        "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
-        type_at_pos(&db, pos),
-    );
 }
 
 #[test]
 fn infer_while_let() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { Some(T), None }
 
 fn test() {
     let foo: Option<f32> = None;
     while let Option::Some(x) = foo {
-        <|>x
-    }
+        x
+    } //^ f32
 }
-
 "#,
     );
-    assert_eq!("f32", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -1687,9 +1673,8 @@ fn test() {
 
 #[test]
 fn shadowing_primitive() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct i32;
 struct Foo;
 
@@ -1697,15 +1682,15 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
 
 fn main() {
     let x: i32 = i32;
-    x.foo()<|>;
+    x.foo();
+        //^ Foo
 }"#,
     );
-    assert_eq!(t, "Foo");
 }
 
 #[test]
 fn not_shadowing_primitive_by_module() {
-    let t = type_at(
+    check_types(
         r#"
 //- /str.rs
 fn foo() {}
@@ -1715,15 +1700,15 @@ fn foo() {}
 fn foo() -> &'static str { "" }
 
 fn main() {
-    foo()<|>;
+    foo();
+      //^ &str
 }"#,
     );
-    assert_eq!(t, "&str");
 }
 
 #[test]
 fn not_shadowing_module_by_primitive() {
-    let t = type_at(
+    check_types(
         r#"
 //- /str.rs
 fn foo() -> u32 {0}
@@ -1733,10 +1718,10 @@ fn foo() -> u32 {0}
 fn foo() -> &'static str { "" }
 
 fn main() {
-    str::foo()<|>;
+    str::foo();
+           //^ u32
 }"#,
     );
-    assert_eq!(t, "u32");
 }
 
 // This test is actually testing the shadowing behavior within ra_hir_def. It
@@ -1744,27 +1729,7 @@ fn main() {
 // capable of asserting the necessary conditions.
 #[test]
 fn should_be_shadowing_imports() {
-    let t = type_at(
-        r#"
-mod a {
-    pub fn foo() -> i8 {0}
-    pub struct foo { a: i8 }
-}
-mod b { pub fn foo () -> u8 {0} }
-mod c { pub struct foo { a: u8 } }
-mod d {
-    pub use super::a::*;
-    pub use super::c::foo;
-    pub use super::b::foo;
-}
-
-fn main() {
-    d::foo()<|>;
-}"#,
-    );
-    assert_eq!(t, "u8");
-
-    let t = type_at(
+    check_types(
         r#"
 mod a {
     pub fn foo() -> i8 {0}
@@ -1779,10 +1744,12 @@ mod d {
 }
 
 fn main() {
-    d::foo{a:0<|>};
+    d::foo();
+         //^ u8
+    d::foo{a:0};
+           //^ u8
 }"#,
     );
-    assert_eq!(t, "u8");
 }
 
 #[test]
index eaeeeb97b19054b8aaf2b4e436a17a9c687dfcc7..e74f3b263c71eea2ceac81e2770f9dfa5c00710e 100644 (file)
@@ -16,6 +16,7 @@
 };
 
 use serde_json::Value;
+use stdx::lines_with_ends;
 use text_size::{TextRange, TextSize};
 
 pub use difference::Changeset as __Changeset;
@@ -159,6 +160,39 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
     res
 }
 
+/// Extracts `//^ some text` annotations
+pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> {
+    let mut res = Vec::new();
+    let mut prev_line_start: Option<TextSize> = None;
+    let mut line_start: TextSize = 0.into();
+    for line in lines_with_ends(text) {
+        if let Some(idx) = line.find("//^") {
+            let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
+            let data = line[idx + "//^".len()..].trim().to_string();
+            res.push((offset, data))
+        }
+        prev_line_start = Some(line_start);
+        line_start += TextSize::of(line);
+    }
+    res
+}
+
+#[test]
+fn test_extract_annotations() {
+    let res = extract_annotations(&trim_indent(
+        r#"
+fn main() {
+    let x = 92;
+      //^ def
+
+    x + 1
+} //^ i32
+    "#,
+    ));
+
+    assert_eq!(res, vec![(20.into(), "def".into()), (47.into(), "i32".into())]);
+}
+
 // Comparison functionality borrowed from cargo:
 
 /// Compare a line with an expected pattern.