use super::{STATUS_TABLE, StatusRegion, has_status_hints_override, parse_status_region};
use crate::command_options::OptionErrorKind;
use crate::command_test_completion::{git_completion, render_completion};
use crate::command_test_support::{
assert_table_invariants, git, git_status, os_arguments, output_text, remove,
repository_with_tracked_file,
};
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Output;
fn machine_readable(values: &[&str]) -> bool {
return parse_status_region(os_arguments(values).as_slice(), &[])
.expect("valid region")
.machine_readable;
}
#[test]
fn detects_machine_readable_formats() {
for values in [
vec!["--porcelain"],
vec!["--porcelain=v2"],
vec!["--porcelain=v1", "path"],
vec!["-z"],
vec!["-s"],
vec!["--short"],
vec!["--null"],
vec!["-sb"],
vec!["-bs"],
vec!["-bz"],
vec!["--por"],
vec!["--shor"],
vec!["--long", "--short"],
vec!["--no-short", "-s"],
] {
assert!(machine_readable(values.as_slice()), "{values:?}");
}
}
#[test]
fn detects_human_readable_formats() {
for values in [
vec![],
vec!["path"],
vec!["--long"],
vec!["-b", "-v", "--show-stash"],
vec!["--short", "--long"],
vec!["-s", "--no-short"],
vec!["--porcelain", "--no-porcelain"],
vec!["-z", "--no-null"],
vec!["--", "--porcelain", "-s"],
vec!["-us"],
] {
assert!(!machine_readable(values.as_slice()), "{values:?}");
}
}
#[test]
fn reads_optional_values_and_refusals() {
assert!(machine_readable(&["--porcelain", "v2"]));
assert!(machine_readable(&["--untracked-files", "-s"]));
assert!(machine_readable(&["--column", "--ignored", "-M", "-s"]));
for (values, kind) in [
(vec!["--unknown"], OptionErrorKind::UnknownOption),
(vec!["--short=1"], OptionErrorKind::UnexpectedValue),
(vec!["--no-find-renames"], OptionErrorKind::UnknownOption),
(vec!["--ignore"], OptionErrorKind::AmbiguousOption),
(vec!["--sh"], OptionErrorKind::AmbiguousOption),
(vec!["-h"], OptionErrorKind::HelpRequested),
] {
assert_eq!(
parse_status_region(os_arguments(values.as_slice()).as_slice(), &[])
.expect_err("refused")
.kind,
kind,
"{values:?}"
);
}
let wrapped: StatusRegion = parse_status_region(
os_arguments(&["--cli-git-keep-going", "-s"]).as_slice(),
&[b"--cli-git-keep-going"],
)
.expect("valid region");
assert_eq!(wrapped.wrapper.len(), 1);
assert!(wrapped.machine_readable);
}
fn overridden(values: &[&str]) -> bool {
return has_status_hints_override(os_arguments(values).as_slice());
}
#[test]
fn detects_the_advice_key_in_global_options() {
for values in [
vec!["-c", "advice.statusHints=true"],
vec!["-c", "advice.statusHints"],
vec!["-c", "Advice.StatusHints=true"],
vec!["-c", "ADVICE.STATUSHINTS=false"],
vec!["-c", "advice.statusHints="],
vec!["-c", "advice.statusHints=a=b"],
vec![
"-C",
"/repo",
"-c",
"a.b=c",
"-c",
"advice.statusHints=true",
"--no-pager",
],
vec!["--config-env=advice.statusHints=HINTS"],
vec!["--config-env", "advice.statusHints=HINTS"],
] {
assert!(overridden(values.as_slice()), "{values:?}");
}
}
#[test]
fn ignores_everything_that_does_not_set_the_advice_key() {
for values in [
vec![],
vec!["-c", "advice.statusHintsX=true"],
vec!["-c", "advice.status=true"],
vec!["-c", "a.b=advice.statusHints=true"],
vec!["-C", "advice.statusHints=true"],
vec!["--git-dir", "advice.statusHints"],
vec!["--namespace", "-c", "--no-pager"],
vec!["--config-env=advice.statusHints"],
vec!["--config-env", "advice.statusHints"],
vec!["--config-env=a.b=advice.statusHints"],
vec!["--config-env=advice.statusHints=x=HINTS"],
vec!["-c"],
vec!["--no-pager", "--bare"],
] {
assert!(!overridden(values.as_slice()), "{values:?}");
}
assert!(!overridden(&["-C", "-c", "advice.statusHints=true"]));
}
#[cfg(unix)]
#[test]
fn compares_keys_as_bytes() {
use crate::command_test_support::byte_argument;
let prefix: Vec<OsString> = vec![
OsString::from("-c"),
byte_argument(b"advice.statusHints=\xff"),
];
assert!(has_status_hints_override(prefix.as_slice()));
let other: Vec<OsString> = vec![
OsString::from("-c"),
byte_argument(b"advice.status\xffints=true"),
];
assert!(!has_status_hints_override(other.as_slice()));
}
#[test]
fn table_and_config_env_match_git() {
let (directory, root): (PathBuf, PathBuf) = repository_with_tracked_file("status-table");
assert_table_invariants(STATUS_TABLE);
assert_eq!(
render_completion(STATUS_TABLE),
git_completion(root.as_path(), &["status"])
);
let from_environment: Output = git(
root.as_path(),
&[
"--config-env=advice.statusHints=PATH",
"config",
"get",
"advice.statusHints",
],
);
assert_eq!(output_text(&from_environment), "/usr/bin:/bin");
let first: Output = git(
root.as_path(),
&[
"-c",
"advice.statusHints=a=b",
"config",
"get",
"advice.statusHints",
],
);
assert_eq!(output_text(&first), "a=b");
let last: Output = git_status(
root.as_path(),
&[
"--config-env=advice.statusHints=x=PATH",
"config",
"get",
"advice.statusHints",
],
);
assert!(!last.status.success());
assert!(String::from_utf8_lossy(&last.stderr).contains("invalid key: advice.statusHints=x"));
remove(directory.as_path());
}