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.
This commit is contained in:
Sylvestre Ledru
2026-05-31 11:41:16 +02:00
parent 28186e9ec3
commit 56d774f576
+100
View File
@@ -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");
}