test(#742): add git-fixture test for diff changed_file_count dedup; fixes unreachable branch in #740 coverage

This commit is contained in:
YeonGyu-Kim 2026-05-26 17:41:02 +09:00
parent 6e78c1fc8b
commit 2036f0bd4c
2 changed files with 82 additions and 0 deletions

View File

@ -7649,3 +7649,5 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
740. **Test coverage gap for ROADMAP #733: `diff_json_has_status_and_result_field_702` did not assert `changed_file_count` contract** — dogfooded 2026-05-26 on `d5f0d6ed`. The test asserts `kind`, `status`, `result`, `action`, `working_directory` but not the new `changed_file_count` field added by #733. Coverage gap: (a) no assertion that the field exists, (b) no assertion of numeric type in git repos, (c) no regression guard for dedupe behavior (staged+unstaged to the same file = 1 changed file). Fix: extend the test to assert `changed_file_count: null` in non-git repos and `changed_file_count: u64` in git repos. Source: gaebal-gajae dogfood on `d5f0d6ed`, 2026-05-26. 740. **Test coverage gap for ROADMAP #733: `diff_json_has_status_and_result_field_702` did not assert `changed_file_count` contract** — dogfooded 2026-05-26 on `d5f0d6ed`. The test asserts `kind`, `status`, `result`, `action`, `working_directory` but not the new `changed_file_count` field added by #733. Coverage gap: (a) no assertion that the field exists, (b) no assertion of numeric type in git repos, (c) no regression guard for dedupe behavior (staged+unstaged to the same file = 1 changed file). Fix: extend the test to assert `changed_file_count: null` in non-git repos and `changed_file_count: u64` in git repos. Source: gaebal-gajae dogfood on `d5f0d6ed`, 2026-05-26.
741. **`claw config list`, `claw config show`, `claw config bogus` --output-format json returned `hint: null` — the unsupported_config_section error envelope had no `hint` field populated, so callers reading `.hint` get null with no actionable guidance** — dogfooded 2026-05-26 on `5d072d21`. The `render_config_json` unsupported-section branch returned a JSON object with `error` (contains the section list) but no `hint` field. Notably `config list` and `config show` are natural verb patterns that users type expecting a list/show subcommand, but claw config uses `claw config` (no args) for list and `claw config <section>` for show — the error gave no indication of this. Fix: add `hint` field to unsupported_config_section error; verbs (`list`, `show`, `help`, `info`) get a hint explaining the correct idiom (`claw config` / `claw config <section>`); other unknown sections get a "not a config section" hint listing valid values. Source: Jobdori dogfood on `5d072d21`, 2026-05-26. 741. **`claw config list`, `claw config show`, `claw config bogus` --output-format json returned `hint: null` — the unsupported_config_section error envelope had no `hint` field populated, so callers reading `.hint` get null with no actionable guidance** — dogfooded 2026-05-26 on `5d072d21`. The `render_config_json` unsupported-section branch returned a JSON object with `error` (contains the section list) but no `hint` field. Notably `config list` and `config show` are natural verb patterns that users type expecting a list/show subcommand, but claw config uses `claw config` (no args) for list and `claw config <section>` for show — the error gave no indication of this. Fix: add `hint` field to unsupported_config_section error; verbs (`list`, `show`, `help`, `info`) get a hint explaining the correct idiom (`claw config` / `claw config <section>`); other unknown sections get a "not a config section" hint listing valid values. Source: Jobdori dogfood on `5d072d21`, 2026-05-26.
742. **ROADMAP #740 test coverage gap: the new `changed_file_count` branch for git repos was unreachable — the fixture is a plain `unique_temp_dir` (no `git init`), so the test always exercises the `no_git_repo` path and never proves the numeric contract or deduplication behavior** — confirmed by gaebal-gajae on `5d072d21`, fixed on `6e78c1fc`. Fix: add `diff_json_changed_file_count_deduplication_733` test that (a) `git init`s a temp repo, (b) commits a file, (c) asserts `result:"clean"` + `changed_file_count:0`, (d) stages an edit + makes an unstaged edit to the same file, (e) asserts `result:"changes"` + `changed_file_count:1` — proving the BTreeSet deduplication actually works. Source: gaebal-gajae dogfood on `5d072d21`, 2026-05-26.

View File

@ -1376,6 +1376,86 @@ fn diff_json_has_status_and_result_field_702() {
} }
} }
#[test]
fn diff_json_changed_file_count_deduplication_733() {
// #733/#742: changed_file_count must be numeric in a git repo, be 0 for clean,
// and deduplicate staged+unstaged edits to the same file (1 file changed = count 1).
use std::process::Command;
let root = unique_temp_dir("diff-changed-dedup");
fs::create_dir_all(&root).expect("temp dir");
// git init + identity config + initial commit
Command::new("git")
.args(["init"])
.current_dir(&root)
.output()
.expect("git init");
Command::new("git")
.args(["config", "user.email", "test@claw.test"])
.current_dir(&root)
.output()
.expect("git config email");
Command::new("git")
.args(["config", "user.name", "Test"])
.current_dir(&root)
.output()
.expect("git config name");
fs::write(root.join("tracked.txt"), b"v1").expect("write tracked");
Command::new("git")
.args(["add", "tracked.txt"])
.current_dir(&root)
.output()
.expect("git add");
Command::new("git")
.args(["commit", "-m", "init"])
.current_dir(&root)
.output()
.expect("git commit");
// Clean state: changed_file_count must be 0
let bin = env!("CARGO_BIN_EXE_claw");
let clean = Command::new(bin)
.current_dir(&root)
.args(["--output-format", "json", "diff"])
.output()
.expect("claw diff clean");
let clean_json: serde_json::Value =
serde_json::from_slice(&clean.stdout).expect("diff clean stdout must be valid JSON");
assert_eq!(clean_json["result"], "clean", "fresh repo must be clean");
assert_eq!(
clean_json["changed_file_count"].as_u64(),
Some(0),
"clean repo must have changed_file_count:0 (#733)"
);
// Make a staged edit AND an unstaged edit to the same file
fs::write(root.join("tracked.txt"), b"v2").expect("staged write");
Command::new("git")
.args(["add", "tracked.txt"])
.current_dir(&root)
.output()
.expect("git add staged");
fs::write(root.join("tracked.txt"), b"v3").expect("unstaged write");
// Dirty state: same file appears in staged+unstaged — must deduplicate to count 1
let dirty = Command::new(bin)
.current_dir(&root)
.args(["--output-format", "json", "diff"])
.output()
.expect("claw diff dirty");
let dirty_json: serde_json::Value =
serde_json::from_slice(&dirty.stdout).expect("diff dirty stdout must be valid JSON");
assert_eq!(
dirty_json["result"], "changes",
"dirty repo must have result:changes (#733)"
);
assert_eq!(
dirty_json["changed_file_count"].as_u64(),
Some(1),
"staged+unstaged edits to same file must deduplicate to changed_file_count:1 (#733)"
);
}
#[test] #[test]
fn export_json_has_kind_702() { fn export_json_has_kind_702() {
// #458/#702: `claw export --output-format json` must emit kind:export. // #458/#702: `claw export --output-format json` must emit kind:export.