use super::*;
use crate::test_support::{fixture, git, remove};
use std::path::{Path, PathBuf};
fn fixture_environment() -> Vec<(OsString, OsString)> {
return [
("PATH", "/usr/bin:/bin"),
("GIT_CONFIG_NOSYSTEM", "1"),
("GIT_CONFIG_GLOBAL", "/nonexistent-global-config"),
("GIT_AUTHOR_NAME", "Fixture"),
("GIT_AUTHOR_EMAIL", "fixture@example.invalid"),
("GIT_COMMITTER_NAME", "Fixture"),
("GIT_COMMITTER_EMAIL", "fixture@example.invalid"),
]
.iter()
.map(|(name, value)| {
return (OsString::from(name), OsString::from(value));
})
.collect();
}
fn git_for(root: &Path) -> PushGit {
return PushGit {
real_git: PathBuf::from("/usr/bin/git"),
cwd: root.to_path_buf(),
environment: fixture_environment(),
};
}
fn repository_with_unpublished_commit(name: &str) -> (PathBuf, String) {
let root = fixture(name);
let origin = root.join("origin.git");
let repo = root.join("repo");
git(
&root,
&["init", "--quiet", "--bare", origin.to_str().expect("utf-8")],
);
std::fs::create_dir_all(&repo).expect("repo");
git(&repo, &["init", "--quiet", "--initial-branch=main"]);
git(&repo, &["config", "user.email", "cli-git@example.invalid"]);
git(&repo, &["config", "user.name", "cli-git fixture"]);
git(
&repo,
&["commit", "--quiet", "--allow-empty", "--message=base"],
);
git(
&repo,
&["remote", "add", "origin", origin.to_str().expect("utf-8")],
);
git(
&repo,
&["push", "--quiet", "origin", "HEAD:refs/heads/main"],
);
std::fs::write(repo.join("new.txt"), "new content\n").expect("new file");
git(&repo, &["add", "new.txt"]);
git(&repo, &["commit", "--quiet", "-m", "new"]);
let tip = String::from_utf8_lossy(&git(&repo, &["rev-parse", "HEAD"]).stdout)
.trim()
.to_owned();
return (repo, tip);
}
#[test]
fn the_pushed_scope_lists_each_commit_once() {
let first = parse_object_id("a".repeat(40).as_bytes()).expect("object name");
let scopes = vec![
UpdateScope::Commits(vec!["a".repeat(40)]),
UpdateScope::None,
UpdateScope::Commits(vec!["a".repeat(40)]),
];
let scope = pushed_scope(&scopes).expect("scope");
assert_eq!(scope.commits, vec![first]);
assert!(scope.trees.is_empty());
}
#[test]
fn the_pushed_scope_lists_each_final_tree_once() {
let tree = parse_object_id("b".repeat(40).as_bytes()).expect("object name");
let scopes = vec![
UpdateScope::FinalTree("b".repeat(40)),
UpdateScope::FinalTree("b".repeat(40)),
];
let scope = pushed_scope(&scopes).expect("scope");
assert_eq!(scope.trees, vec![tree]);
assert!(scope.commits.is_empty());
}
#[test]
fn a_push_of_an_unpublished_commit_scans_that_commit() {
let (repo, tip) = repository_with_unpublished_commit("mp-lifecycle-scope");
let scope = manual_push_scope(
&git_for(&repo),
&[],
&[OsString::from("origin"), OsString::from("main")],
)
.expect("scope");
let expected = parse_object_id(tip.as_bytes()).expect("object name");
assert_eq!(scope.commits, vec![expected]);
remove(repo.parent().expect("root"));
}
#[test]
fn an_unreachable_destination_fails_the_scope() {
let (repo, _tip) = repository_with_unpublished_commit("mp-lifecycle-unreachable");
let missing = repo.parent().expect("root").join("missing.git");
let result = manual_push_scope(
&git_for(&repo),
&[],
&[
OsString::from(missing.to_str().expect("utf-8")),
OsString::from("main"),
],
);
assert!(result.is_err());
remove(repo.parent().expect("root"));
}