use super::*;
use crate::repo_read_layout::read_layout_in;
use crate::test_support::{fixture, git, git_output, isolated_overlay, remove};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
fn oid(n: u8) -> String {
return format!("{n:02x}").repeat(32);
}
fn commit(repo: &Path, files: &[(&str, String)], message: &str) -> String {
for (path, text) in files {
let target: PathBuf = repo.join(path);
std::fs::create_dir_all(target.parent().expect("a parent")).expect("directories");
std::fs::write(target, text).expect("file");
}
git(repo, &["add", "--all"]);
git(repo, &["commit", "--quiet", "--allow-empty", &format!("--message={message}")]);
return String::from_utf8(git_output(repo, &["rev-parse", "HEAD"]).stdout).expect("UTF-8").trim().to_owned();
}
fn pointer(n: u8) -> String {
return format!("version https://git-lfs.github.com/spec/v1\noid sha256:{}\nsize 10\n", oid(n));
}
fn store(repo: &Path, n: u8) {
let name: String = oid(n);
let directory: PathBuf = repo.join(".git/lfs/objects").join(&name[..2]).join(&name[2..4]);
std::fs::create_dir_all(&directory).expect("storage");
std::fs::write(directory.join(&name), b"0123456789").expect("object");
}
fn world(root: &Path) -> (PathBuf, String, String, String) {
let repo: PathBuf = root.join("repo");
std::fs::create_dir(&repo).expect("dir");
git(repo.as_path(), &["init", "--quiet", "--initial-branch=main"]);
store(repo.as_path(), 1);
let known: String = commit(repo.as_path(), &[("assets/one.bin", pointer(1))], "known");
git(repo.as_path(), &["update-ref", "refs/remotes/origin/main", known.as_str()]);
let tip: String = commit(repo.as_path(), &[("docs/readme.txt", String::from("text\n"))], "plain");
git(repo.as_path(), &["checkout", "--quiet", "-b", "feature"]);
let with_pointer: String = commit(repo.as_path(), &[("assets/two.bin", pointer(2))], "pointer");
git(repo.as_path(), &["checkout", "--quiet", "main"]);
return (repo, known, tip, with_pointer);
}
fn plan(refs: &[&str], full_scan: bool, everything: bool) -> UploadPlan {
return UploadPlan {
remotes: vec![OsString::from("origin")],
refs: refs.iter().map(OsString::from).collect(),
everything,
submodules: false,
full_scan,
objects: None,
};
}
fn narrow(repo: &Path, plan: UploadPlan) -> Option<UploadPlan> {
let layout = read_layout_in(repo, isolated_overlay().as_slice());
return narrow_plan(plan, layout.as_ref());
}
#[test]
fn a_push_that_adds_no_pointer_uploads_nothing() {
let root = fixture("lfs-object-plan-none");
let (repo, _known, _tip, _with_pointer) = world(root.as_path());
assert_eq!(narrow(repo.as_path(), plan(&["main"], false, false)), None);
assert_eq!(narrow(repo.as_path(), plan(&["refs/heads/main"], false, false)), None, "a full ref name reads the same");
assert_eq!(narrow(repo.as_path(), plan(&["HEAD"], false, false)), None, "and so does HEAD");
remove(root.as_path());
}
#[test]
fn a_push_that_adds_one_pointer_names_that_object() {
let root = fixture("lfs-object-plan-one");
let (repo, _known, _tip, _with_pointer) = world(root.as_path());
store(repo.as_path(), 2);
let narrowed: UploadPlan = narrow(repo.as_path(), plan(&["feature"], false, false)).expect("something to upload");
assert_eq!(narrowed.objects, Some(vec![oid(2)]));
let runs = narrowed.runs(std::ffi::OsStr::new("origin"));
let expected: Vec<OsString> = ["push", "--object-id", "origin", oid(2).as_str()].iter().map(OsString::from).collect();
assert_eq!(runs, vec![expected]);
remove(root.as_path());
}
#[test]
fn an_untrusted_destination_scans_the_whole_history() {
let root = fixture("lfs-object-plan-full");
let (repo, _known, _tip, _with_pointer) = world(root.as_path());
store(repo.as_path(), 2);
let narrowed: UploadPlan = narrow(repo.as_path(), plan(&["feature"], true, false)).expect("something to upload");
assert_eq!(narrowed.objects, Some(vec![oid(1), oid(2)]));
let mirrored: UploadPlan = narrow(repo.as_path(), plan(&[], true, true)).expect("something to upload");
assert_eq!(mirrored.objects, Some(vec![oid(1), oid(2)]), "a mirror push reads every ref");
remove(root.as_path());
}
#[test]
fn a_pointer_without_its_local_object_is_left_to_git_lfs() {
let root = fixture("lfs-object-plan-missing");
let (repo, _known, _tip, _with_pointer) = world(root.as_path());
let original: UploadPlan = plan(&["feature"], false, false);
assert_eq!(narrow(repo.as_path(), original.clone()), Some(original));
remove(root.as_path());
}
#[test]
fn what_the_readers_decline_leaves_the_plan_to_git_lfs() {
let root = fixture("lfs-object-plan-decline");
let (repo, _known, _tip, _with_pointer) = world(root.as_path());
for refs in [vec!["nosuchref"], vec!["main~1"], vec!["main^{tree}"], vec!["feature", "nosuchref"]] {
let original: UploadPlan = plan(&refs, false, false);
assert_eq!(narrow(repo.as_path(), original.clone()), Some(original), "{refs:?}");
}
let original: UploadPlan = plan(&["feature"], false, false);
assert_eq!(narrow_plan(original.clone(), None), Some(original), "no layout");
remove(root.as_path());
}