use crate::command_options::{
Arity, DEFAULT_MODE, Occurrence, OptionError, OptionErrorKind, OptionSpec, OptionValue,
ParsedOptions, parse_options, row,
};
use crate::command_options_query::{is_enabled, is_stated, last_occurrence};
use crate::command_test_support::{
ALL, ALLOW_EMPTY, ALLOW_EMPTY_MESSAGE, AMEND, NO_VERIFY, os_arguments, parse_synthetic,
};
fn refusal(kind: OptionErrorKind) -> Result<ParsedOptions, OptionError> {
return Err(OptionError { kind, token: 0 });
}
#[test]
fn resolves_unique_abbreviations() {
let parsed: ParsedOptions =
parse_synthetic(&["--am", "--mess=x", "--untracked=no"]).expect("valid");
assert!(is_enabled(&parsed, AMEND));
assert_eq!(
parsed.occurrences[1].value,
Some(OptionValue::Attached {
token: 1,
offset: 7
})
);
assert_eq!(
parsed.occurrences[2].value,
Some(OptionValue::Attached {
token: 2,
offset: 12
})
);
}
#[test]
fn refuses_ambiguous_abbreviations() {
for values in [
vec!["--a"],
vec!["--allow"],
vec!["--allow-"],
vec!["--n"],
vec!["--no"],
vec!["--no-"],
vec!["--no-a"],
vec!["--=x"],
] {
assert_eq!(
parse_synthetic(values.as_slice()),
refusal(OptionErrorKind::AmbiguousOption),
"{values:?}"
);
}
}
#[test]
fn prefers_an_exact_name_over_an_abbreviation() {
let exact: ParsedOptions =
parse_synthetic(&["--allow-empty", "--allow-empty-m"]).expect("valid");
assert_eq!(exact.occurrences[0].id, ALLOW_EMPTY);
assert_eq!(exact.occurrences[1].id, ALLOW_EMPTY_MESSAGE);
let reordered: &[OptionSpec] = &[
row(
ALLOW_EMPTY_MESSAGE,
None,
Some("allow-empty-message"),
Arity::None,
true,
),
row(ALLOW_EMPTY, None, Some("allow-empty"), Arity::None, true),
];
let later_exact: ParsedOptions = parse_options(
os_arguments(&["--allow-empty"]).as_slice(),
reordered,
DEFAULT_MODE,
&[],
)
.expect("exact match");
assert!(is_enabled(&later_exact, ALLOW_EMPTY));
assert!(!is_stated(&later_exact, ALLOW_EMPTY_MESSAGE));
}
#[test]
fn negates_with_a_no_prefix() {
let negated: ParsedOptions = parse_synthetic(&["--all", "--no-all", "--no-am"]).expect("ok");
assert!(is_stated(&negated, ALL) && !is_enabled(&negated, ALL));
assert_eq!(
last_occurrence(&negated, AMEND),
Some(Occurrence {
id: AMEND,
negated: true,
value: None,
token: 2
})
);
let restored: ParsedOptions = parse_synthetic(&["--no-all", "--all"]).expect("ok");
assert!(is_enabled(&restored, ALL));
}
#[test]
fn reads_rows_whose_name_starts_with_no() {
let on: ParsedOptions = parse_synthetic(&["--no-verify"]).expect("ok");
assert!(is_enabled(&on, NO_VERIFY));
let positive: ParsedOptions = parse_synthetic(&["--verify"]).expect("ok");
assert!(is_stated(&positive, NO_VERIFY) && !is_enabled(&positive, NO_VERIFY));
let double: ParsedOptions = parse_synthetic(&["--no-no-verify"]).expect("ok");
assert!(is_stated(&double, NO_VERIFY) && !is_enabled(&double, NO_VERIFY));
assert_eq!(
parse_synthetic(&["--no-no-all"]),
refusal(OptionErrorKind::UnknownOption)
);
}
#[test]
fn refuses_negation_of_non_negatable_rows() {
for values in [vec!["--no-hard"], vec!["--no-contains"], vec!["--no-har"]] {
assert_eq!(
parse_synthetic(values.as_slice()),
refusal(OptionErrorKind::UnknownOption),
"{values:?}"
);
}
assert!(parse_synthetic(&["--hard", "--har"]).is_ok());
}
#[test]
fn resolves_a_very_short_negation_when_unique() {
let only_all: &[OptionSpec] = &[row(ALL, Some(b'a'), Some("all"), Arity::None, true)];
assert_eq!(
parse_options(
os_arguments(&["--no-"]).as_slice(),
only_all,
DEFAULT_MODE,
&[]
),
refusal(OptionErrorKind::AmbiguousOption)
);
for spelling in ["--n", "--no"] {
let parsed: ParsedOptions = parse_options(
os_arguments(&[spelling]).as_slice(),
only_all,
DEFAULT_MODE,
&[],
)
.expect("unique negation");
assert_eq!(
parsed.occurrences,
vec![Occurrence {
id: ALL,
negated: true,
value: None,
token: 0
}],
"{spelling}"
);
}
}
#[test]
fn reads_help_and_refuses_unknown_names() {
for values in [
vec!["--help"],
vec!["--help-all"],
vec!["--git-completion-helper"],
vec!["--git-completion-helper-all"],
] {
assert_eq!(
parse_synthetic(values.as_slice()),
refusal(OptionErrorKind::HelpRequested),
"{values:?}"
);
}
assert_eq!(
parse_synthetic(&["-a", "--git-completion-helper"]),
Err(OptionError {
kind: OptionErrorKind::UnknownOption,
token: 1
})
);
for values in [vec!["--unknown"], vec!["--allx"], vec!["--message-x=1"]] {
assert_eq!(
parse_synthetic(values.as_slice()),
refusal(OptionErrorKind::UnknownOption),
"{values:?}"
);
}
}