use winnow::stream::BStr;
use winnow_args::{Args, Error, ErrorKind};
#[derive(Args, Debug, PartialEq, Default)]
#[arg(plus_options, disable_help_flag)]
struct Set {
#[arg(short = 'e', plus = 'e')]
errexit: Option<bool>,
#[arg(short = 'u', plus = 'u')]
nounset: Option<bool>,
#[arg(short = 'x', plus = 'x')]
xtrace: Option<bool>,
#[arg(short = 'o', default_missing = "")]
enable: Vec<String>,
#[arg(plus = 'o', default_missing = "")]
disable: Vec<String>,
#[arg(positional, double_dash = "preserve", stop_flags)]
args: Vec<String>,
#[arg(skip)]
extra: Vec<u32>,
}
fn parse(line: &[&str]) -> Result<Set, Error> {
Set::parse_from(line)
}
fn ok(line: &[&str]) -> Set {
parse(line).unwrap_or_else(|e| panic!("{line:?}: {e}"))
}
fn strings(words: &[&str]) -> Vec<String> {
words.iter().map(|w| w.to_string()).collect()
}
#[test]
fn minus_sets_and_plus_clears() {
let s = ok(&["-eu", "+x"]);
assert_eq!(
(s.errexit, s.nounset, s.xtrace),
(Some(true), Some(true), Some(false))
);
let s = ok(&["+eu"]);
assert_eq!(
(s.errexit, s.nounset, s.xtrace),
(Some(false), Some(false), None)
);
assert_eq!(ok(&["-e", "+e"]).errexit, Some(false));
assert_eq!(ok(&["+e", "-e"]).errexit, Some(true));
}
#[test]
fn value_letters_in_both_bundles() {
let s = ok(&["-euxo", "pipefail", "+o", "noglob"]);
assert_eq!(s.enable, strings(&["pipefail"]));
assert_eq!(s.disable, strings(&["noglob"]));
assert_eq!((s.errexit, s.xtrace), (Some(true), Some(true)));
assert_eq!(ok(&["-o"]).enable, strings(&[""]));
assert_eq!(ok(&["+o"]).disable, strings(&[""]));
}
#[test]
fn operands_end_both_kinds_of_bundle() {
let s = ok(&["-e", "--", "+x", "-u"]);
assert_eq!((s.errexit, s.xtrace, s.nounset), (Some(true), None, None));
assert_eq!(s.args, strings(&["--", "+x", "-u"]));
let s = ok(&["a", "+e"]);
assert_eq!((s.errexit, s.args), (None, strings(&["a", "+e"])));
assert_eq!(ok(&["+"]).args, strings(&["+"]));
assert!(ok(&["-e"]).extra.is_empty());
}
#[test]
fn an_unknown_plus_letter_is_reported_with_its_plus() {
let e = parse(&["+q"]).unwrap_err();
assert_eq!((e.kind(), e.token()), (ErrorKind::UnknownFlag, Some("+q")));
}
#[derive(Args, Debug)]
struct Plain {
#[arg(short)]
e: bool,
#[arg(positional)]
rest: Vec<String>,
}
#[test]
fn plus_words_are_words_elsewhere() {
let words = [BStr::new("+e")];
let p = Plain::parse_words(&words).unwrap();
assert_eq!((p.e, p.rest), (false, strings(&["+e"])));
}