]> git.lizzy.rs Git - rust.git/blob - crates/test_utils/src/fixture.rs
Merge #8055
[rust.git] / crates / test_utils / src / fixture.rs
1 //! Defines `Fixture` -- a convenient way to describe the initial state of
2 //! rust-analyzer database from a single string.
3
4 use rustc_hash::FxHashMap;
5 use stdx::{lines_with_ends, split_once, trim_indent};
6
7 #[derive(Debug, Eq, PartialEq)]
8 pub struct Fixture {
9     pub path: String,
10     pub text: String,
11     pub krate: Option<String>,
12     pub deps: Vec<String>,
13     pub cfg_atoms: Vec<String>,
14     pub cfg_key_values: Vec<(String, String)>,
15     pub edition: Option<String>,
16     pub env: FxHashMap<String, String>,
17     pub introduce_new_source_root: bool,
18 }
19
20 impl Fixture {
21     /// Parses text which looks like this:
22     ///
23     ///  ```not_rust
24     ///  //- some meta
25     ///  line 1
26     ///  line 2
27     ///  // - other meta
28     ///  ```
29     pub fn parse(ra_fixture: &str) -> Vec<Fixture> {
30         let fixture = trim_indent(ra_fixture);
31
32         let mut res: Vec<Fixture> = Vec::new();
33
34         let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") };
35
36         for (ix, line) in default.into_iter().chain(lines_with_ends(&fixture)).enumerate() {
37             if line.contains("//-") {
38                 assert!(
39                     line.starts_with("//-"),
40                     "Metadata line {} has invalid indentation. \
41                      All metadata lines need to have the same indentation.\n\
42                      The offending line: {:?}",
43                     ix,
44                     line
45                 );
46             }
47
48             if line.starts_with("//-") {
49                 let meta = Fixture::parse_meta_line(line);
50                 res.push(meta)
51             } else if let Some(entry) = res.last_mut() {
52                 entry.text.push_str(line);
53             }
54         }
55
56         res
57     }
58
59     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
60     fn parse_meta_line(meta: &str) -> Fixture {
61         assert!(meta.starts_with("//-"));
62         let meta = meta["//-".len()..].trim();
63         let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
64
65         let path = components[0].to_string();
66         assert!(path.starts_with('/'));
67
68         let mut krate = None;
69         let mut deps = Vec::new();
70         let mut edition = None;
71         let mut cfg_atoms = Vec::new();
72         let mut cfg_key_values = Vec::new();
73         let mut env = FxHashMap::default();
74         let mut introduce_new_source_root = false;
75         for component in components[1..].iter() {
76             let (key, value) = split_once(component, ':').unwrap();
77             match key {
78                 "crate" => krate = Some(value.to_string()),
79                 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
80                 "edition" => edition = Some(value.to_string()),
81                 "cfg" => {
82                     for entry in value.split(',') {
83                         match split_once(entry, '=') {
84                             Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())),
85                             None => cfg_atoms.push(entry.to_string()),
86                         }
87                     }
88                 }
89                 "env" => {
90                     for key in value.split(',') {
91                         if let Some((k, v)) = split_once(key, '=') {
92                             env.insert(k.into(), v.into());
93                         }
94                     }
95                 }
96                 "new_source_root" => introduce_new_source_root = true,
97                 _ => panic!("bad component: {:?}", component),
98             }
99         }
100
101         Fixture {
102             path,
103             text: String::new(),
104             krate,
105             deps,
106             cfg_atoms,
107             cfg_key_values,
108             edition,
109             env,
110             introduce_new_source_root,
111         }
112     }
113 }
114
115 #[test]
116 #[should_panic]
117 fn parse_fixture_checks_further_indented_metadata() {
118     Fixture::parse(
119         r"
120         //- /lib.rs
121           mod bar;
122
123           fn foo() {}
124           //- /bar.rs
125           pub fn baz() {}
126           ",
127     );
128 }
129
130 #[test]
131 fn parse_fixture_gets_full_meta() {
132     let parsed = Fixture::parse(
133         r"
134     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo
135     mod m;
136     ",
137     );
138     assert_eq!(1, parsed.len());
139
140     let meta = &parsed[0];
141     assert_eq!("mod m;\n", meta.text);
142
143     assert_eq!("foo", meta.krate.as_ref().unwrap());
144     assert_eq!("/lib.rs", meta.path);
145     assert_eq!(2, meta.env.len());
146 }