use super::*;
#[test]
fn help_render_matches_spawned_binary() {
for args in [
vec!["clone", "--help"],
vec!["capture", "--help"],
vec!["capture", "--help-agent"],
vec!["push", "--help"],
vec!["log", "--help"],
vec!["import", "git", "--help"],
vec!["import", "--help"],
vec!["help"],
vec!["help", "advanced"],
vec!["help", "git-concepts"],
vec!["help", "threads"],
vec!["help", "git-overlay"],
vec!["help", "status"],
vec!["-vC", ".", "capture", "--help-agent"],
vec!["--output", "text", "capture", "--help-agent"],
] {
let spawned = heddle(&args, None)
.unwrap_or_else(|err| panic!("spawned `heddle {}`: {err}", args.join(" ")));
let in_process = heddle_help(&args);
assert_eq!(
in_process,
spawned,
"in-process render of `heddle {}` must match the spawned binary's stdout byte-for-byte",
args.join(" ")
);
}
}
#[test]
fn clone_help_pins_behavior_stanza() {
let summary = heddle_help(&["clone", "--help"]);
assert!(
summary.contains("Behavior:"),
"clone help should include a Behavior stanza: {summary}"
);
assert!(
summary.contains("selected default branch"),
"clone help summary should say where clones land: {summary}"
);
assert!(
summary.contains("--thread"),
"clone help summary should name the escape hatch: {summary}"
);
assert!(
summary.contains("heddle help clone"),
"clone help should breadcrumb to the full clone topic: {summary}"
);
let help = heddle_help(&["help", "clone"]);
assert!(
help.contains("Git source is streamed by Sley directly")
&& help.contains("No Git executable or `.heddle/git` mirror is used"),
"clone topic should explain the Git-overlay transport and storage path: {help}"
);
assert!(
help.contains("Native clones target `main` directly")
&& help.contains("if the remote has no `main` thread")
&& help.contains("--thread <name>"),
"clone topic should explain native default-thread selection: {help}"
);
assert!(
help.contains("--depth 0") && help.contains("full history"),
"clone topic should explain that --depth 0 is full history: {help}"
);
assert!(
help.contains("depth boundary") && help.contains("re-clone at a greater --depth"),
"clone topic should explain that history past the depth boundary is absent and recovered by re-cloning at a greater depth: {help}"
);
assert!(
help.contains("Git Overlay clones ingest full history")
&& help.contains("reject partial-history")
&& help.contains("options"),
"clone topic should explain that shallow history is native-only: {help}"
);
assert!(
help.contains("tip plus its immediate parents"),
"clone topic should explain that --depth 1 keeps the tip plus immediate parents: {help}"
);
assert!(
help.contains("heddle help threads"),
"clone topic should point at the threads topic: {help}"
);
}
#[test]
fn capture_help_agent_reveals_hidden_flags_through_clap() {
let expect_revealed = |help: &str, ctx: &str| {
for flag in [
"--agent-provider",
"--agent-model",
"--agent-session",
"--agent-segment",
"--policy",
"--no-policy",
"--no-agent",
"--split",
"--into",
] {
assert!(
help.contains(flag),
"`{ctx}` should reveal `{flag}` inline: {help}"
);
}
};
let plain = heddle_help(&["capture", "--help-agent"]);
expect_revealed(&plain, "capture --help-agent");
let clustered = heddle_help(&["-vC", ".", "capture", "--help-agent"]);
expect_revealed(&clustered, "-vC <path> capture --help-agent");
let long_global = heddle_help(&["--output", "text", "capture", "--help-agent"]);
expect_revealed(&long_global, "--output text capture --help-agent");
}
#[test]
fn capture_help_keeps_help_agent_hidden_but_keeps_the_pointer() {
let help = heddle_help(&["capture", "--help"]);
assert!(
help.contains("heddle capture --help-agent"),
"`capture --help` should keep the after-help pointer to `--help-agent`: {help}"
);
assert_eq!(
help.matches("--help-agent").count(),
1,
"`capture --help` must not list the hidden `--help-agent` flag (only the after-help pointer): {help}"
);
}
#[test]
fn clone_help_carries_hidden_flag_breadcrumb() {
let help = heddle_help(&["clone", "--help"]);
assert!(
help.contains("Advanced/planned flags: see `heddle help clone`."),
"clone help should point to the advanced/planned flag topic: {help}"
);
assert!(
!help.contains("--lazy") && !help.contains("--filter"),
"clone help should keep hidden flags out of the human options/body: {help}"
);
}
#[test]
fn pull_help_carries_hidden_flag_breadcrumb() {
let help = heddle_help(&["pull", "--help"]);
assert!(
help.contains("--lazy") && help.contains("hydrates it explicitly later"),
"pull help should name the hidden --lazy flag and its behavior: {help}"
);
}
#[test]
fn start_help_carries_hidden_flag_breadcrumb() {
let help = heddle_help(&["start", "--help"]);
for flag in [
"--agent-provider",
"--agent-model",
"--parent-thread",
"--print-cd-path",
"--daemon",
"--no-daemon",
"--shared-target",
"--no-shared-target",
] {
assert!(
help.contains(flag),
"start help should name the hidden `{flag}` flag in its advanced stanza: {help}"
);
}
}
#[test]
fn diff_help_explains_git_compatible_patch_headers() {
let help = heddle_help(&["diff", "--help"]);
assert!(
help.contains("Git-compatible unified diff")
&& help.contains("extended headers for type and mode changes"),
"diff help should explain its patch format and extended headers: {help}"
);
}
#[test]
fn commit_help_explains_capture_boundary() {
let help = heddle_help(&["commit", "--help"]);
assert!(
help.contains("Defaults to the current capture intent")
&& help.contains("Commits the complete captured tree")
&& help.contains("Git pre-commit and commit-msg hooks are not run"),
"commit help should explain how a capture becomes Git history: {help}"
);
}
#[test]
fn git_concepts_topic_explains_authority_and_current_surface() {
let help = heddle_help(&["help", "git-concepts"]);
assert!(
help.contains("Git and Heddle own different layers."),
"git-concepts topic should lead with the authority boundary: {help}"
);
for ownership in [
"`.git` owns commits, refs",
"the index, and worktree state",
"coordination and durable metadata in `.heddle`",
"captures, provenance, threads, readiness, review, and safe landing",
] {
assert!(
help.contains(ownership),
"git-concepts topic missing ownership statement `{ownership}`: {help}"
);
}
assert!(
help.contains("`clone`,")
&& help.contains("`commit`,")
&& help.contains("`pull`,")
&& help.contains("`push`, and `remote`")
&& help.contains("embedded Sley engine directly"),
"git-concepts topic should name the current thin Git surface and engine: {help}"
);
for mapping in [
"| Intent | Git Overlay | Native Heddle |",
"`heddle capture`, then `heddle commit`",
"| Record a granular Heddle savepoint | `heddle capture` | `heddle capture` |",
"| Check integration readiness | `heddle ready` | `heddle ready` |",
"| Integrate a managed thread | `heddle land` | `heddle land` |",
"| Synchronize source | `heddle pull` / `heddle push`",
"| Configure remotes | `heddle remote` | `heddle remote` |",
] {
assert!(
help.contains(mapping),
"git-concepts topic missing current mapping `{mapping}`: {help}"
);
}
assert!(
help.contains("Use `heddle init` to add that sidecar")
&& help.contains("`heddle adopt`")
&& help.contains("one atomic transition")
&& help.contains("makes Heddle the repository authority"),
"git-concepts topic should distinguish sidecar initialization from adoption: {help}"
);
assert!(
help.contains("optional Git-compatible client")
&& help.contains("it is not a Heddle dependency")
&& help.contains("`import git`")
&& help.contains("`export")
&& help.contains("git`, and `sync git`")
&& help.contains("translate data between authorities"),
"git-concepts topic should explain unsupported Git operations and authority translation: {help}"
);
for removed in ["heddle checkpoint", "heddle fetch", "heddle switch"] {
assert!(
!help.contains(removed),
"git-concepts topic must not advertise removed command `{removed}`: {help}"
);
}
let top = heddle_help(&["help"]);
assert!(
top.contains("heddle help git-concepts"),
"main help should link the git concept map from Start here: {top}"
);
}