use std::path::Path;
use std::process::Command;
use sley::{EntryKind, ObjectId, Repository};
fn run_git(cwd: &Path, args: &[&str]) -> Option<String> {
let output = Command::new("git")
.args(args)
.current_dir(cwd)
.output()
.ok()?;
if !output.status.success() {
return None;
}
String::from_utf8(output.stdout).ok()
}
#[test]
fn tree_builder_matches_git_write_tree() {
let tmp = std::env::temp_dir().join(format!("sley-tree-editor-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&tmp);
std::fs::create_dir_all(&tmp).expect("test operation should succeed");
if run_git(&tmp, &["--version"]).is_none() {
let _ = std::fs::remove_dir_all(&tmp);
return;
}
assert!(run_git(&tmp, &["init", "-q", "-b", "main"]).is_some());
std::fs::write(tmp.join("a.txt"), b"alpha\n").expect("test operation should succeed");
std::fs::write(tmp.join("foo.txt"), b"foo file\n").expect("test operation should succeed");
let run = tmp.join("run.sh");
std::fs::write(&run, b"#!/bin/sh\necho hi\n").expect("test operation should succeed");
std::fs::create_dir_all(tmp.join("foo")).expect("test operation should succeed");
std::fs::write(tmp.join("foo/bar.txt"), b"bar\n").expect("test operation should succeed");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&run, std::fs::Permissions::from_mode(0o755))
.expect("test operation should succeed");
std::os::unix::fs::symlink("a.txt", tmp.join("link"))
.expect("test operation should succeed");
}
assert!(run_git(&tmp, &["add", "-A"]).is_some());
let expected = run_git(&tmp, &["write-tree"])
.expect("test operation should succeed")
.trim()
.to_string();
let listing = run_git(&tmp, &["ls-tree", &expected]).expect("test operation should succeed");
let mut entries: Vec<(u32, ObjectId, Vec<u8>)> = Vec::new();
for line in listing.lines() {
let (meta, name) = line.split_once('\t').expect("ls-tree line has a tab");
let mut fields = meta.split_whitespace();
let mode = u32::from_str_radix(fields.next().expect("test operation should succeed"), 8)
.expect("test operation should succeed");
let _type = fields.next().expect("test operation should succeed");
let oid: ObjectId = fields
.next()
.expect("test operation should succeed")
.parse()
.expect("test operation should succeed");
entries.push((mode, oid, name.as_bytes().to_vec()));
}
assert!(entries.len() >= 3, "expected several top-level entries");
let repo = Repository::discover(&tmp).expect("test operation should succeed");
let mut builder = repo
.edit_tree(&ObjectId::empty_tree(repo.object_format()))
.expect("test operation should succeed");
for (mode, oid, name) in entries.into_iter().rev() {
match EntryKind::from_mode(mode) {
Some(kind) => builder.upsert(name, kind, oid),
None => builder.upsert_raw(name, mode, oid),
}
}
let got = repo
.write_tree(builder)
.expect("test operation should succeed");
assert_eq!(
got.to_string(),
expected,
"tree OID must be byte-identical to `git write-tree`"
);
assert!(
!repo
.read_tree(&got)
.expect("test operation should succeed")
.entries
.is_empty()
);
let _ = std::fs::remove_dir_all(&tmp);
}