use super::{PUSH_TABLE, PushRegion, parse_push_region};
use crate::command_options::{OptionErrorKind, WrapperOccurrence};
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::path::{Path, PathBuf};
use std::process::Output;
fn region(values: &[&str]) -> PushRegion {
return parse_push_region(os_arguments(values).as_slice(), &[]).expect("valid region");
}
#[test]
fn detects_an_atomicity_choice() {
assert!(!region(&["origin", "main"]).atomic_stated);
assert!(!region(&[]).atomic_stated);
for values in [
vec!["--atomic", "origin", "main"],
vec!["--no-atomic", "origin", "main"],
vec!["origin", "main", "--atomic"],
vec!["--at"],
vec!["--no-at"],
vec!["--atomic", "--no-atomic"],
] {
assert!(region(values.as_slice()).atomic_stated, "{values:?}");
}
for values in [
vec!["-o", "--atomic", "origin"],
vec!["--repo", "--atomic"],
vec!["origin", "--", "--atomic"],
] {
assert!(!region(values.as_slice()).atomic_stated, "{values:?}");
}
}
#[test]
fn reports_the_final_dry_run_state() {
for values in [
vec!["-n"],
vec!["--dry-run", "origin"],
vec!["--dry"],
vec!["-nf"],
vec!["-fn"],
vec!["-vnq"],
vec!["--no-dry-run", "-n"],
] {
assert!(region(values.as_slice()).dry_run, "{values:?}");
}
for values in [
vec!["origin", "main"],
vec!["-n", "--no-dry-run"],
vec!["--dry-run", "--no-dry"],
vec!["-o", "-n", "origin"],
vec!["--push-option", "--dry-run"],
vec!["--repo", "-n"],
vec!["--exec", "-n"],
vec!["-on"],
vec!["origin", "--", "-n"],
] {
assert!(!region(values.as_slice()).dry_run, "{values:?}");
}
}
#[test]
fn reports_wrapper_flags_and_refusals() {
let parsed: PushRegion = parse_push_region(
os_arguments(&["--cli-git-keep-going", "-o", "--cli-git-keep-going"]).as_slice(),
&[b"--cli-git-keep-going"],
)
.expect("valid region");
assert_eq!(
parsed.wrapper,
vec![WrapperOccurrence { flag: 0, token: 0 }]
);
for (values, kind) in [
(vec!["--unknown"], OptionErrorKind::UnknownOption),
(vec!["-x"], OptionErrorKind::UnknownOption),
(vec!["--atomic=1"], OptionErrorKind::UnexpectedValue),
(vec!["--d"], OptionErrorKind::AmbiguousOption),
(vec!["-o"], OptionErrorKind::MissingValue),
(vec!["--no-ipv4"], OptionErrorKind::UnknownOption),
] {
assert_eq!(
parse_push_region(os_arguments(values.as_slice()).as_slice(), &[])
.expect_err("refused")
.kind,
kind,
"{values:?}"
);
}
}
#[test]
fn table_matches_git_push_completion_helper() {
let (directory, root): (PathBuf, PathBuf) = repository_with_tracked_file("push-table");
assert_table_invariants(PUSH_TABLE);
assert_eq!(
render_completion(PUSH_TABLE),
git_completion(root.as_path(), &["push"])
);
remove(directory.as_path());
}
fn remote_refs(remote: &Path) -> String {
return output_text(&git(remote, &["for-each-ref", "--format=%(refname)"]));
}
#[test]
fn abbreviation_cluster_and_value_readings_match_git() {
let (directory, root): (PathBuf, PathBuf) = repository_with_tracked_file("push-readings");
let remote: PathBuf = directory.join("remote.git");
git(
directory.as_path(),
&["init", "--quiet", "--bare", "remote.git"],
);
git(
remote.as_path(),
&["config", "receive.advertisePushOptions", "true"],
);
git(
root.as_path(),
&["push", "--quiet", "-nf", "../remote.git", "main"],
);
assert_eq!(remote_refs(remote.as_path()), "");
assert!(region(&["--quiet", "-nf", "../remote.git", "main"]).dry_run);
git(
root.as_path(),
&[
"push",
"--quiet",
"-o",
"-n",
"../remote.git",
"main:refs/heads/option",
],
);
assert_eq!(remote_refs(remote.as_path()), "refs/heads/option");
assert!(!region(&["--quiet", "-o", "-n", "../remote.git", "main"]).dry_run);
git(
root.as_path(),
&["push", "--quiet", "--at", "../remote.git", "main"],
);
assert!(remote_refs(remote.as_path()).contains("refs/heads/main"));
assert!(region(&["--quiet", "--at", "../remote.git", "main"]).atomic_stated);
let ambiguous: Output = git_status(root.as_path(), &["push", "--d", "../remote.git"]);
assert_eq!(ambiguous.status.code(), Some(129));
remove(directory.as_path());
}