use std::ffi::OsStr;
use std::path::Path;
use std::process::{Command, Output};
#[allow(dead_code)]
pub mod event_signature_fixtures;
#[allow(dead_code)]
pub mod git_repo;
#[allow(dead_code)]
pub mod inspect;
#[allow(dead_code)]
pub mod snapshots;
#[allow(dead_code)]
pub fn pointbreak<I, S>(args: I) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
Command::new(env!("CARGO_BIN_EXE_pointbreak"))
.args(args)
.env_remove("POINTBREAK_LOG")
.env_remove("RUST_LOG")
.env_remove("POINTBREAK_FORMAT")
.env_remove("NO_COLOR")
.env_remove("CLICOLOR_FORCE")
.env_remove("POINTBREAK_THEME")
.env_remove("BAT_THEME")
.output()
.expect("run pointbreak binary")
}
#[allow(dead_code)]
pub fn pointbreak_env<I, S>(args: I, env: &[(&str, &str)]) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let mut command = Command::new(env!("CARGO_BIN_EXE_pointbreak"));
command
.args(args)
.env_remove("POINTBREAK_LOG")
.env_remove("RUST_LOG")
.env_remove("POINTBREAK_FORMAT")
.env_remove("POINTBREAK_THEME")
.env_remove("BAT_THEME");
for (key, value) in env {
command.env(key, value);
}
command.output().expect("run pointbreak binary")
}
#[allow(dead_code)]
pub fn dump_repo() -> git_repo::GitRepo {
let repo = git_repo::GitRepo::new();
repo.write("src/lib.rs", "pub fn value() -> u32 { 1 }\n");
repo.commit_all("base");
repo.write("src/lib.rs", "pub fn value() -> u32 { 2 }\n");
repo
}
#[allow(dead_code)]
pub fn superseded_dump_repo() -> (git_repo::GitRepo, String, String) {
let repo = dump_repo();
let repo_arg = repo.path().to_str().expect("temporary path is utf-8");
let first: serde_json::Value =
serde_json::from_slice(&pointbreak(["capture", "--repo", repo_arg]).stdout)
.expect("first capture emits JSON");
let first_id = first["revision"]["id"]
.as_str()
.expect("first revision id")
.to_owned();
repo.write("src/lib.rs", "pub fn value() -> u32 { 3 }\n");
let second: serde_json::Value = serde_json::from_slice(
&pointbreak(["capture", "--repo", repo_arg, "--supersedes", &first_id]).stdout,
)
.expect("second capture emits JSON");
let second_id = second["revision"]["id"]
.as_str()
.expect("second revision id")
.to_owned();
(repo, first_id, second_id)
}
#[allow(dead_code)]
pub fn committed_repo() -> git_repo::GitRepo {
let repo = git_repo::GitRepo::new();
repo.write("src/lib.rs", "pub fn value() -> u32 { 1 }\n");
repo.commit_all("base");
repo.write("src/lib.rs", "pub fn value() -> u32 { 2 }\n");
repo.commit_all("change");
repo
}
#[allow(dead_code)]
pub fn common_dir_store(repo_root: &Path) -> std::path::PathBuf {
let output = Command::new("git")
.args(["rev-parse", "--path-format=absolute", "--git-common-dir"])
.current_dir(repo_root)
.output()
.expect("run git rev-parse --git-common-dir");
assert!(
output.status.success(),
"git rev-parse --git-common-dir failed in {}",
repo_root.display()
);
let common_dir = String::from_utf8(output.stdout)
.expect("git-common-dir is utf-8")
.trim()
.to_owned();
Path::new(&common_dir).join("pointbreak")
}
#[allow(dead_code)]
pub fn append_provenance_free_revision(
repo_root: &Path,
object_id: &str,
object_artifact_content_hash: &str,
) -> String {
use pointbreak::model::{
EngagementId, JournalId, ObjectId, ReviewTargetRef, RevisionId, TargetRef,
};
use pointbreak::session::event::{
EventTarget, EventType, Revision, ShoreEvent, WorkObjectProposal,
WorkObjectProposedPayload, Writer,
};
use sha2::{Digest, Sha256};
let revision_id = RevisionId::new(format!("rev:sha256:{}", "15".repeat(32)));
let target = TargetRef::Review(ReviewTargetRef::Revision {
revision_id: revision_id.clone(),
});
let payload = WorkObjectProposedPayload {
engagement_id: EngagementId::new(format!("engagement:sha256:{}", "16".repeat(32))),
work_object: WorkObjectProposal::Revision {
revision: Revision {
id: revision_id.clone(),
object_id: ObjectId::new(object_id),
git_provenance: None,
},
summary: Some("generated revision".to_owned()),
object_artifact_content_hash: object_artifact_content_hash.to_owned(),
supersedes: Vec::new(),
},
};
let idempotency_key = format!("fixture:provenance-free:{}", revision_id.as_str());
let event = ShoreEvent::new(
EventType::WorkObjectProposed,
&idempotency_key,
EventTarget::for_generative_move(
JournalId::new("journal:default"),
pointbreak::model::EngagementType::Review,
target,
None,
)
.expect("fixture event target"),
Writer::shore_local("test"),
payload,
"2026-07-24T00:00:00Z",
)
.expect("fixture event");
let events_dir = common_dir_store(repo_root).join("events");
std::fs::create_dir_all(&events_dir).expect("create fixture events directory");
let stem = Sha256::digest(idempotency_key.as_bytes())
.iter()
.map(|byte| format!("{byte:02x}"))
.collect::<String>();
std::fs::write(
events_dir.join(format!("{stem}.json")),
serde_json::to_vec(&event).expect("serialize fixture event"),
)
.expect("write fixture event");
revision_id.as_str().to_owned()
}
#[track_caller]
#[allow(dead_code)]
pub fn assert_existing_paths_eq(actual: &Path, expected: &Path) {
assert_eq!(
actual.canonicalize().expect("canonicalize actual path"),
expected.canonicalize().expect("canonicalize expected path")
);
}