#![cfg(all(
feature = "cli",
feature = "embed",
feature = "test-support",
feature = "unix-runtime"
))]
mod support;
use proptest::prelude::*;
use support::{
append_read_command, append_read_results, read_var_names, run_shell, semantic_output,
shell_quote,
};
const READ_IFS_VALUES: &[&str] = &[" \t\n", " ", ""];
const GETOPTS_STRINGS: &[&str] = &[
"a", ":a", "ab", ":ab", "f:", ":f:", "af:", ":af:", "abf:", ":abf:", "a:b", ":a:b",
];
const GETOPTS_ARGS: &[&str] = &[
"-a", "-b", "-f", "-ab", "-ba", "-af", "-bf", "-abf", "-fa", "-fvalue", "-avalue", "-z", "--",
"value", "arg", "",
];
fn read_input() -> impl Strategy<Value = String> {
let ch = prop_oneof![Just('a'), Just('b'), Just(' '), Just(','), Just('\t'),];
prop::collection::vec(ch, 0..8)
.prop_map(|chars| {
let mut s: String = chars.into_iter().collect();
s.push('\n');
s
})
.boxed()
}
fn read_var_count() -> impl Strategy<Value = usize> {
1usize..=3usize
}
fn read_script(ifs: &str, raw_mode: bool, var_count: usize) -> String {
let var_names = read_var_names(var_count);
let mut script = String::new();
append_read_command(&mut script, ifs, raw_mode, var_names);
append_read_results(&mut script, var_names);
script
}
fn getopts_args() -> impl Strategy<Value = Vec<String>> {
prop::collection::vec(prop::sample::select(GETOPTS_ARGS), 0..6).prop_map(|args| {
args.into_iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
})
}
fn getopts_script(optstring: &str, args: &[String], optind: i32, calls: u8) -> String {
let args = args
.iter()
.map(|arg| shell_quote(arg))
.collect::<Vec<_>>()
.join(" ");
let mut script = String::new();
script.push_str(&format!("set -- {args}; "));
script.push_str(&format!("OPTIND={optind}; "));
script.push_str("OPTARG=keep; ");
for _ in 0..calls {
script.push_str(&format!("getopts {} opt; ", shell_quote(optstring)));
script
.push_str("printf '%s|%s|%s|%s\\n' \"$opt\" \"${OPTARG-unset}\" \"$OPTIND\" \"$?\"; ");
}
script
}
proptest! {
#![proptest_config(ProptestConfig {
cases: 128,
max_local_rejects: 0,
failure_persistence: None,
.. ProptestConfig::default()
})]
#[test]
fn read_matches_dash(
ifs in prop::sample::select(READ_IFS_VALUES),
raw_mode in any::<bool>(),
var_count in read_var_count(),
stdin in read_input(),
) {
let script = read_script(ifs, raw_mode, var_count);
let mxsh = run_shell("mxsh", &["-c", &script], &stdin);
let sh = run_shell("/bin/sh", &["-c", &script], &stdin);
prop_assert_eq!(
semantic_output(&mxsh),
semantic_output(&sh),
"script={:?} stdin={:?}",
script,
stdin,
);
}
#[test]
fn getopts_matches_dash(
optstring in prop::sample::select(GETOPTS_STRINGS),
args in getopts_args(),
optind in prop_oneof![Just(-1), Just(0), 1i32..=6i32, Just(999)],
calls in 1u8..=5u8,
) {
let script = getopts_script(optstring, &args, optind, calls);
let mxsh = run_shell("mxsh", &["-c", &script], "");
let sh = run_shell("/bin/sh", &["-c", &script], "");
prop_assert_eq!(
semantic_output(&mxsh),
semantic_output(&sh),
"script={:?}",
script,
);
}
}