mod support;
use std::fs;
use tempfile::TempDir;
use git2::Repository;
use thoughts_tool::git::pull::pull_ff_only;
use thoughts_tool::git::utils::is_worktree_dirty;
#[ignore = "integration test - run with: just test-integration"]
#[test]
fn fetch_and_fast_forward() {
let remote = TempDir::new().unwrap();
support::git_ok(remote.path(), &["init", "--bare", "."]);
let producer = TempDir::new().unwrap();
support::git_ok(producer.path(), &["init"]);
fs::write(producer.path().join("a.txt"), "one").unwrap();
support::git_ok(producer.path(), &["add", "."]);
support::git_ok(
producer.path(),
&[
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"commit",
"-m",
"init",
],
);
support::git_ok(producer.path(), &["branch", "-M", "main"]);
support::git_ok(
producer.path(),
&["remote", "add", "origin", remote.path().to_str().unwrap()],
);
support::git_ok(producer.path(), &["push", "-u", "origin", "main"]);
{
let bare_repo = Repository::open(remote.path()).expect("open bare remote");
bare_repo
.set_head("refs/heads/main")
.expect("set bare HEAD to main");
}
let consumer = TempDir::new().unwrap();
support::git_ok(
consumer.path(),
&["clone", remote.path().to_str().unwrap(), "work"],
);
fs::write(producer.path().join("b.txt"), "two").unwrap();
support::git_ok(producer.path(), &["add", "."]);
support::git_ok(
producer.path(),
&[
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"commit",
"-m",
"second",
],
);
support::git_ok(producer.path(), &["push"]);
let work = consumer.path().join("work");
pull_ff_only(&work, "origin", Some("main")).expect("fetch and ff should succeed");
assert!(work.join("b.txt").exists());
let content = fs::read_to_string(work.join("b.txt")).unwrap();
assert_eq!(content, "two");
let repo = Repository::open(&work).expect("open consumer repo");
assert!(
!is_worktree_dirty(&repo).expect("status check failed"),
"worktree should be clean after fast-forward"
);
let head_oid = repo.refname_to_id("HEAD").expect("HEAD oid");
let upstream_oid = repo
.refname_to_id("refs/remotes/origin/main")
.expect("upstream oid");
assert_eq!(
head_oid, upstream_oid,
"HEAD should match upstream after FF"
);
}
#[ignore = "integration test - run with: just test-integration"]
#[test]
fn fetch_already_up_to_date() {
let remote = TempDir::new().unwrap();
support::git_ok(remote.path(), &["init", "--bare", "."]);
let producer = TempDir::new().unwrap();
support::git_ok(producer.path(), &["init"]);
fs::write(producer.path().join("a.txt"), "one").unwrap();
support::git_ok(producer.path(), &["add", "."]);
support::git_ok(
producer.path(),
&[
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"commit",
"-m",
"init",
],
);
support::git_ok(producer.path(), &["branch", "-M", "main"]);
support::git_ok(
producer.path(),
&["remote", "add", "origin", remote.path().to_str().unwrap()],
);
support::git_ok(producer.path(), &["push", "-u", "origin", "main"]);
{
let bare_repo = Repository::open(remote.path()).expect("open bare remote");
bare_repo
.set_head("refs/heads/main")
.expect("set bare HEAD to main");
}
let consumer = TempDir::new().unwrap();
support::git_ok(
consumer.path(),
&["clone", remote.path().to_str().unwrap(), "work"],
);
let work = consumer.path().join("work");
pull_ff_only(&work, "origin", Some("main")).expect("pull should succeed when up to date");
let repo = Repository::open(&work).expect("open consumer repo");
assert!(
!is_worktree_dirty(&repo).expect("status check failed"),
"worktree should remain clean when already up to date"
);
}
#[ignore = "integration test - run with: just test-integration"]
#[test]
fn fetch_with_no_remote_is_ok() {
let repo = TempDir::new().unwrap();
support::git_ok(repo.path(), &["init"]);
fs::write(repo.path().join("a.txt"), "local").unwrap();
support::git_ok(repo.path(), &["add", "."]);
support::git_ok(
repo.path(),
&[
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"commit",
"-m",
"local",
],
);
pull_ff_only(repo.path(), "origin", Some("main")).expect("pull should succeed without remote");
}