use super::*;
fn programs(command: &str) -> Vec<String> {
segments(command)
.into_iter()
.filter_map(|s| s.words.first().cloned())
.collect()
}
#[test]
fn one_command_is_one_segment_with_its_words() {
let segs = segments("ls -la /tmp");
assert_eq!(segs.len(), 1);
assert_eq!(segs[0].words, ["ls", "-la", "/tmp"]);
assert!(segs[0].redirects.is_empty());
}
#[test]
fn every_separator_cuts_a_segment() {
let mut got = programs("ls; a && b || c | d & e\nf < g");
got.sort();
assert_eq!(got, ["a", "b", "c", "d", "e", "f", "g", "ls"]);
}
#[test]
fn quotes_and_escapes_keep_a_word_whole() {
let segs = segments(r#"echo 'a; b' "c && d" e\ f"#);
assert_eq!(segs.len(), 1);
assert_eq!(segs[0].words, ["echo", "a; b", "c && d", "e f"]);
assert_eq!(segments("echo x\\").len(), 1);
}
#[test]
fn a_write_redirect_is_held_apart_from_the_words() {
let segs = segments("echo hi > /etc/hosts");
assert_eq!(segs[0].words, ["echo", "hi"]);
assert_eq!(segs[0].redirects, ["/etc/hosts"]);
let segs = segments("cargo test 2>> log.txt");
assert_eq!(segs[0].redirects, ["log.txt"]);
}
#[test]
fn a_substitution_is_lifted_out_as_its_own_command() {
let mut got = programs("cd `git rev-parse --show-toplevel`");
got.sort();
assert_eq!(got, ["cd", "git"]);
let mut got = programs("echo $(id $(whoami))");
got.sort();
assert_eq!(got, ["echo", "id", "whoami"]);
let mut got = programs("echo \"$(curl x)\"");
got.sort();
assert_eq!(got, ["curl", "echo"]);
assert_eq!(programs("echo '$(curl x)'"), ["echo"]);
}
#[test]
fn an_empty_or_separator_only_command_yields_nothing() {
assert!(segments("").is_empty());
assert!(segments(" ;; && ").is_empty());
}
#[test]
fn the_substitution_worklist_is_capped_by_an_unclassifiable_segment() {
let command = "a ".to_owned() + &"$(b ".repeat(MAX_TEXTS + 4) + &")".repeat(MAX_TEXTS + 4);
let segs = segments(&command);
assert!(
segs.iter().any(|s| s.words == [OVERFLOW_WORD]),
"the cap must leave a mark: {segs:?}"
);
}