aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/fixture.rs46
-rw-r--r--crates/test_utils/src/lib.rs104
2 files changed, 140 insertions, 10 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 8248684ee..51d4c493e 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -1,4 +1,48 @@
1//! FIXME: write short doc here 1//! Fixtures are strings containing rust source code with optional metadata.
2//! A fixture without metadata is parsed into a single source file.
3//! Use this to test functionality local to one file.
4//!
5//! Example:
6//! ```
7//! r#"
8//! fn main() {
9//! println!("Hello World")
10//! }
11//! "#
12//! ```
13//!
14//! Metadata can be added to a fixture after a `//-` comment.
15//! The basic form is specifying filenames,
16//! which is also how to define multiple files in a single test fixture
17//!
18//! Example:
19//! ```
20//! "
21//! //- /main.rs
22//! mod foo;
23//! fn main() {
24//! foo::bar();
25//! }
26//!
27//! //- /foo.rs
28//! pub fn bar() {}
29//! "
30//! ```
31//!
32//! Metadata allows specifying all settings and variables
33//! that are available in a real rust project:
34//! - crate names via `crate:cratename`
35//! - dependencies via `deps:dep1,dep2`
36//! - configuration settings via `cfg:dbg=false,opt_level=2`
37//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
38//!
39//! Example:
40//! ```
41//! "
42//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
43//! fn insert_source_code_here() {}
44//! "
45//! ```
2 46
3use std::str::FromStr; 47use std::str::FromStr;
4use std::sync::Arc; 48use std::sync::Arc;
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index b1365444a..b13e13af2 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -155,7 +155,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
155 res 155 res
156} 156}
157 157
158#[derive(Debug)] 158#[derive(Debug, Eq, PartialEq)]
159pub struct FixtureEntry { 159pub struct FixtureEntry {
160 pub meta: String, 160 pub meta: String,
161 pub text: String, 161 pub text: String,
@@ -170,19 +170,26 @@ pub struct FixtureEntry {
170/// // - other meta 170/// // - other meta
171/// ``` 171/// ```
172pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> { 172pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
173 let margin = fixture 173 let fixture = indent_first_line(fixture);
174 .lines() 174 let margin = fixture_margin(&fixture);
175 .filter(|it| it.trim_start().starts_with("//-"))
176 .map(|it| it.len() - it.trim_start().len())
177 .next()
178 .expect("empty fixture");
179 175
180 let mut lines = fixture 176 let mut lines = fixture
181 .split('\n') // don't use `.lines` to not drop `\r\n` 177 .split('\n') // don't use `.lines` to not drop `\r\n`
182 .filter_map(|line| { 178 .enumerate()
179 .filter_map(|(ix, line)| {
183 if line.len() >= margin { 180 if line.len() >= margin {
184 assert!(line[..margin].trim().is_empty()); 181 assert!(line[..margin].trim().is_empty());
185 Some(&line[margin..]) 182 let line_content = &line[margin..];
183 if !line_content.starts_with("//-") {
184 assert!(
185 !line_content.contains("//-"),
186 r#"Metadata line {} has invalid indentation. All metadata lines need to have the same indentation.
187The offending line: {:?}"#,
188 ix,
189 line
190 );
191 }
192 Some(line_content)
186 } else { 193 } else {
187 assert!(line.trim().is_empty()); 194 assert!(line.trim().is_empty());
188 None 195 None
@@ -202,6 +209,85 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
202 res 209 res
203} 210}
204 211
212/// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines.
213/// This allows fixtures to start off in a different indentation, e.g. to align the first line with
214/// the other lines visually:
215/// ```
216/// let fixture = "//- /lib.rs
217/// mod foo;
218/// //- /foo.rs
219/// fn bar() {}
220/// ";
221/// assert_eq!(fixture_margin(fixture),
222/// " //- /lib.rs
223/// mod foo;
224/// //- /foo.rs
225/// fn bar() {}
226/// ")
227/// ```
228fn indent_first_line(fixture: &str) -> String {
229 if fixture.is_empty() {
230 return String::new();
231 }
232 let mut lines = fixture.lines();
233 let first_line = lines.next().unwrap();
234 if first_line.contains("//-") {
235 let rest = lines.collect::<Vec<_>>().join("\n");
236 let fixed_margin = fixture_margin(&rest);
237 let fixed_indent = fixed_margin - indent_len(first_line);
238 format!("\n{}{}\n{}", " ".repeat(fixed_indent), first_line, rest)
239 } else {
240 fixture.to_owned()
241 }
242}
243
244fn fixture_margin(fixture: &str) -> usize {
245 fixture
246 .lines()
247 .filter(|it| it.trim_start().starts_with("//-"))
248 .map(indent_len)
249 .next()
250 .expect("empty fixture")
251}
252
253fn indent_len(s: &str) -> usize {
254 s.len() - s.trim_start().len()
255}
256
257#[test]
258#[should_panic]
259fn parse_fixture_checks_further_indented_metadata() {
260 parse_fixture(
261 r"
262 //- /lib.rs
263 mod bar;
264
265 fn foo() {}
266 //- /bar.rs
267 pub fn baz() {}
268 ",
269 );
270}
271
272#[test]
273fn parse_fixture_can_handle_unindented_first_line() {
274 let fixture = "//- /lib.rs
275 mod foo;
276 //- /foo.rs
277 struct Bar;
278";
279 assert_eq!(
280 parse_fixture(fixture),
281 parse_fixture(
282 "//- /lib.rs
283mod foo;
284//- /foo.rs
285struct Bar;
286"
287 )
288 )
289}
290
205/// Same as `parse_fixture`, except it allow empty fixture 291/// Same as `parse_fixture`, except it allow empty fixture
206pub fn parse_single_fixture(fixture: &str) -> Option<FixtureEntry> { 292pub fn parse_single_fixture(fixture: &str) -> Option<FixtureEntry> {
207 if !fixture.lines().any(|it| it.trim_start().starts_with("//-")) { 293 if !fixture.lines().any(|it| it.trim_start().starts_with("//-")) {