aboutsummaryrefslogtreecommitdiff
path: root/crates/test_utils/src/lib.rs
diff options
context:
space:
mode:
authorMikhail Rakhmanov <[email protected]>2020-06-03 19:10:54 +0100
committerMikhail Rakhmanov <[email protected]>2020-06-03 19:10:54 +0100
commiteefa10bc6bff3624ddd0bbb6bc89d8beb4bed186 (patch)
tree15c38c2993c52f4065d338090ca9185cc1fcd3da /crates/test_utils/src/lib.rs
parenta9d567584857b1be4ca8eaa5ef2c7d85f7b2845e (diff)
parent794f6da821c5d6e2490b996baffe162e4753262d (diff)
Merge branch 'master' into assists_extract_enum
Diffstat (limited to 'crates/test_utils/src/lib.rs')
-rw-r--r--crates/test_utils/src/lib.rs156
1 files changed, 150 insertions, 6 deletions
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index be2cfbaa2..2141bfc20 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -14,6 +14,11 @@ use std::{
14 path::{Path, PathBuf}, 14 path::{Path, PathBuf},
15}; 15};
16 16
17pub use ra_cfg::CfgOptions;
18use stdx::split1;
19
20pub use relative_path::{RelativePath, RelativePathBuf};
21pub use rustc_hash::FxHashMap;
17use serde_json::Value; 22use serde_json::Value;
18use text_size::{TextRange, TextSize}; 23use text_size::{TextRange, TextSize};
19 24
@@ -157,10 +162,82 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
157 162
158#[derive(Debug, Eq, PartialEq)] 163#[derive(Debug, Eq, PartialEq)]
159pub struct FixtureEntry { 164pub struct FixtureEntry {
160 pub meta: String, 165 pub meta: FixtureMeta,
161 pub text: String, 166 pub text: String,
162} 167}
163 168
169#[derive(Debug, Eq, PartialEq)]
170pub enum FixtureMeta {
171 Root { path: RelativePathBuf },
172 File(FileMeta),
173}
174
175#[derive(Debug, Eq, PartialEq)]
176pub struct FileMeta {
177 pub path: RelativePathBuf,
178 pub crate_name: Option<String>,
179 pub deps: Vec<String>,
180 pub cfg: CfgOptions,
181 pub edition: Option<String>,
182 pub env: FxHashMap<String, String>,
183}
184
185impl FixtureMeta {
186 pub fn path(&self) -> &RelativePath {
187 match self {
188 FixtureMeta::Root { path } => &path,
189 FixtureMeta::File(f) => &f.path,
190 }
191 }
192
193 pub fn crate_name(&self) -> Option<&String> {
194 match self {
195 FixtureMeta::File(f) => f.crate_name.as_ref(),
196 _ => None,
197 }
198 }
199
200 pub fn cfg_options(&self) -> Option<&CfgOptions> {
201 match self {
202 FixtureMeta::File(f) => Some(&f.cfg),
203 _ => None,
204 }
205 }
206
207 pub fn edition(&self) -> Option<&String> {
208 match self {
209 FixtureMeta::File(f) => f.edition.as_ref(),
210 _ => None,
211 }
212 }
213
214 pub fn env(&self) -> impl Iterator<Item = (&String, &String)> {
215 struct EnvIter<'a> {
216 iter: Option<std::collections::hash_map::Iter<'a, String, String>>,
217 }
218
219 impl<'a> EnvIter<'a> {
220 fn new(meta: &'a FixtureMeta) -> Self {
221 Self {
222 iter: match meta {
223 FixtureMeta::File(f) => Some(f.env.iter()),
224 _ => None,
225 },
226 }
227 }
228 }
229
230 impl<'a> Iterator for EnvIter<'a> {
231 type Item = (&'a String, &'a String);
232 fn next(&mut self) -> Option<Self::Item> {
233 self.iter.as_mut().and_then(|i| i.next())
234 }
235 }
236
237 EnvIter::new(self)
238 }
239}
240
164/// Parses text which looks like this: 241/// Parses text which looks like this:
165/// 242///
166/// ```not_rust 243/// ```not_rust
@@ -169,8 +246,8 @@ pub struct FixtureEntry {
169/// line 2 246/// line 2
170/// // - other meta 247/// // - other meta
171/// ``` 248/// ```
172pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> { 249pub fn parse_fixture(ra_fixture: &str) -> Vec<FixtureEntry> {
173 let fixture = indent_first_line(fixture); 250 let fixture = indent_first_line(ra_fixture);
174 let margin = fixture_margin(&fixture); 251 let margin = fixture_margin(&fixture);
175 252
176 let mut lines = fixture 253 let mut lines = fixture
@@ -200,6 +277,7 @@ The offending line: {:?}"#,
200 for line in lines.by_ref() { 277 for line in lines.by_ref() {
201 if line.starts_with("//-") { 278 if line.starts_with("//-") {
202 let meta = line["//-".len()..].trim().to_string(); 279 let meta = line["//-".len()..].trim().to_string();
280 let meta = parse_meta(&meta);
203 res.push(FixtureEntry { meta, text: String::new() }) 281 res.push(FixtureEntry { meta, text: String::new() })
204 } else if let Some(entry) = res.last_mut() { 282 } else if let Some(entry) = res.last_mut() {
205 entry.text.push_str(line); 283 entry.text.push_str(line);
@@ -209,6 +287,52 @@ The offending line: {:?}"#,
209 res 287 res
210} 288}
211 289
290//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
291fn parse_meta(meta: &str) -> FixtureMeta {
292 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
293
294 if components[0] == "root" {
295 let path: RelativePathBuf = components[1].into();
296 assert!(path.starts_with("/") && path.ends_with("/"));
297 return FixtureMeta::Root { path };
298 }
299
300 let path: RelativePathBuf = components[0].into();
301 assert!(path.starts_with("/"));
302
303 let mut krate = None;
304 let mut deps = Vec::new();
305 let mut edition = None;
306 let mut cfg = CfgOptions::default();
307 let mut env = FxHashMap::default();
308 for component in components[1..].iter() {
309 let (key, value) = split1(component, ':').unwrap();
310 match key {
311 "crate" => krate = Some(value.to_string()),
312 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
313 "edition" => edition = Some(value.to_string()),
314 "cfg" => {
315 for key in value.split(',') {
316 match split1(key, '=') {
317 None => cfg.insert_atom(key.into()),
318 Some((k, v)) => cfg.insert_key_value(k.into(), v.into()),
319 }
320 }
321 }
322 "env" => {
323 for key in value.split(',') {
324 if let Some((k, v)) = split1(key, '=') {
325 env.insert(k.into(), v.into());
326 }
327 }
328 }
329 _ => panic!("bad component: {:?}", component),
330 }
331 }
332
333 FixtureMeta::File(FileMeta { path, crate_name: krate, deps, edition, cfg, env })
334}
335
212/// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. 336/// 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 337/// This allows fixtures to start off in a different indentation, e.g. to align the first line with
214/// the other lines visually: 338/// the other lines visually:
@@ -288,13 +412,33 @@ struct Bar;
288 ) 412 )
289} 413}
290 414
415#[test]
416fn parse_fixture_gets_full_meta() {
417 let parsed = parse_fixture(
418 r"
419 //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo
420 mod m;
421 ",
422 );
423 assert_eq!(1, parsed.len());
424
425 let parsed = &parsed[0];
426 assert_eq!("mod m;\n\n", parsed.text);
427
428 let meta = &parsed.meta;
429 assert_eq!("foo", meta.crate_name().unwrap());
430 assert_eq!("/lib.rs", meta.path());
431 assert!(meta.cfg_options().is_some());
432 assert_eq!(2, meta.env().count());
433}
434
291/// Same as `parse_fixture`, except it allow empty fixture 435/// Same as `parse_fixture`, except it allow empty fixture
292pub fn parse_single_fixture(fixture: &str) -> Option<FixtureEntry> { 436pub fn parse_single_fixture(ra_fixture: &str) -> Option<FixtureEntry> {
293 if !fixture.lines().any(|it| it.trim_start().starts_with("//-")) { 437 if !ra_fixture.lines().any(|it| it.trim_start().starts_with("//-")) {
294 return None; 438 return None;
295 } 439 }
296 440
297 let fixtures = parse_fixture(fixture); 441 let fixtures = parse_fixture(ra_fixture);
298 if fixtures.len() > 1 { 442 if fixtures.len() > 1 {
299 panic!("too many fixtures"); 443 panic!("too many fixtures");
300 } 444 }