aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_db/src/fixture.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_db/src/fixture.rs')
-rw-r--r--crates/ra_db/src/fixture.rs130
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
3use std::str::FromStr; 61use std::str::FromStr;
4use std::sync::Arc; 62use std::sync::Arc;
5 63
6use ra_cfg::CfgOptions; 64use ra_cfg::CfgOptions;
7use rustc_hash::FxHashMap; 65use rustc_hash::FxHashMap;
8use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; 66use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER};
9 67
10use crate::{ 68use 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) 261impl From<&FixtureMeta> for ParsedMeta {
204fn 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
249fn 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}