|
1 |
+ |
# Mutants no test can kill, with the reason each is equivalent to the code it
|
|
2 |
+ |
# replaces.
|
|
3 |
+ |
#
|
|
4 |
+ |
# THE BAR IS IMPOSSIBILITY, NOT COST (infra `374e1971`, settled 2026-08-31). A
|
|
5 |
+ |
# mutant a test could kill, where nobody has written that test, stays a visible
|
|
6 |
+ |
# survivor with a GoingsOn task against it however unappealing the test looks.
|
|
7 |
+ |
# An exclusion list that also absorbs "not worth it" reports zero while real
|
|
8 |
+ |
# coverage gaps sit underneath it, which is the one thing the number is for.
|
|
9 |
+ |
#
|
|
10 |
+ |
# The two in-memory size guards are the worked example of the other direction.
|
|
11 |
+ |
# `data.len() > cap` and `total_in > cap` survived every run because the cap was
|
|
12 |
+ |
# a 4 GiB constant and `>`, `>=` and `==` agree at every size a fixture can
|
|
13 |
+ |
# reach. That is cost, not impossibility: the cap became a per-client field
|
|
14 |
+ |
# (`synckit@7bc19e6`) and two tests now stand on both sides of it. Neither is in
|
|
15 |
+ |
# this file.
|
|
16 |
+ |
#
|
|
17 |
+ |
# The patterns are regexes matched against the WHOLE listing line, `file:line:col`
|
|
18 |
+ |
# included, so `+`, `*` and `|` need escaping. A bare `||` is an empty
|
|
19 |
+ |
# alternation and silently excludes every mutant in the crate.
|
|
20 |
+ |
#
|
|
21 |
+ |
# Both entries carry a position because the description alone is ambiguous:
|
|
22 |
+ |
# cargo-mutants names a mutant by its operator and enclosing function and
|
|
23 |
+ |
# nothing else, and each of these functions holds other `<` comparisons that are
|
|
24 |
+ |
# caught. A stale anchor stops matching and the mutant returns as a visible
|
|
25 |
+ |
# survivor, which is the safe direction. Re-derive by diffing
|
|
26 |
+ |
# `cargo mutants --list` with and without this file.
|
|
27 |
+ |
|
|
28 |
+ |
exclude_re = [
|
|
29 |
+ |
# `next_part < start.part_count` in the part-filling loop. Every part but
|
|
30 |
+ |
# the last is exactly `part_size`, so the loop never sends the final part;
|
|
31 |
+ |
# `staged.len() >= part_size` can hold at `next_part == start.part_count`
|
|
32 |
+ |
# only when the ciphertext is an exact multiple of the part size, and the
|
|
33 |
+ |
# extra iteration then sends byte-identical bytes to the same URL before the
|
|
34 |
+ |
# function returns down the resume branch regardless. No observation
|
|
35 |
+ |
# distinguishes it.
|
|
36 |
+ |
"src/client/blob.rs:632:58: replace < with <= in SyncKitClient::stream_blob_parts",
|
|
37 |
+ |
|
|
38 |
+ |
# `next_chunk < h.chunk_count` in the chunk-peeling loop. One chunk past the
|
|
39 |
+ |
# count breaks on the next line against an empty buffer, before anything is
|
|
40 |
+ |
# decrypted or appended. The bound is written as the count because that is
|
|
41 |
+ |
# what the count means, not because it is what stops the loop.
|
|
42 |
+ |
"src/client/blob.rs:940:30: replace < with <= in SyncKitClient::blob_download",
|
|
43 |
+ |
]
|