#![cfg(unix)]
use super::support::{Fixture, Observed, REAL_GIT, bounded, direct, executable, fixture, observe, remove, wrapped};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn banner(real_git: &Path) -> String {
return format!("monochromatic-git-policy-cli {VERSION}, shadowing git at {}\n", real_git.display());
}
fn help_section(real_git: &Path) -> String {
return format!(
"\nmonochromatic-git-policy-cli {VERSION} sits in front of this git\n\
It adds repository policies on commit, push and worktree commands,\n\
the `git cli-git` management command (`git cli-git --help`),\n\
and `git cli-git doctor`, which lists the traditional hooks a repository holds.\n\
real git: {}\n",
real_git.display()
);
}
fn answers(fixture: &Fixture, arguments: &[&str]) -> (Observed, Observed) {
let through_wrapper: Observed = observe(wrapped(fixture).current_dir(&fixture.root).args(arguments), b"");
let through_git: Observed = observe(direct(fixture).current_dir(&fixture.root).args(arguments), b"");
return (through_wrapper, through_git);
}
#[test]
fn version_spellings_add_one_banner_line() {
let fixture: Fixture = fixture("announce-version");
let banner_line: String = banner(Path::new(REAL_GIT));
for arguments in [
vec!["--version"],
vec!["-v"],
vec!["-C", "/", "--version"],
vec!["--no-pager", "-c", "user.name=x", "-v"],
] {
let (through_wrapper, through_git) = answers(&fixture, arguments.as_slice());
assert_eq!(through_git.code, Some(0), "{arguments:?}");
let mut expected: Vec<u8> = through_git.stdout.clone();
expected.extend_from_slice(banner_line.as_bytes());
assert_eq!(through_wrapper.stdout, expected, "{arguments:?}");
assert_eq!(through_wrapper.stderr, through_git.stderr, "{arguments:?}");
assert_eq!(through_wrapper.code, Some(0), "{arguments:?}");
}
remove(&fixture);
}
#[test]
fn help_spellings_add_the_section() {
let fixture: Fixture = fixture("announce-help");
let section: String = help_section(Path::new(REAL_GIT));
for arguments in [vec!["--help"], vec!["-h"], vec!["-C", "/", "-h"]] {
let (through_wrapper, through_git) = answers(&fixture, arguments.as_slice());
assert_eq!(through_git.code, Some(0), "{arguments:?}");
assert!(!through_git.stdout.is_empty(), "{arguments:?}");
let mut expected: Vec<u8> = through_git.stdout.clone();
expected.extend_from_slice(section.as_bytes());
assert_eq!(through_wrapper.stdout, expected, "{arguments:?}");
assert_eq!(through_wrapper.stderr, through_git.stderr, "{arguments:?}");
assert_eq!(through_wrapper.code, Some(0), "{arguments:?}");
}
remove(&fixture);
}
fn through_stand_in(fixture: &Fixture, arguments: &[&str], status: u8) -> (Observed, PathBuf) {
std::fs::create_dir(fixture.root.join("probe")).expect("probe directory");
let probe: PathBuf = fixture.root.join("probe/git");
executable(
probe.as_path(),
format!("#!/bin/sh\necho probe-out\necho probe-err >&2\nexit {status}\n").as_bytes(),
);
let mut path: OsString = fixture.root.join("bin").into_os_string();
path.push(":");
path.push(fixture.root.join("probe"));
let observed: Observed =
observe(bounded(fixture, fixture.root.join("bin/git").as_path(), path.as_os_str()).args(arguments), b"");
return (observed, probe);
}
#[test]
fn a_failing_git_prints_nothing_extra() {
for (name, arguments) in [
("announce-failing-version", vec!["--version"]),
("announce-failing-short", vec!["-v"]),
("announce-failing-help", vec!["--help"]),
("announce-failing-short-help", vec!["-h"]),
] {
let fixture: Fixture = fixture(name);
let (observed, _probe): (Observed, PathBuf) = through_stand_in(&fixture, arguments.as_slice(), 3);
assert_eq!(observed.stdout, b"probe-out\n", "{arguments:?}");
assert_eq!(observed.stderr, b"probe-err\n", "{arguments:?}");
assert_eq!(observed.code, Some(3), "{arguments:?}");
remove(&fixture);
}
}
#[test]
fn a_succeeding_stand_in_gets_the_text_naming_its_path() {
for (name, arguments, version) in [
("announce-stand-in-version", vec!["--version"], true),
("announce-stand-in-help", vec!["-h"], false),
] {
let fixture: Fixture = fixture(name);
let (observed, probe): (Observed, PathBuf) = through_stand_in(&fixture, arguments.as_slice(), 0);
let mut expected: String = String::from("probe-out\n");
expected.push_str(
if version { banner(probe.as_path()) } else { help_section(probe.as_path()) }.as_str(),
);
assert_eq!(String::from_utf8_lossy(&observed.stdout), expected, "{arguments:?}");
assert_eq!(observed.stderr, b"probe-err\n", "{arguments:?}");
assert_eq!(observed.code, Some(0), "{arguments:?}");
remove(&fixture);
}
}
#[test]
fn subcommand_help_stays_exact() {
let fixture: Fixture = fixture("announce-subcommand");
for arguments in [vec!["help", "--no-such-option"], vec!["version"]] {
let (through_wrapper, through_git) = answers(&fixture, arguments.as_slice());
assert_eq!(through_wrapper, through_git, "{arguments:?}");
}
remove(&fixture);
}