use super::*;
fn patterns() -> Vec<Pattern> {
crate::pattern::builtins().to_vec()
}
#[test]
fn double_spaces_inside_double_quotes_preserved() {
let out = rewrite("pytest -k \"a b\"", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k \"a b\"");
}
#[test]
fn double_spaces_inside_single_quotes_preserved() {
let out = rewrite("pytest -k 'a b'", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k 'a b'");
}
#[test]
fn tabs_preserved() {
let out = rewrite("pytest\t-q", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest\t-q");
let out = rewrite("pytest -q\t\t--x", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -q\t\t--x");
}
#[test]
fn embedded_newline_inside_quotes_preserved() {
let out = rewrite("pytest -k \"a\nb\"", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k \"a\nb\"");
let out = rewrite("pytest -k 'a\nb'", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k 'a\nb'");
}
#[test]
fn leading_trailing_whitespace_preserved_in_segment() {
let out = rewrite(" pytest -q ", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -q");
let out = rewrite("pytest -q --x", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -q --x");
}
#[test]
fn env_prefix_original_spacing_preserved() {
let out = rewrite("FOO=1 pytest -q", &patterns()).expect("must rewrite");
assert_eq!(out, "FOO=1 oo pytest -q");
let out = rewrite("FOO=1 BAR=2 pytest -q", &patterns()).expect("must rewrite");
assert_eq!(out, "FOO=1 BAR=2 oo pytest -q");
}
#[test]
fn env_value_with_quote_refused() {
assert!(rewrite("FOO='a b' pytest -q", &patterns()).is_none());
assert!(rewrite("FOO=\"a b\" pytest -q", &patterns()).is_none());
}
#[test]
fn env_value_with_backslash_refused() {
assert!(rewrite("FOO=a\\b pytest -q", &patterns()).is_none());
}
#[test]
fn unquoted_newline_refused() {
assert!(rewrite("pytest -q\nfoo", &patterns()).is_none());
let out = rewrite("pytest -k 'a\nb' && pytest", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k 'a\nb' && oo pytest");
}
#[test]
fn multiline_quoted_segment_with_separator() {
let out = rewrite("pytest -k 'x\ny' ; cargo build", &patterns()).expect("must rewrite");
assert_eq!(out, "oo pytest -k 'x\ny' ; oo cargo build");
}
#[test]
fn rewrite_output_is_input_plus_prefixes_only() {
let inputs = [
"pytest -q",
"pytest -k \"a b\"",
"pytest -k 'a b'",
"pytest\t-q",
"pytest -k 'a\nb'",
"FOO=1 pytest -q",
"FOO=1 BAR=2 pytest -q",
"cd x && pytest -q",
"git status && cargo build",
"pytest -q ; cargo build",
"pytest -q || cargo test",
"nope pytest -q",
];
for input in inputs {
let Some(out) = rewrite(input, &patterns()) else {
continue;
};
let trimmed = input.trim();
let reconstructed = strip_inserted_prefixes(trimmed, &out);
assert_eq!(
reconstructed, trimmed,
"output must be input + inserted `oo ` prefixes only (input={input:?})"
);
let inserted = out.len() - trimmed.len();
assert_eq!(
inserted % 3,
0,
"inserted bytes must be a multiple of 3 (input={input:?})"
);
assert_eq!(
out.len(),
trimmed.len() + inserted,
"output length must equal input length + inserted bytes (input={input:?})"
);
}
}
fn strip_inserted_prefixes(input: &str, out: &str) -> String {
let mut result = String::new();
let mut in_iter = input.chars().peekable();
let mut out_iter = out.chars().peekable();
loop {
let in_ch = in_iter.peek().copied();
let out_ch = out_iter.peek().copied();
match (in_ch, out_ch) {
(None, None) => break,
(Some(a), Some(b)) if a == b => {
result.push(a);
in_iter.next();
out_iter.next();
}
(Some(_), Some('o')) => {
let o1 = out_iter.next();
let o2 = out_iter.next();
let o3 = out_iter.next();
assert_eq!(o1, Some('o'));
assert_eq!(o2, Some('o'));
assert_eq!(o3, Some(' '));
}
(Some(_), None) => break,
(Some(_), Some(other)) => {
panic!("unexpected char {other:?} in output not in input");
}
(None, Some(_)) => {
let o1 = out_iter.next();
let o2 = out_iter.next();
let o3 = out_iter.next();
assert_eq!((o1, o2, o3), (Some('o'), Some('o'), Some(' ')));
}
}
}
result
}