openpencil/crates/op-git/src/tests.rs
Kayshen-X 2aacde0ce2 style: apply rustfmt to the workspace
cargo fmt --all -- --check was failing on CI after the recent
feature work landed unformatted (insert_<comp> MCP tools,
Component-Browser panel, Design-MD panel, op-i18n locale tables,
op-opmerge). Running cargo fmt --all touches 48 files; no behaviour
change.
2026-05-21 22:03:43 +08:00

91 lines
3.1 KiB
Rust

//! Integration tests — each runs against a throwaway repository
//! created with the real system `git`.
//!
//! `git` is a hard requirement of this crate, but the test harness
//! still guards on its presence so the suite is skipped (not failed)
//! on a machine without `git` installed.
//!
//! This module is the spine: it holds the shared test fixtures
//! (`TempRepo`, `clone_for_test`, the `git_available` guard) used by
//! the per-topic sibling test modules (`tests_repo`, `tests_merge`,
//! `tests_auth`). Each test file is kept under the 800-line cap.
#![cfg(test)]
use std::path::PathBuf;
use std::process::Command;
use crate::GitRepo;
/// Whether the system `git` executable is usable.
pub(crate) fn git_available() -> bool {
Command::new("git")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
/// Whether `ssh-keygen` is usable. `-?` is an unknown flag — it
/// prints usage and exits non-zero *without* reading stdin, so the
/// process simply running (an `Ok` output) proves availability.
pub(crate) fn ssh_keygen_available() -> bool {
Command::new("ssh-keygen").arg("-?").output().is_ok()
}
/// A unique temp directory path for one test.
pub(crate) fn unique_temp_dir(tag: &str) -> PathBuf {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
std::env::temp_dir().join(format!("op-git-test-{tag}-{}-{nanos}", std::process::id()))
}
/// A throwaway repository with a configured commit identity, removed
/// from disk when dropped.
pub(crate) struct TempRepo {
pub(crate) dir: PathBuf,
pub(crate) repo: GitRepo,
}
impl TempRepo {
/// Create a fresh initialized repo, or `None` when `git` is absent.
pub(crate) fn new(tag: &str) -> Option<Self> {
if !git_available() {
return None;
}
let dir = unique_temp_dir(tag);
let repo = GitRepo::init(&dir).expect("git init");
// A hermetic identity so `git commit` never depends on the
// host's global git config.
repo.run(&["config", "user.email", "test@openpencil.dev"])
.expect("set user.email");
repo.run(&["config", "user.name", "OP Test"])
.expect("set user.name");
Some(Self { dir, repo })
}
/// Write `content` to `name` in the working tree.
pub(crate) fn write(&self, name: &str, content: &str) {
std::fs::write(self.dir.join(name), content).expect("write file");
}
}
impl Drop for TempRepo {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.dir);
}
}
/// Clone the bare repo at `remote` into a fresh temp dir and give it
/// a hermetic commit identity. Returns the clone's dir + handle.
pub(crate) fn clone_for_test(remote: &std::path::Path, tag: &str) -> (PathBuf, GitRepo) {
let dir = unique_temp_dir(tag);
let repo = GitRepo::clone(remote.to_str().unwrap(), &dir).expect("clone");
repo.run(&["config", "user.email", "t@openpencil.dev"])
.unwrap();
repo.run(&["config", "user.name", "OP Test"]).unwrap();
(dir, repo)
}