diff options
Diffstat (limited to 'crates/ra_db/src/fixture.rs')
-rw-r--r-- | crates/ra_db/src/fixture.rs | 130 |
1 files changed, 80 insertions, 50 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 8248684ee..482a2f3e6 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -1,11 +1,69 @@ | |||
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 | //! Simple 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 using two files in the same crate: | ||
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 | //! Example using two crates with one file each, with one crate depending on the other: | ||
33 | //! ``` | ||
34 | //! r#" | ||
35 | //! //- /main.rs crate:a deps:b | ||
36 | //! fn main() { | ||
37 | //! b::foo(); | ||
38 | //! } | ||
39 | //! //- /lib.rs crate:b | ||
40 | //! pub fn b() { | ||
41 | //! println!("Hello World") | ||
42 | //! } | ||
43 | //! "# | ||
44 | //! ``` | ||
45 | //! | ||
46 | //! Metadata allows specifying all settings and variables | ||
47 | //! that are available in a real rust project: | ||
48 | //! - crate names via `crate:cratename` | ||
49 | //! - dependencies via `deps:dep1,dep2` | ||
50 | //! - configuration settings via `cfg:dbg=false,opt_level=2` | ||
51 | //! - environment variables via `env:PATH=/bin,RUST_LOG=debug` | ||
52 | //! | ||
53 | //! Example using all available metadata: | ||
54 | //! ``` | ||
55 | //! " | ||
56 | //! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | ||
57 | //! fn insert_source_code_here() {} | ||
58 | //! " | ||
59 | //! ``` | ||
2 | 60 | ||
3 | use std::str::FromStr; | 61 | use std::str::FromStr; |
4 | use std::sync::Arc; | 62 | use std::sync::Arc; |
5 | 63 | ||
6 | use ra_cfg::CfgOptions; | 64 | use ra_cfg::CfgOptions; |
7 | use rustc_hash::FxHashMap; | 65 | use rustc_hash::FxHashMap; |
8 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; | 66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; |
9 | 67 | ||
10 | use crate::{ | 68 | use crate::{ |
11 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, |
@@ -55,7 +113,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId | |||
55 | let fixture = parse_single_fixture(ra_fixture); | 113 | let fixture = parse_single_fixture(ra_fixture); |
56 | 114 | ||
57 | let crate_graph = if let Some(entry) = fixture { | 115 | let crate_graph = if let Some(entry) = fixture { |
58 | let meta = match parse_meta(&entry.meta) { | 116 | let meta = match ParsedMeta::from(&entry.meta) { |
59 | ParsedMeta::File(it) => it, | 117 | ParsedMeta::File(it) => it, |
60 | _ => panic!("with_single_file only support file meta"), | 118 | _ => panic!("with_single_file only support file meta"), |
61 | }; | 119 | }; |
@@ -112,7 +170,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
112 | let mut file_position = None; | 170 | let mut file_position = None; |
113 | 171 | ||
114 | for entry in fixture.iter() { | 172 | for entry in fixture.iter() { |
115 | let meta = match parse_meta(&entry.meta) { | 173 | let meta = match ParsedMeta::from(&entry.meta) { |
116 | ParsedMeta::Root { path } => { | 174 | ParsedMeta::Root { path } => { |
117 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); | 175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); |
118 | db.set_source_root(source_root_id, Arc::new(source_root)); | 176 | db.set_source_root(source_root_id, Arc::new(source_root)); |
@@ -200,53 +258,25 @@ struct FileMeta { | |||
200 | env: Env, | 258 | env: Env, |
201 | } | 259 | } |
202 | 260 | ||
203 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo) | 261 | impl From<&FixtureMeta> for ParsedMeta { |
204 | fn parse_meta(meta: &str) -> ParsedMeta { | 262 | fn from(meta: &FixtureMeta) -> Self { |
205 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 263 | match meta { |
206 | 264 | FixtureMeta::Root { path } => { | |
207 | if components[0] == "root" { | 265 | // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' |
208 | let path: RelativePathBuf = components[1].into(); | 266 | // see https://github.com/rust-lang/rust/issues/69018 |
209 | assert!(path.starts_with("/") && path.ends_with("/")); | 267 | ParsedMeta::Root { path: path.to_owned() } |
210 | return ParsedMeta::Root { path }; | ||
211 | } | ||
212 | |||
213 | let path: RelativePathBuf = components[0].into(); | ||
214 | assert!(path.starts_with("/")); | ||
215 | |||
216 | let mut krate = None; | ||
217 | let mut deps = Vec::new(); | ||
218 | let mut edition = Edition::Edition2018; | ||
219 | let mut cfg = CfgOptions::default(); | ||
220 | let mut env = Env::default(); | ||
221 | for component in components[1..].iter() { | ||
222 | let (key, value) = split1(component, ':').unwrap(); | ||
223 | match key { | ||
224 | "crate" => krate = Some(value.to_string()), | ||
225 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | ||
226 | "edition" => edition = Edition::from_str(&value).unwrap(), | ||
227 | "cfg" => { | ||
228 | for key in value.split(',') { | ||
229 | match split1(key, '=') { | ||
230 | None => cfg.insert_atom(key.into()), | ||
231 | Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | "env" => { | ||
236 | for key in value.split(',') { | ||
237 | if let Some((k, v)) = split1(key, '=') { | ||
238 | env.set(k, v.into()); | ||
239 | } | ||
240 | } | ||
241 | } | 268 | } |
242 | _ => panic!("bad component: {:?}", component), | 269 | FixtureMeta::File(f) => Self::File(FileMeta { |
270 | path: f.path.to_owned(), | ||
271 | krate: f.crate_name.to_owned(), | ||
272 | deps: f.deps.to_owned(), | ||
273 | cfg: f.cfg.to_owned(), | ||
274 | edition: f | ||
275 | .edition | ||
276 | .as_ref() | ||
277 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | ||
278 | env: Env::from(f.env.iter()), | ||
279 | }), | ||
243 | } | 280 | } |
244 | } | 281 | } |
245 | |||
246 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env }) | ||
247 | } | ||
248 | |||
249 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
250 | let idx = haystack.find(delim)?; | ||
251 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
252 | } | 282 | } |