From 56d774f576bd8e3a04027d555b9cdfc471cb923f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 31 May 2026 11:41:16 +0200 Subject: [PATCH] test: cover slow-path modes that literal tests no longer reach The buffer-at-a-time fast path now serves the literal patterns that the existing -l/-L/-q and binary tests used, leaving the line-at-a-time engine's equivalents uncovered. Add bracket-class (non-literal) tests for -l/-L/-q and binary handling (notice, -a text, without-match bail, and the finalize-time notice), plus a fast-path test for a NUL that is only discovered after a line was already printed. No dead code was found: the remaining uncovered lines are writer I/O error-propagation arms and pre-existing filesystem error handlers. --- tests/test_grep.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/test_grep.rs b/tests/test_grep.rs index 87bc292..560dc12 100644 --- a/tests/test_grep.rs +++ b/tests/test_grep.rs @@ -1339,3 +1339,103 @@ fn literal_buffer_path_spans_many_chunks() { .succeeds() .stdout_only(expected_n); } + +// Plain literals run on the buffer-at-a-time fast path, so the following tests +// use bracket-class patterns (non-literal) to keep the line-at-a-time engine's +// `-l` / `-L` / `-q` and binary-handling paths exercised too. + +#[test] +fn slow_path_list_and_quiet_modes() { + let (scene, _) = ucmd(); + scene.fixtures.write("hit", "yes\n"); + scene.fixtures.write("miss", "no\n"); + + // -l: list matching files. + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-l", "[y]es", "hit", "miss"]) + .succeeds() + .stdout_is("hit\n"); + + // -L with a match in one file: only the non-matching file is listed. + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-L", "[y]es", "hit", "miss"]) + .succeeds() + .stdout_is("miss\n"); + + // -L with no match anywhere: both files listed, exit 1. + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-L", "[z]z", "hit", "miss"]) + .fails_with_code(1) + .stdout_is("hit\nmiss\n"); + + // -q stops at the first match (exit 0) or reports no match (exit 1). + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-q", "[y]es", "hit"]) + .succeeds() + .no_output(); + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-q", "[z]z", "hit"]) + .fails_with_code(1) + .no_output(); +} + +#[test] +fn slow_path_binary_handling() { + let (scene, _) = ucmd(); + // NOTE: avoid the name "nul" here — it's a reserved device name on Windows, + // so writing/reading it hits the null device instead of a real file. + scene.fixtures.write_bytes("nulbin", b"hit\0\n"); + scene.fixtures.write_bytes("bad", b"a\x9d\n"); + + // Binary notice on the line-at-a-time engine (regex pattern). + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["[h]it", "nulbin"]) + .succeeds() + .no_stdout() + .stderr_contains("binary file matches"); + + // -a forces text mode: the NUL line is printed verbatim. + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["-a", "[h]it", "nulbin"]) + .succeeds() + .stdout_is_bytes(b"hit\0\n"); + + // --binary-files=without-match bails out on an invalid-UTF-8 match. + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["--binary-files=without-match", "[a]", "bad"]) + .fails_with_code(1) + .no_output(); + + // A NUL after the matched line means binariness is discovered at EOF, so + // the line is printed first and the notice is emitted during finalization. + scene.fixtures.write_bytes("late", b"hit\nno\0\n"); + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["[h]it", "late"]) + .succeeds() + .stdout_is("hit\n") + .stderr_contains("binary file matches"); +} + +#[test] +fn fast_path_binary_detected_after_a_printed_line() { + // A NUL that appears only after the last match in the buffer marks the file + // binary on the fast path *after* an earlier match was already printed: the + // printed line stays and the trailing notice is still emitted. + let (scene, _) = ucmd(); + scene.fixtures.write_bytes("b", b"hit\nno\0\n"); + scene + .cmd(env!("CARGO_BIN_EXE_grep")) + .args(&["hit", "b"]) + .succeeds() + .stdout_is("hit\n") + .stderr_contains("binary file matches"); +}