| 1 |
# Mutants that NO test can kill, with the reason each one is unreachable by any |
| 2 |
# test that could be written. |
| 3 |
# |
| 4 |
# WHY THIS IS AT THE WORKSPACE ROOT AND NOT PER-CRATE. Measured against |
| 5 |
# cargo-mutants 27.1.0: the config is read from the workspace root and nowhere |
| 6 |
# else. A `crates/shop-vt/.cargo/mutants.toml` is silently ignored -- both |
| 7 |
# `cargo mutants -p shop-vt` from here and `cargo mutants` run inside the crate |
| 8 |
# directory listed the full 191 mutants with it in place, and 170 with the same |
| 9 |
# file here. So one file covers the workspace, and every pattern is qualified by |
| 10 |
# the type it belongs to (`Perform::`, `Parser::`) rather than relying on scope. |
| 11 |
# |
| 12 |
# THE BAR IS IMPOSSIBILITY, NOT COST. A mutant that a test could kill, where |
| 13 |
# nobody has written that test, does not belong here however unappealing the |
| 14 |
# test looks. It stays a visible survivor with a GoingsOn task against it. The |
| 15 |
# two classes are easy to conflate and the difference is the whole value of the |
| 16 |
# number: an exclusion list that also absorbs "not worth it" reports zero while |
| 17 |
# real coverage gaps sit underneath it. |
| 18 |
# |
| 19 |
# The patterns are regexes, so `+`, `*`, `|` and `.` need escaping. A bare `||` |
| 20 |
# is an empty alternation and silently excludes every mutant in the crate. |
| 21 |
|
| 22 |
exclude_re = [ |
| 23 |
# ===================== shop-vt ===================== |
| 24 |
# --- Default trait method bodies ------------------------------------- |
| 25 |
# |
| 26 |
# Every `Perform` method has a default body of the form `let _ = args;`, |
| 27 |
# which exists only to name the arguments so an implementor that wants none |
| 28 |
# of them compiles without warnings. Replacing that body with `()` is the |
| 29 |
# same program: the discard has no effect and the method returns `()` |
| 30 |
# either way. What the parser calls is always the implementor's override, |
| 31 |
# and no test can observe a default that does nothing being replaced by |
| 32 |
# nothing. |
| 33 |
"replace Perform::print with \\(\\)", |
| 34 |
"replace Perform::execute with \\(\\)", |
| 35 |
"replace Perform::csi_dispatch with \\(\\)", |
| 36 |
"replace Perform::esc_dispatch with \\(\\)", |
| 37 |
"replace Perform::osc_dispatch with \\(\\)", |
| 38 |
"replace Perform::hook with \\(\\)", |
| 39 |
"replace Perform::put with \\(\\)", |
| 40 |
"replace Perform::apc_dispatch with \\(\\)", |
| 41 |
|
| 42 |
# --- Match arms that fall through to an identical `_ => {}` ----------- |
| 43 |
# |
| 44 |
# The state handlers are written to mirror the DEC parser's transition |
| 45 |
# tables arm for arm, including the arms whose action is "nothing". Those |
| 46 |
# arms document a byte range the spec calls out; deleting one lets the same |
| 47 |
# bytes reach the handler's own `_ => {}`, which does the same nothing. The |
| 48 |
# arms are kept because a reader checking this file against vt100.net needs |
| 49 |
# to find them, and excluded because no observation distinguishes them. |
| 50 |
# |
| 51 |
# 0x7F (DEL) is ignored in every state that names it, which is the reason |
| 52 |
# this list is mostly 0x7F. |
| 53 |
"delete match arm 0x80\\.\\.= 0xBF in Parser::ground", |
| 54 |
"delete match arm 0x7F in Parser::escape$", |
| 55 |
"delete match arm 0x7F in Parser::escape_intermediate", |
| 56 |
"delete match arm 0x7F in Parser::csi_entry", |
| 57 |
"delete match arm 0x7F in Parser::csi_param", |
| 58 |
"delete match arm 0x7F in Parser::csi_intermediate", |
| 59 |
"delete match arm 0x7F in Parser::dcs_entry", |
| 60 |
"delete match arm 0x7F in Parser::dcs_param", |
| 61 |
"delete match arm 0x7F in Parser::dcs_intermediate", |
| 62 |
|
| 63 |
# The three DCS prelude states discard C0 controls rather than executing |
| 64 |
# them (unlike the CSI states, which execute). The arm's body is `{}` and |
| 65 |
# the fall-through is `{}`. |
| 66 |
"delete match arm 0x00\\.\\.= 0x17 \\| 0x19 \\| 0x1C\\.\\.= 0x1F in Parser::dcs_entry", |
| 67 |
"delete match arm 0x00\\.\\.= 0x17 \\| 0x19 \\| 0x1C\\.\\.= 0x1F in Parser::dcs_param", |
| 68 |
"delete match arm 0x00\\.\\.= 0x17 \\| 0x19 \\| 0x1C\\.\\.= 0x1F in Parser::dcs_intermediate", |
| 69 |
|
| 70 |
# --- Clearing state that is already clear ----------------------------- |
| 71 |
# |
| 72 |
# `ESC ESC` in the Escape state. Every route into Escape calls `clear()` on |
| 73 |
# the way in (Ground, Utf8, DcsIgnore, DcsPassthrough, OscString and |
| 74 |
# ApcString all do), and the only arm inside Escape that writes |
| 75 |
# intermediates or parameters is 0x20..=0x2F, which leaves Escape as it |
| 76 |
# writes. So the parser is never in Escape holding anything to clear, and |
| 77 |
# deleting the arm leaves the byte to a `_ => {}` that also holds the state |
| 78 |
# still. Kept because the DEC table names the transition. |
| 79 |
"delete match arm 0x1B in Parser::escape$", |
| 80 |
|
| 81 |
# --- A reset that its partner has always already done ----------------- |
| 82 |
# |
| 83 |
# `apc_start` clears `apc_buf` and `string_overflow` on the way into an APC, |
| 84 |
# SOS or PM body. Every route out of `ApcString` -- the BEL arm and the ESC |
| 85 |
# arm, which are the only two -- calls `apc_end`, which clears both and |
| 86 |
# shrinks the buffer besides. So the parser is never in Escape about to open |
| 87 |
# a string while holding a previous one's bytes or its overflow flag, and |
| 88 |
# the opening clear has nothing to clear. Kept because the pairing is what |
| 89 |
# makes that true, and a third exit added later would need it. |
| 90 |
# |
| 91 |
# `osc_start` is NOT here and is caught: it also pushes the first parameter |
| 92 |
# placeholder, which is work nothing else does. |
| 93 |
"replace Parser::apc_start with \\(\\)", |
| 94 |
] |
| 95 |
|