test: mutation testing — break dotup on purpose and check the suite notices
Each file in .tests/mutations/ is one deliberate bug: what it breaks, why that matters, the assertion meant to catch it, and an OLD/NEW pair applied to a copy of the tree. A mutation is KILLED only when the suite fails AND the named assertion is among the failures — failing for an unrelated reason is reported as WRONG-TEST, because that is luck, and luck is lost the next time the unrelated test moves. A mutation whose OLD block no longer matches is STALE rather than quietly skipped. 19 reproduces the DU-C1 shape: a comment moved back inside the fzf line-continuation. It is killed by "dotup pick exits 0".
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# what: the private filter in selected_packages, removed
|
||||
# why: the "private is never a package" invariant is what makes --unattended safe
|
||||
# kills: no private row reaches the plan
|
||||
# run: unit
|
||||
<<<OLD
|
||||
$3=="private" { next }
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: the bws checksum comparison, inverted: accepts on mismatch, rejects on match
|
||||
# why: the binary is about to hold the key to every other credential
|
||||
# kills: a checksum mismatch refuses to install
|
||||
# run: unit
|
||||
<<<OLD
|
||||
if [ -n "$want" ] && [ "$want" != "$got" ]; then
|
||||
<<<NEW
|
||||
if [ -n "$want" ] && [ "$want" = "$got" ]; then
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: the bws token written 644 instead of 600
|
||||
# why: any account on the box could then read the machine credential
|
||||
# kills: the bws token is written 600
|
||||
# run: unit
|
||||
<<<OLD
|
||||
chmod 600 "$BWS_TOKEN"
|
||||
<<<NEW
|
||||
chmod 644 "$BWS_TOKEN"
|
||||
<<<END
|
||||
@@ -0,0 +1,8 @@
|
||||
# what: the chmod -R go-rwx on the cloned private source, removed
|
||||
# why: the clone lands at the caller umask -- 022 on stock Ubuntu -- holding ssh config and machine identity
|
||||
# kills: the private source is unreadable to anyone else
|
||||
# run: unit
|
||||
<<<OLD
|
||||
[ ! -d "$PRIV_SRC" ] || chmod -R go-rwx "$PRIV_SRC" 2>/dev/null || :
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,13 @@
|
||||
# what: the password retry loop: any non-200 is fatal again
|
||||
# why: these credentials are asked for after every package is installed; one typo used to cost the whole install
|
||||
# kills: …then asks again, keeping the URL
|
||||
# run: unit
|
||||
<<<OLD
|
||||
P_BLOB=''
|
||||
say " Try again, or type q at the URL prompt to stay public-only."
|
||||
done
|
||||
<<<NEW
|
||||
P_BLOB=''
|
||||
return 1
|
||||
done
|
||||
<<<END
|
||||
@@ -0,0 +1,11 @@
|
||||
# what: cmd_private's unattended guard, inverted
|
||||
# why: an unattended run would sit at a password prompt nobody is there to answer
|
||||
# kills: --unattended: nobody is here to type it
|
||||
# run: unit
|
||||
<<<OLD
|
||||
if [ "$UNATTENDED" -eq 1 ]; then
|
||||
warn "unattended: the private tier needs a password nobody is here to type — skipped"
|
||||
<<<NEW
|
||||
if [ "$UNATTENDED" -ne 1 ]; then
|
||||
warn "unattended: the private tier needs a password nobody is here to type — skipped"
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: cmd_private's terminal guard, inverted
|
||||
# why: the private tier would run with no terminal, reading EOF for a password
|
||||
# kills: no tty: it says THAT instead
|
||||
# run: unit
|
||||
<<<OLD
|
||||
[ -t 0 ] || { warn "no terminal: the private tier needs a password — skipped"; return 0; }
|
||||
<<<NEW
|
||||
[ ! -t 0 ] || { warn "no terminal: the private tier needs a password — skipped"; return 0; }
|
||||
<<<END
|
||||
@@ -0,0 +1,19 @@
|
||||
# what: cmd_install's unattended invasive refusal, deleted
|
||||
# why: a stale state file would install a docker daemon on a machine with nobody at the keyboard
|
||||
# kills: the daemon never reaches a package manager
|
||||
# run: unit
|
||||
<<<OLD
|
||||
if [ "$UNATTENDED" -eq 1 ]; then
|
||||
inv=$(awk -F'\t' -v selfile="$SEL" '
|
||||
BEGIN{ while((getline l < selfile)>0) sel[l]=1 }
|
||||
!/^[#@]/ && NF>=3 && $3=="invasive" && (($1"/"$2) in sel) {print $1"/"$2}' "$MANIFEST")
|
||||
if [ -n "$inv" ]; then
|
||||
warn "unattended: refusing invasive packages$(printf ' %s' $inv)"
|
||||
for k in $inv; do
|
||||
awk -F'\t' -v k="$k" '$3!=k' "$tbl" > "$tbl.f"; mv "$tbl.f" "$tbl"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,11 @@
|
||||
# what: cmd_install always returns 0
|
||||
# why: a CI run or a wrapper script cannot tell a clean install from six failures
|
||||
# kills: the run exits non-zero
|
||||
# run: unit
|
||||
<<<OLD
|
||||
printf '\n%s%d package(s) did not install.%s Everything else did.\n' "$YEL" "$n" "$R" >&2
|
||||
return 1
|
||||
<<<NEW
|
||||
printf '\n%s%d package(s) did not install.%s Everything else did.\n' "$YEL" "$n" "$R" >&2
|
||||
return 0
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: note_fail() neutered: failures are dropped
|
||||
# why: the summary, the count and the exit code all come from this one file
|
||||
# kills: …under a heading you can find
|
||||
# run: unit
|
||||
<<<OLD
|
||||
note_fail() { printf '%s\t%s\n' "$1" "$2" >> "$FAILED"; err "$1: $2"; }
|
||||
<<<NEW
|
||||
note_fail() { :; }
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: ensure_chezmoi's installer call replaced with true
|
||||
# why: the private tier died with `chezmoi: not found` AFTER writing the bws token
|
||||
# kills: the installer call did not install anything
|
||||
# run: lab:scenarios/31-chezmoi-absent.sh
|
||||
<<<OLD
|
||||
sh -c "$(curl -fsLS get.chezmoi.io)" -- -b "$HOME/.local/bin" >/dev/null 2>&1 \
|
||||
<<<NEW
|
||||
true >/dev/null 2>&1 \
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: find_tool no longer looks in ~/.local/bin
|
||||
# why: uv, bws and chezmoi all land there, on no PATH the running process has
|
||||
# kills: uv is found in ~/.local/bin, off PATH
|
||||
# run: unit
|
||||
<<<OLD
|
||||
for ft_c in "$HOME/.local/bin/$1" "$HOME/bin/$1" "$HOME/.npm-global/bin/$1" \
|
||||
<<<NEW
|
||||
for ft_c in "$HOME/bin/$1" "$HOME/.npm-global/bin/$1" \
|
||||
<<<END
|
||||
@@ -0,0 +1,11 @@
|
||||
# what: the apt one-at-a-time retry, removed
|
||||
# why: apt refuses the whole batch when one name is unusable; the retry is the difference between 34 installed and 0
|
||||
# kills: …then btop on its own
|
||||
# run: unit
|
||||
<<<OLD
|
||||
for p in $keep; do
|
||||
run_sh "${SUDO:+$SUDO }DEBIAN_FRONTEND=noninteractive apt-get install -y $p" \
|
||||
|| note_fail "$p" "apt install failed"
|
||||
done
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,8 @@
|
||||
# what: the npm one-at-a-time retry, removed
|
||||
# why: same shape as apt: one bad spec takes every other tool down with it
|
||||
# kills: …then @openai/codex on its own
|
||||
# run: unit
|
||||
<<<OLD
|
||||
for p in $specs; do run_sh "$NPM install -g $p" || note_fail "$(keyof npm "$p")" "npm install failed"; done
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: install_fzf's base URL pointed at a host that does not exist
|
||||
# why: the picker cannot draw the list that installs fzf without fzf
|
||||
# kills: the fetch goes to the fzf release download URL
|
||||
# run: unit
|
||||
<<<OLD
|
||||
base=https://github.com/junegunn/fzf/releases/download
|
||||
<<<NEW
|
||||
base=https://github.invalid/junegunn/fzf/releases/download
|
||||
<<<END
|
||||
@@ -0,0 +1,9 @@
|
||||
# what: the neovim tarball extracted to /opt/nvim-TYPO
|
||||
# why: tar succeeds, the symlink dangles, and nothing says so
|
||||
# kills: the tarball is extracted where the symlink points
|
||||
# run: unit
|
||||
<<<OLD
|
||||
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf /tmp/nvim.tgz -C /opt/nvim --strip-components=1" \
|
||||
<<<NEW
|
||||
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf /tmp/nvim.tgz -C /opt/nvim-TYPO --strip-components=1" \
|
||||
<<<END
|
||||
@@ -0,0 +1,8 @@
|
||||
# what: install_deb's install step, removed: it downloads and stops
|
||||
# why: chrome and ghostty would report success having installed nothing
|
||||
# kills: …and then handed to the package manager
|
||||
# run: unit
|
||||
<<<OLD
|
||||
run_sh "${SUDO:+$SUDO }apt-get install -y '$f'" || note_fail "$(keyof deb "$s")" "dpkg install failed"
|
||||
<<<NEW
|
||||
<<<END
|
||||
@@ -0,0 +1,10 @@
|
||||
# what: a comment moved back INSIDE the fzf line-continuation (the DU-C1 shape)
|
||||
# why: the `\`-newline is stripped first, so the comment's own newline ends the command: fzf gets two binds and the lines below run as a command named --bind
|
||||
# kills: dotup pick exits 0
|
||||
# run: unit
|
||||
<<<OLD
|
||||
--bind "tab:execute-silent($SELF expand {2})+reload($SELF render)" \
|
||||
<<<NEW
|
||||
--bind "tab:execute-silent($SELF expand {2})+reload($SELF render)" \
|
||||
# clear-query is not cosmetic: ^t toggles every row the filter shows.
|
||||
<<<END
|
||||
Reference in New Issue
Block a user