git-ents.gitmain
⌘K
foforge
commit b9ab22c
refactor: share the git test fixtures through git-store test-support

The tempdir-plus-init repo fixture, commit_all, head, and git_with_stdin each lived as verbatim copies across the workspace’s test modules; downstream crates now enable one copy from their dev-dependencies.

feat: add a test-support feature to git-store with shared fixtures Assisted-by: Claude:claude-fable-5

Joseph D. Carpinelli · 1 month ago

Reviews

No reviews of this commit yet — record a verdict below.

Start a review

verdict

Cargo.lock @@ -1248,8 +1248,8 @@ version = "0.0.0" dependencies = [ "facet", + "git-store", "gix", - "tempfile", "thiserror 2.0.18", ] @@ -1260,7 +1260,6 @@ "facet", "git-anchor", "git-store", - "tempfile", ] [[package]]
crates/git-anchor/Cargo.toml @@ -11,7 +11,7 @@ thiserror = { workspace = true } [dev-dependencies] -tempfile = { workspace = true } +git-store = { workspace = true, features = ["test-support"] } [lints] workspace = true
crates/git-comment/Cargo.toml @@ -11,7 +11,7 @@ git-store = { workspace = true } [dev-dependencies] -tempfile = { workspace = true } +git-store = { workspace = true, features = ["test-support"] } [lints] workspace = true
crates/git-ents/Cargo.toml @@ -21,5 +21,8 @@ tokio-tungstenite = { version = "0.29.0", features = ["rustls-tls-webpki-roots"] } ureq = "3.3.0" +[dev-dependencies] +git-store = { workspace = true, features = ["test-support"] } + [lints] workspace = true
crates/git-store/Cargo.toml @@ -9,10 +9,16 @@ facet = { workspace = true } facet-git-tree = { workspace = true } gix = { workspace = true } +tempfile = { workspace = true, optional = true } thiserror = { workspace = true } [dev-dependencies] tempfile = { workspace = true } +[features] +# Shared git test fixtures for the workspace's test suites; enable from a +# downstream crate's dev-dependencies. +test-support = ["dep:tempfile"] + [lints] workspace = true
crates/git-anchor/src/lib.rs @@ -364,60 +364,10 @@ reason = "unit test" )] - use std::path::Path; - use std::process::Command; + use git_store::test_support::{commit_all, head, repo}; use super::*; - fn repo() -> tempfile::TempDir { - let dir = tempfile::tempdir().unwrap(); - let status = Command::new("git") - .arg("-C") - .arg(dir.path()) - .args(["init", "-q"]) - .status() - .unwrap(); - assert!(status.success()); - dir - } - - fn commit_all(dir: &Path, message: &str) { - let status = Command::new("git") - .arg("-C") - .arg(dir) - .args(["add", "-A"]) - .status() - .unwrap(); - assert!(status.success()); - let status = Command::new("git") - .arg("-C") - .arg(dir) - .args([ - "-c", - "user.name=test", - "-c", - "user.email=test@example.com", - "commit", - "-q", - "-m", - message, - ]) - .status() - .unwrap(); - assert!(status.success()); - } - - fn head(dir: &Path) -> String { - let output = Command::new("git") - .arg("-C") - .arg(dir) - .args(["rev-parse", "HEAD"]) - .output() - .unwrap(); - assert!(output.status.success()); - String::from_utf8(output.stdout).unwrap().trim().to_owned() - } - fn numbered(range: std::ops::RangeInclusive<u32>) -> String { range.map(|n| format!("line {n}\n")).collect() }
crates/git-comment/src/lib.rs @@ -107,25 +107,13 @@ reason = "unit test" )] - use std::io::Write as _; - use std::process::{Command, Stdio}; + use std::process::Command; use git_anchor::LineRange; + use git_store::test_support::{commit_all, git_with_stdin, repo}; use super::*; - fn repo() -> tempfile::TempDir { - let dir = tempfile::tempdir().unwrap(); - let status = Command::new("git") - .arg("-C") - .arg(dir.path()) - .args(["init", "-q"]) - .status() - .unwrap(); - assert!(status.success()); - dir - } - fn comment(body: &str, issue: Option<&str>) -> Comment { Comment { body: body.to_owned(), @@ -207,29 +195,7 @@ fn a_stored_comment_projects_onto_the_commit_it_was_written_against() { let dir = repo(); std::fs::write(dir.path().join("file.txt"), "one\ntwo\nthree\n").unwrap(); - let status = Command::new("git") - .arg("-C") - .arg(dir.path()) - .args(["add", "-A"]) - .status() - .unwrap(); - assert!(status.success()); - let status = Command::new("git") - .arg("-C") - .arg(dir.path()) - .args([ - "-c", - "user.name=test", - "-c", - "user.email=test@example.com", - "commit", - "-q", - "-m", - "one", - ]) - .status() - .unwrap(); - assert!(status.success()); + commit_all(dir.path(), "one"); let anchor = git_anchor::capture( dir.path(), @@ -257,28 +223,6 @@ ); } - /// Run a git plumbing command in `repo` with `input` on stdin, returning - /// its trimmed stdout. - fn git_with_stdin(repo: &Path, args: &[&str], input: &str) -> String { - let mut child = Command::new("git") - .arg("-C") - .arg(repo) - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - child - .stdin - .as_mut() - .unwrap() - .write_all(input.as_bytes()) - .unwrap(); - let output = child.wait_with_output().unwrap(); - assert!(output.status.success()); - String::from_utf8(output.stdout).unwrap().trim().to_owned() - } - #[test] fn loads_the_on_disk_comment_format() { // A fixture written as the real on-disk layout — a `body` blob, an
crates/git-ents/src/testutil.rs @@ -14,9 +14,8 @@ reason = "test support" )] -use std::io::Write as _; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Command; use std::sync::atomic::{AtomicUsize, Ordering}; /// A freshly initialized, uniquely named git repository under the temp dir. @@ -377,21 +376,5 @@ /// Run git in `repo` with `input` on stdin, returning its trimmed stdout. fn git_with_stdin(repo: &Path, args: &[&str], input: &str) -> String { - let mut child = Command::new("git") - .arg("-C") - .arg(repo) - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - child - .stdin - .take() - .unwrap() - .write_all(input.as_bytes()) - .unwrap(); - let output = child.wait_with_output().unwrap(); - assert!(output.status.success(), "git {args:?} failed"); - String::from_utf8(output.stdout).unwrap().trim().to_owned() + git_store::test_support::git_with_stdin(repo, args, input) }
crates/git-store/src/lib.rs @@ -574,20 +574,22 @@ author: Authorship, } -#[cfg(test)] -mod tests { - #![allow( - clippy::unwrap_used, - clippy::let_underscore_must_use, - reason = "unit test" - )] +/// Shared git test fixtures: a throwaway repository and the plumbing helpers +/// the workspace's test suites drive it with, kept here once instead of as a +/// copy per crate. Compiled for this crate's own tests and under the +/// `test-support` feature, which downstream crates enable from their +/// dev-dependencies. +#[cfg(any(test, feature = "test-support"))] +pub mod test_support { + #![allow(clippy::unwrap_used, reason = "test fixture")] - use std::collections::BTreeMap; - use std::process::Command; + use std::io::Write as _; + use std::path::Path; + use std::process::{Command, Stdio}; - use super::*; - - fn repo() -> tempfile::TempDir { + /// A fresh temporary directory holding an initialized git repository. + #[must_use] + pub fn repo() -> tempfile::TempDir { let dir = tempfile::tempdir().unwrap(); let status = Command::new("git") .arg("-C") @@ -599,6 +601,83 @@ dir } + /// Stage everything in `dir` and commit it as `message` under the fixed + /// test identity. + pub fn commit_all(dir: &Path, message: &str) { + let status = Command::new("git") + .arg("-C") + .arg(dir) + .args(["add", "-A"]) + .status() + .unwrap(); + assert!(status.success()); + let status = Command::new("git") + .arg("-C") + .arg(dir) + .args([ + "-c", + "user.name=test", + "-c", + "user.email=test@example.com", + "commit", + "-q", + "-m", + message, + ]) + .status() + .unwrap(); + assert!(status.success()); + } + + /// The full hex id of `dir`'s `HEAD` commit. + #[must_use] + pub fn head(dir: &Path) -> String { + let output = Command::new("git") + .arg("-C") + .arg(dir) + .args(["rev-parse", "HEAD"]) + .output() + .unwrap(); + assert!(output.status.success()); + String::from_utf8(output.stdout).unwrap().trim().to_owned() + } + + /// Run git in `repo` with `input` on stdin, returning its trimmed stdout. + #[must_use] + pub fn git_with_stdin(repo: &Path, args: &[&str], input: &str) -> String { + let mut child = Command::new("git") + .arg("-C") + .arg(repo) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + child + .stdin + .take() + .unwrap() + .write_all(input.as_bytes()) + .unwrap(); + let output = child.wait_with_output().unwrap(); + assert!(output.status.success(), "git {args:?} failed"); + String::from_utf8(output.stdout).unwrap().trim().to_owned() + } +} + +#[cfg(test)] +mod tests { + #![allow( + clippy::unwrap_used, + clippy::let_underscore_must_use, + reason = "unit test" + )] + + use std::collections::BTreeMap; + + use super::*; + use crate::test_support::repo; + fn entries(pairs: &[(&str, &str)]) -> BTreeMap<String, String> { pairs .iter()