Skip to content

Commit 0da9124

Browse files
committed
feat(tests): Add support for arguments with internal whitespace in directives
1 parent 58696e1 commit 0da9124

1 file changed

Lines changed: 59 additions & 5 deletions

File tree

tests/src/main.rs

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,62 @@ fn parse_directives(path: &Path) -> Vec<String> {
172172
directives
173173
}
174174

175+
fn parse_args(args_str: &str) -> Vec<&str> {
176+
let mut args = vec![];
177+
178+
let mut char_indices_iter = args_str.char_indices();
179+
while let Some((c_idx, c)) = char_indices_iter.next() {
180+
// NOTE: Skip past multiple consecutive whitespace separators between args.
181+
if c.is_whitespace() { continue; }
182+
183+
let (start_idx, end_idx) = match c {
184+
'"' => {
185+
let start_idx = char_indices_iter.offset();
186+
let end_idx = 'end_idx: {
187+
while let Some((c_idx, c)) = char_indices_iter.next() {
188+
if c != '"' { continue; }
189+
match char_indices_iter.clone().next() {
190+
None => { break 'end_idx c_idx; }
191+
Some((_, next_c)) if next_c.is_whitespace() => {
192+
// NOTE: Skip past the whitespace character after `"`.
193+
let _ = char_indices_iter.next();
194+
break 'end_idx c_idx;
195+
}
196+
_ => { continue; }
197+
}
198+
}
199+
// NOTE: This is the fallback value if `"` is not closed by the end of the args list.
200+
args_str.len()
201+
};
202+
(start_idx, end_idx)
203+
}
204+
_ => {
205+
let end_idx = 'end_idx: {
206+
while let Some((c_idx, c)) = char_indices_iter.next() {
207+
if c.is_whitespace() { break 'end_idx c_idx; }
208+
}
209+
args_str.len()
210+
};
211+
(c_idx, end_idx)
212+
}
213+
};
214+
215+
args.push(&args_str[start_idx..end_idx]);
216+
}
217+
218+
args
219+
}
220+
221+
#[test]
222+
fn test_parse_args() {
223+
assert_eq!(["foo", "bar", "baz"], parse_args("foo bar baz")[..]);
224+
assert_eq!(["foo", "bar", "baz"], parse_args("foo bar baz")[..]);
225+
assert_eq!(["foo", "bar baz", "abc"], parse_args("foo \"bar baz\" abc")[..]);
226+
assert_eq!(["foo", "bar=\"baz\"", "abc"], parse_args("foo \"bar=\"baz\"\" abc")[..]);
227+
assert_eq!(["foo", "bar baz"], parse_args("foo \"bar baz\"")[..]);
228+
assert_eq!(["foo", "bar baz"], parse_args("foo \"bar baz")[..]);
229+
}
230+
175231
fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, results: &mut TestRunResults) {
176232
if !path.is_file() { return; }
177233
if !path.extension().is_some_and(|v| v == "rs") { return; }
@@ -478,8 +534,7 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
478534
cmd.env(key, val);
479535
}
480536

481-
let rustc_flags = directives.iter().filter_map(|d| d.strip_prefix("rustc-flags:").map(str::trim))
482-
.flat_map(|flags| flags.split(" ").filter(|flag| !flag.is_empty()));
537+
let rustc_flags = directives.iter().filter_map(|d| d.strip_prefix("rustc-flags:").map(str::trim)).flat_map(parse_args);
483538
cmd.args(rustc_flags);
484539

485540
if aux {
@@ -506,7 +561,7 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
506561
mutest_args.push(mutest_prints.into_iter().intersperse(",").collect::<String>());
507562
}
508563
directives.iter().filter_map(|d| d.strip_prefix("mutest-flags:").map(str::trim))
509-
.flat_map(|flags| flags.split(" ").filter(|flag| !flag.is_empty()).map(str::to_owned))
564+
.flat_map(|flags| parse_args(flags).into_iter().map(str::to_owned))
510565
.collect_into(&mut mutest_args);
511566
mutest_args.push(mutest_subcommand.to_owned());
512567
cmd.env("MUTEST_ENCODED_ARGS".to_owned(), mutest_args.join("\x1F"));
@@ -561,8 +616,7 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
561616
cmd.env(key, val);
562617
}
563618

564-
let run_flags = directives.iter().filter_map(|d| d.strip_prefix("run-flags:").map(str::trim))
565-
.flat_map(|flags| flags.split(" ").filter(|flag| !flag.is_empty()));
619+
let run_flags = directives.iter().filter_map(|d| d.strip_prefix("run-flags:").map(str::trim)).flat_map(parse_args);
566620
cmd.args(run_flags);
567621

568622
// NOTE: Avoid passing on the `CARGO_*` environment variables from the test runner.

0 commit comments

Comments
 (0)