use super::*;
use crate::repo_read_config_scan::ScopeEnvironment;
use crate::repo_read_layout::read_layout_with;
use crate::test_support::{REAL_GIT, fixture, git_output, remove, repository};
use std::cell::Cell;
fn copy_git(root: &Path, name: &str) -> PathBuf {
let target: PathBuf = root.join(name);
std::fs::copy(REAL_GIT, &target).expect("fixture");
return target;
}
fn printed_by_git() -> PathBuf {
let output = std::process::Command::new(REAL_GIT).args(["var", "GIT_CONFIG_SYSTEM"]).env_clear().output().expect("git var");
assert!(output.status.success());
return parse_path_line(output.stdout.as_slice()).expect("an absolute path");
}
#[test]
fn the_learned_path_equals_what_git_prints_and_is_asked_once() {
let root = fixture("system-config-learned");
let git_copy = copy_git(root.as_path(), "git");
let cache = root.join("xdg").join("cli-git");
let starts: Cell<usize> = Cell::new(0);
let counting = |path: &Path| -> Option<Vec<u8>> {
starts.set(starts.get() + 1);
return ask_git(path);
};
let first = system_config_of(git_copy.as_path(), Some(cache.as_path()), &counting);
assert_eq!(first, Some(printed_by_git()));
assert_eq!(starts.get(), 1);
assert_eq!(system_config_of(git_copy.as_path(), Some(cache.as_path()), &counting), first);
assert_eq!(starts.get(), 1, "the second read must come from the cache");
remove(root.as_path());
}
#[test]
fn a_replaced_executable_is_asked_again_and_another_prefix_is_believed() {
let root = fixture("system-config-replaced");
let git_copy = copy_git(root.as_path(), "git");
let cache = root.join("xdg").join("cli-git");
let elsewhere = root.join("opt").join("etc").join("gitconfig");
let from_prefix = |_: &Path| -> Option<Vec<u8>> { return Some(format!("{}\n", elsewhere.display()).into_bytes()); };
assert_eq!(system_config_of(git_copy.as_path(), Some(cache.as_path()), &from_prefix), Some(elsewhere.clone()));
let mut bytes = std::fs::read(&git_copy).expect("read");
bytes.push(0);
std::fs::write(&git_copy, bytes).expect("rewrite");
let asked: Cell<bool> = Cell::new(false);
let host = |path: &Path| -> Option<Vec<u8>> {
asked.set(true);
return ask_git(path);
};
assert_eq!(system_config_of(git_copy.as_path(), Some(cache.as_path()), &host), Some(printed_by_git()));
assert!(asked.get(), "the stale entry must not be trusted");
remove(root.as_path());
}
#[test]
fn unknown_answers_are_none() {
for refused in ["", "\n", "relative/gitconfig\n", "/two\n/lines\n", "/no/newline", "/nul\0byte\n"] {
assert_eq!(parse_path_line(refused.as_bytes()), None, "{refused:?}");
}
let root = fixture("system-config-unknown");
let script = root.join("git");
std::fs::write(&script, "#!/bin/sh\n").expect("script");
let never = |_: &Path| -> Option<Vec<u8>> { panic!("a script has no identity, so Git is never asked"); };
assert_eq!(system_config_of(script.as_path(), None, &never), None);
let git_copy = copy_git(root.as_path(), "named-git");
let failing = |_: &Path| -> Option<Vec<u8>> { return None; };
assert_eq!(system_config_of(git_copy.as_path(), None, &failing), None);
let named = copy_git(root.as_path(), "git-dir");
let subdirectory = root.join("bin");
std::fs::create_dir(&subdirectory).expect("directory");
std::fs::rename(&named, subdirectory.join("git")).expect("move");
assert_eq!(system_config_of(subdirectory.join("git").as_path(), None, &failing), None);
remove(root.as_path());
}
#[test]
fn the_scope_reads_the_file_the_git_names() {
let root = fixture("system-config-scope");
let git_copy = copy_git(root.as_path(), "git");
let variables: Vec<(OsString, OsString)> = vec![
(OsString::from(FORWARD_TARGET_VARIABLE), git_copy.clone().into_os_string()),
(OsString::from("XDG_CACHE_HOME"), root.join("cache").into_os_string()),
(OsString::from("HOME"), root.join("home").into_os_string()),
];
let scope = ScopeEnvironment::from_variables(variables.as_slice());
assert_eq!(scope.system_default, Some(printed_by_git()));
assert!(!scope.unresolvable);
assert_eq!(scope.labelled_files().first().map(|(label, file)| { return (*label, file.clone()); }), Some(("system", printed_by_git())));
let unknown = ScopeEnvironment::from_variables(&[(OsString::from("HOME"), root.join("home").into_os_string())]);
assert!(unknown.unresolvable);
let removed = ScopeEnvironment::from_variables(&[(OsString::from("GIT_CONFIG_NOSYSTEM"), OsString::from("1"))]);
assert!(!removed.unresolvable);
let replaced = ScopeEnvironment::from_variables(&[(OsString::from("GIT_CONFIG_SYSTEM"), OsString::from("/replaced"))]);
assert!(!replaced.unresolvable);
remove(root.as_path());
}
#[test]
fn a_system_file_outside_etc_is_the_one_the_readers_check() {
let root = fixture("system-config-outside-etc");
let repo = repository(root.as_path(), "repo");
let system = root.join("opt").join("etc").join("gitconfig");
std::fs::create_dir_all(system.parent().expect("parent")).expect("directories");
let scope = ScopeEnvironment {
home: Some(root.join("no-home")),
system_default: Some(system.clone()),
global: Some(PathBuf::from("/nonexistent-global-config")),
..ScopeEnvironment::default()
};
std::fs::write(&system, "[core]\n\tbare = true\n").expect("system");
assert!(read_layout_with(repo.as_path(), &[], &scope).is_none(), "a system file that sets core.bare must be declined");
std::fs::write(&system, "[user]\n\tname = Someone\n").expect("system");
assert!(read_layout_with(repo.as_path(), &[], &scope).is_some(), "a plain system file is answered");
let real = git_output(repo.as_path(), &["rev-parse", "--git-dir"]);
assert!(real.status.success());
remove(root.as_path());
}