use crate::peer::{converge, scan, seed};
use std::path::Path;
fn run(dir: &Path, args: &[&str]) {
let output = crate::git_backend::git_command()
.args(args)
.current_dir(dir)
.output()
.unwrap_or_else(|e| panic!("git {args:?}: {e}"));
assert!(
output.status.success(),
"git {args:?}: {}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn test9980_the_seed_matches_a_scan_of_the_committed_tree() {
let temp = tempfile::tempdir().expect("tempdir");
let dir = temp.path();
run(dir, &["init", "-q", "-b", "main"]);
run(dir, &["config", "user.name", "Test"]);
run(dir, &["config", "user.email", "test@example.com"]);
std::fs::create_dir_all(dir.join("src/deep")).expect("mkdir");
std::fs::write(dir.join("README.md"), "workspace\n").expect("write");
std::fs::write(dir.join("src/main.rs"), "fn main() {}\n").expect("write");
std::fs::write(dir.join("src/deep/nested.txt"), "deep\n").expect("write");
std::fs::write(dir.join("run.sh"), "#!/bin/sh\necho hi\n").expect("write");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(dir.join("run.sh"), std::fs::Permissions::from_mode(0o755))
.expect("chmod");
}
#[cfg(unix)]
std::os::unix::fs::symlink("src/main.rs", dir.join("link.rs")).expect("symlink");
run(dir, &["add", "."]);
run(dir, &["commit", "-qm", "one"]);
let seeded = seed::from_head(dir).expect("a seed");
let scanned = scan::read(dir, &scan::Policy::default()).expect("a scan");
assert_eq!(
seeded.keys().collect::<Vec<_>>(),
scanned.keys().collect::<Vec<_>>(),
"the seed and a scan of the same clean tree must cover the same paths"
);
for (path, entry) in &seeded {
let found = scanned.get(path).expect("the same path");
assert!(
entry.same_as(found),
"{path}: the seed says {entry:?} and the tree holds {found:?}"
);
}
#[cfg(unix)]
{
assert!(seeded["run.sh"].executable, "the executable bit is part of the seed");
assert_eq!(seeded["link.rs"].kind, converge::EntryKind::Symlink);
assert_eq!(
seeded["link.rs"].hash,
converge::hash_bytes(b"src/main.rs"),
"a link is seeded as its target text, like a scan reads it"
);
}
}
#[test]
fn test9981_uncommitted_work_is_not_agreed_and_not_seeded() {
let temp = tempfile::tempdir().expect("tempdir");
let dir = temp.path();
run(dir, &["init", "-q", "-b", "main"]);
run(dir, &["config", "user.name", "Test"]);
run(dir, &["config", "user.email", "test@example.com"]);
std::fs::write(dir.join("committed.txt"), "in the commit\n").expect("write");
run(dir, &["add", "."]);
run(dir, &["commit", "-qm", "one"]);
std::fs::write(dir.join("committed.txt"), "edited since\n").expect("write");
std::fs::write(dir.join("new.txt"), "never committed\n").expect("write");
let seeded = seed::from_head(dir).expect("a seed");
assert_eq!(
seeded["committed.txt"].hash,
converge::hash_bytes(b"in the commit\n"),
"the seed holds the committed content, not what is on disk now"
);
assert!(
!seeded.contains_key("new.txt"),
"an uncommitted file is not something both machines have agreed on"
);
let here = scan::read(dir, &scan::Policy::default()).expect("a scan");
let there = seeded.clone();
let plan = converge::plan(&here, &there, &seeded);
assert!(
plan.actions.iter().all(|action| !action.is_conflict()),
"a fresh relationship must not conflict on committed files: {:?}",
plan.actions
);
assert_eq!(plan.pending(), 2, "both the edit and the new file are carried");
}
#[test]
fn test9982_an_unborn_branch_seeds_an_empty_baseline() {
let temp = tempfile::tempdir().expect("tempdir");
let dir = temp.path();
run(dir, &["init", "-q", "-b", "main"]);
assert!(seed::from_head(dir).expect("a seed").is_empty());
}
#[test]
fn test9983_a_submodule_is_not_part_of_its_parents_seed() {
let temp = tempfile::tempdir().expect("tempdir");
let child = temp.path().join("child");
std::fs::create_dir_all(&child).expect("mkdir");
run(&child, &["init", "-q", "-b", "main"]);
run(&child, &["config", "user.name", "Test"]);
run(&child, &["config", "user.email", "test@example.com"]);
std::fs::write(child.join("inner.txt"), "child\n").expect("write");
run(&child, &["add", "."]);
run(&child, &["commit", "-qm", "child"]);
let parent = temp.path().join("parent");
std::fs::create_dir_all(&parent).expect("mkdir");
run(&parent, &["init", "-q", "-b", "main"]);
run(&parent, &["config", "user.name", "Test"]);
run(&parent, &["config", "user.email", "test@example.com"]);
std::fs::write(parent.join("top.txt"), "parent\n").expect("write");
run(&parent, &["add", "."]);
run(&parent, &["commit", "-qm", "parent"]);
run(
&parent,
&[
"-c",
"protocol.file.allow=always",
"submodule",
"add",
"-q",
child.to_str().expect("path"),
"child",
],
);
run(&parent, &["commit", "-qm", "add child"]);
let seeded = seed::from_head(&parent).expect("a seed");
assert!(seeded.contains_key("top.txt"));
assert!(
!seeded.keys().any(|path| path.starts_with("child/")),
"the submodule's files reached the superproject's baseline: {:?}",
seeded.keys().collect::<Vec<_>>()
);
}