aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-06-30 09:34:08 +0100
committerGitHub <[email protected]>2020-06-30 09:34:08 +0100
commitd13ded6cbc8b835807f08606db90bedf18643154 (patch)
treed77c573d3ed0cadc5d318b2cfe57b8e8d4426fa7 /crates/ra_ide
parent2bd717139918e15e537dcd833bb003e85d24b3d1 (diff)
parenta4f934efa8e37d3bc822575109d103998ecd8fe1 (diff)
Merge #5101
5101: Add expect -- a light-weight alternative to insta r=matklad a=matklad This PR implements a small snapshot-testing library. Snapshot updating is done by setting an env var, or by using editor feature (which runs a test with env-var set). Here's workflow for updating a failing test: ![expect](https://user-images.githubusercontent.com/1711539/85926956-28afa080-b8a3-11ea-9260-c6d0d8914d0b.gif) Here's workflow for adding a new test: ![expect-fresh](https://user-images.githubusercontent.com/1711539/85926961-306f4500-b8a3-11ea-9369-f2373e327a3f.gif) Note that colorized diffs are not implemented in this PR, but should be easy to add (we already use them in test_utils). Main differences from insta (which is essential for rust-analyzer development, thanks @mitsuhiko!): * self-updating tests, no need for a separate tool * fewer features (only inline snapshots, no redactions) * fewer deps (no yaml, no persistence) * tighter integration with editor * first-class snapshot object, which can be used to write test functions (as opposed to testing macros) * trivial to tweak for rust-analyzer needs, by virtue of being a workspace member. I think eventually we should converge to a single snapshot testing library, but I am not sure that `expect` is exactly right, so I suggest rolling with both insta and expect for some time (if folks agree that expect might be better in the first place!). # Editor Integration Implementation The thing I am most excited about is the ability to update a specific snapshot from the editor. I want this to be available to other snapshot-testing libraries (cc @mitsuhiko, @aaronabramov), so I want to document how this works. The ideal UI here would be a code action (:bulb:). Unfortunately, it seems like it is impossible to implement without some kind of persistence (if you save test failures into some kind of a database, like insta does, than you can read the database from the editor plugin). Note that it is possible to highlight error by outputing error message in rustc's format. Unfortunately, one can't use the same trick to implement a quick fix. For this reason, expect makes use of another rust-analyzer feature -- ability to run a single test at the cursor position. This does need some expect-specific code in rust-analyzer unfortunately. Specifically, if rust-analyzer notices that the cursor is on `expect!` macro, it adds a special flag to runnable's JSON. However, given #5017 it is possible to approximate this well-enough without rust-analyzer integration. Specifically, an extension can register a special runner which checks (using regexes) if rust-anlyzer runnable covers text with specific macro invocation and do special magic in that case. closes #3835 Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/goto_definition.rs41
2 files changed, 34 insertions, 8 deletions
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index bbc6a5c9b..8e8892309 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -28,6 +28,7 @@ ra_cfg = { path = "../ra_cfg" }
28ra_fmt = { path = "../ra_fmt" } 28ra_fmt = { path = "../ra_fmt" }
29ra_prof = { path = "../ra_prof" } 29ra_prof = { path = "../ra_prof" }
30test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils" }
31expect = { path = "../expect" }
31ra_assists = { path = "../ra_assists" } 32ra_assists = { path = "../ra_assists" }
32ra_ssr = { path = "../ra_ssr" } 33ra_ssr = { path = "../ra_ssr" }
33 34
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index bea7fbfa7..969d5e0ff 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -103,6 +103,7 @@ pub(crate) fn reference_definition(
103 103
104#[cfg(test)] 104#[cfg(test)]
105mod tests { 105mod tests {
106 use expect::{expect, Expect};
106 use test_utils::assert_eq_text; 107 use test_utils::assert_eq_text;
107 108
108 use crate::mock_analysis::analysis_and_position; 109 use crate::mock_analysis::analysis_and_position;
@@ -142,16 +143,40 @@ mod tests {
142 nav.assert_match(expected); 143 nav.assert_match(expected);
143 } 144 }
144 145
146 fn check(ra_fixture: &str, expect: Expect) {
147 let (analysis, pos) = analysis_and_position(ra_fixture);
148
149 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
150 if navs.len() == 0 {
151 panic!("unresolved reference")
152 }
153 assert_eq!(navs.len(), 1);
154
155 let nav = navs.pop().unwrap();
156 let file_text = analysis.file_text(nav.file_id()).unwrap();
157
158 let mut actual = nav.debug_render();
159 actual += "\n";
160 actual += &file_text[nav.full_range()].to_string();
161 if let Some(focus) = nav.focus_range() {
162 actual += "|";
163 actual += &file_text[focus];
164 actual += "\n";
165 }
166 expect.assert_eq(&actual);
167 }
168
145 #[test] 169 #[test]
146 fn goto_def_in_items() { 170 fn goto_def_in_items() {
147 check_goto( 171 check(
148 " 172 r#"
149 //- /lib.rs 173struct Foo;
150 struct Foo; 174enum E { X(Foo<|>) }
151 enum E { X(Foo<|>) } 175"#,
152 ", 176 expect![[r#"
153 "Foo STRUCT_DEF FileId(1) 0..11 7..10", 177 Foo STRUCT_DEF FileId(1) 0..11 7..10
154 "struct Foo;|Foo", 178 struct Foo;|Foo
179 "#]],
155 ); 180 );
156 } 181 }
157 182