Skip to content

Commit 47191e6

Browse files
committed
test: add integration tests for git diff --quiet optimization
1 parent ef5b0c0 commit 47191e6

File tree

1 file changed

+120
-3
lines changed

1 file changed

+120
-3
lines changed

crates/prek/tests/skipped_hooks.rs

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,130 @@ fn all_hooks_skipped_multiple_priority_groups() -> Result<()> {
206206
assert!(stdout.contains("priority-20") && stdout.contains("Skipped"));
207207
assert!(stdout.contains("priority-30") && stdout.contains("Skipped"));
208208

209-
// Regression test for #1335: only 1 get_diff call (initial baseline)
210-
// Without fix: 4 calls (1 initial + 3 per priority group)
209+
// Stashed workflow + all hooks skipped => no diff calls.
211210
let stderr = String::from_utf8_lossy(&output.stderr);
212211
let get_diff_calls = stderr.matches("get_diff").count();
212+
assert_eq!(
213+
get_diff_calls, 0,
214+
"Expected 0 get_diff calls when all hooks skip in stashed workflow.\n\
215+
Found {get_diff_calls} get_diff calls.\n\
216+
Trace output:\n{stderr}"
217+
);
218+
219+
Ok(())
220+
}
221+
222+
/// When stashed, use `has_worktree_changes` first and fall back to `get_diff` after changes.
223+
#[test]
224+
fn uses_has_worktree_changes_when_stashed() -> Result<()> {
225+
let context = TestContext::new();
226+
context.init_project();
227+
228+
let cwd = context.work_dir();
229+
230+
// Hook that modifies files (triggers modification detection)
231+
context.write_pre_commit_config(indoc::indoc! {r#"
232+
repos:
233+
- repo: local
234+
hooks:
235+
- id: modifier
236+
name: modifier
237+
language: system
238+
entry: python3 -c "open('file.txt', 'a').write('modified')"
239+
files: \.txt$
240+
"#});
241+
242+
cwd.child("file.txt").write_str("original")?;
243+
context.git_add(".");
244+
245+
let output = context.run().env("RUST_LOG", "prek::git=trace").output()?;
246+
247+
// Hook should fail because it modified files
248+
assert!(
249+
!output.status.success(),
250+
"hook should fail due to file modification"
251+
);
252+
253+
let stderr = String::from_utf8_lossy(&output.stderr);
254+
255+
// First check uses has_worktree_changes; get_diff only after changes are detected.
256+
let has_worktree_changes_calls = stderr.matches("has_worktree_changes").count();
257+
let get_diff_calls = stderr.matches("get_diff").count();
258+
259+
assert!(
260+
has_worktree_changes_calls >= 1,
261+
"Expected has_worktree_changes to be called for first modification check.\n\
262+
Found {has_worktree_changes_calls} has_worktree_changes calls, {get_diff_calls} get_diff calls.\n\
263+
Trace output:\n{stderr}"
264+
);
265+
266+
// One get_diff call after change detection.
213267
assert_eq!(
214268
get_diff_calls, 1,
215-
"Expected 1 get_diff call (initial baseline) when all hooks skip, found {get_diff_calls}.\n\
269+
"Expected 1 get_diff call (to capture state after change detection).\n\
270+
Found {get_diff_calls} get_diff calls.\n\
271+
Trace output:\n{stderr}"
272+
);
273+
274+
Ok(())
275+
}
276+
277+
/// With --all-files (no stash), use full diff comparison to detect new changes.
278+
#[test]
279+
fn uses_get_diff_when_all_files() -> Result<()> {
280+
let context = TestContext::new();
281+
context.init_project();
282+
283+
let cwd = context.work_dir();
284+
285+
// Hook that modifies files
286+
context.write_pre_commit_config(indoc::indoc! {r#"
287+
repos:
288+
- repo: local
289+
hooks:
290+
- id: modifier
291+
name: modifier
292+
language: system
293+
entry: python3 -c "open('file.txt', 'a').write('modified')"
294+
files: \.txt$
295+
"#});
296+
297+
cwd.child("file.txt").write_str("original")?;
298+
// Stage and commit so file is tracked, then use --all-files
299+
context.git_add(".");
300+
context.configure_git_author();
301+
context.git_commit("initial");
302+
303+
let output = context
304+
.run()
305+
.arg("--all-files")
306+
.env("RUST_LOG", "prek::git=trace")
307+
.output()?;
308+
309+
// Hook should fail because it modified files
310+
assert!(
311+
!output.status.success(),
312+
"hook should fail due to file modification"
313+
);
314+
315+
let stderr = String::from_utf8_lossy(&output.stderr);
316+
317+
// With --all-files (no stash), should use get_diff for comparison
318+
let get_diff_calls = stderr.matches("get_diff").count();
319+
let has_worktree_changes_calls = stderr.matches("has_worktree_changes").count();
320+
321+
assert!(
322+
get_diff_calls >= 1,
323+
"Expected get_diff to be called for --all-files workflow.\n\
324+
Found {get_diff_calls} get_diff calls, {has_worktree_changes_calls} has_worktree_changes calls.\n\
325+
Trace output:\n{stderr}"
326+
);
327+
328+
// has_worktree_changes should NOT be used in --all-files workflow
329+
assert_eq!(
330+
has_worktree_changes_calls, 0,
331+
"Expected 0 has_worktree_changes calls in --all-files workflow.\n\
332+
Found {has_worktree_changes_calls} has_worktree_changes calls.\n\
216333
Trace output:\n{stderr}"
217334
);
218335

0 commit comments

Comments
 (0)