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