Delete src/convert.c: libakstdlib 0.2.0 grew the contract it existed for
Some checks failed
akbasic CI Build / cmake_build (push) Successful in 2m52s
akbasic CI Build / sanitizers (push) Successful in 3m9s
akbasic CI Build / coverage (push) Failing after 3m12s
akbasic CI Build / akgl_build (push) Failing after 20s
akbasic CI Build / mutation_test (push) Successful in 7m27s
Some checks failed
akbasic CI Build / cmake_build (push) Successful in 2m52s
akbasic CI Build / sanitizers (push) Successful in 3m9s
akbasic CI Build / coverage (push) Failing after 3m12s
akbasic CI Build / akgl_build (push) Failing after 20s
akbasic CI Build / mutation_test (push) Successful in 7m27s
That file wrapped strtoll and strtod because libakstdlib's aksl_ato* family
could not report a conversion failure at all -- atoi("not a number") returned
success with 0, turning four diagnosable errors into wrong answers. Its own note
said what to do when that changed: "When it grows it, delete src/convert.c and
switch the call sites over." 0.2.0 grew it, so it is gone.
Six call sites go straight to the library now: both literal constructors in
src/grammar.c, the line number in src/scanner.c, FunctionVAL in
src/runtime_functions.c, INPUT in src/runtime_commands.c, and GSHAPE's handle in
src/runtime_graphics.c. aksl_strtoll(str, NULL, base, &dest) rather than
aksl_atoll wherever a base is involved, because the ato* forms are base 10 and
grammar.c picks base 8 or 16 off the lexeme's prefix; the NULL endptr is what
makes trailing junk an error rather than a stopping point.
The raised status changed from AKBASIC_ERR_VALUE to AKERR_VALUE, and the message
with it -- VAL("garbage") now says `no digits in "garbage"`. Section 1.8 makes
message text part of the acceptance contract, so that was checked against the
corpus before touching anything: no golden file contained a conversion message,
which is also why section 1.9 had been asking for one. Two exist now, so the next
change to that text has to move a golden file, and one of them pins the
reference's octal-literal defect (section 6 item 10) while it is still
deliberately reproduced.
tests/convert.c became tests/numeric_contract.c rather than being deleted with
the code. The assertions did not stop being worth making when the wrapper went
away -- they became assertions about a contract this port depends on and no
longer owns, and a regression in it would make four things quietly return zero.
Repoints the CI mutation job, which was bounded to src/convert.c and
src/symtab.c. src/symtab.c alone measures 74.1% against the gate of 65.
src/audio_tables.c was measured as a replacement second file and scored 64.7%:
that is a real gap rather than a reason to skip it, since almost every survivor
is in akbasic_audio_state_init, where nothing asserts a freshly initialised audio
state is actually zeroed -- the same gap this job's history records closing for
symtab. Recorded in TODO.md so the file can earn its place back.
One thing worth knowing before reading any score here, and now written down: the
harness's ICR operator only rewrites the constants 0 and 1, so a lookup table of
other values produces no mutants and a high score over one says nothing about
whether its entries are right. tests/audio_verbs.c now asserts all 32 ADSR
entries against the datasheet anyway, because a hand-edit typo is the real
failure mode there -- but that could not and did not move the mutation number,
and claiming otherwise would be the kind of thing this file exists to stop.
72/72 core, 73/73 with libakgl, 72/72 under ASan+UBSan, coverage 93.6% line and
97.8% function, clean under -Wall -Wextra, doxygen clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -238,16 +238,27 @@ jobs:
|
||||
# sites -- gcov attributes ATTEMPT/CATCH/PASS to the caller, so coverage
|
||||
# cannot see them and mutation testing is the only thing that checks them.
|
||||
#
|
||||
# Bounded to two small, fast, deterministic files. src/value.c is the file
|
||||
# most worth mutating and is deliberately *not* here: 368 mutants at ~11s
|
||||
# each is about 70 minutes, because almost everything links against it.
|
||||
# Run the default target locally for the whole tree:
|
||||
# Bounded to one small, fast, deterministic file. It used to be two --
|
||||
# src/convert.c was the other -- but that file has been deleted: it existed
|
||||
# only because libakstdlib's aksl_ato* family could not report a conversion
|
||||
# failure, and 0.2.0 fixed that. src/value.c is the file most worth
|
||||
# mutating and is deliberately *not* here: 368 mutants at ~11s each is
|
||||
# about 70 minutes, because almost everything links against it. Run the
|
||||
# default target locally for the whole tree:
|
||||
# cmake --build build --target mutation
|
||||
#
|
||||
# The threshold is a ratchet, not a quality bar. The measured score for
|
||||
# these two files is 77.8% (84 killed, 24 survived, 108 total); 65 leaves
|
||||
# headroom for runner variance while still failing on a real regression --
|
||||
# a test deleted, or new untested code added.
|
||||
# src/symtab.c is 74.1% (46 killed by test, 14 by compile, 21 survived, 81
|
||||
# total); 65 leaves headroom for runner variance while still failing on a
|
||||
# real regression -- a test deleted, or new untested code added.
|
||||
#
|
||||
# src/audio_tables.c was measured as a replacement second file and scored
|
||||
# 64.7%, below the gate. That is a real test gap rather than a reason to
|
||||
# avoid the file: almost every survivor is in akbasic_audio_state_init,
|
||||
# where nothing asserts that a freshly initialised audio state is actually
|
||||
# zeroed and defaulted -- the same gap this job's own history records
|
||||
# closing for src/symtab.c. Recorded in TODO.md; add the file back when it
|
||||
# is closed.
|
||||
#
|
||||
# It was 73.1% before writing this job. The run's own findings closed the
|
||||
# gap: nothing exercised a maximum-length symbol-table key, so every
|
||||
@@ -255,17 +266,16 @@ jobs:
|
||||
# freshly initialised table was actually zeroed. Adding those two
|
||||
# assertions to tests/symtab.c killed five mutants. The same run found that
|
||||
# errno was never asserted clear before a strtoll, which is what stops a
|
||||
# stale ERANGE from failing a valid conversion -- that is now in
|
||||
# tests/convert.c.
|
||||
# stale ERANGE from failing a valid conversion -- that assertion outlived
|
||||
# the wrapper it was written for and is now in tests/numeric_contract.c,
|
||||
# asserted against libakstdlib.
|
||||
#
|
||||
# The 24 remaining survivors are listed in the published report. Most are
|
||||
# The 21 remaining survivors are listed in the published report. Most are
|
||||
# ICR mutants on loop and accumulator initialisers that a stronger
|
||||
# placement assertion would catch; three in convert.c are genuinely
|
||||
# equivalent and cannot be killed. Recorded in TODO.md.
|
||||
# placement assertion would catch. Recorded in TODO.md.
|
||||
- name: mutation testing
|
||||
run: |
|
||||
python3 scripts/mutation_test.py \
|
||||
--target src/convert.c \
|
||||
--target src/symtab.c \
|
||||
--junit mutation-junit.xml \
|
||||
--threshold 65
|
||||
|
||||
@@ -83,10 +83,10 @@ jobs:
|
||||
# measure them.
|
||||
#
|
||||
# The default threshold matches ci.yaml's rather than being stricter.
|
||||
# Whole-tree coverage is uneven -- src/convert.c and src/symtab.c are the
|
||||
# two measured files, at 77.8% between them, and the rest is unmeasured, so
|
||||
# a tighter number here would be a guess. Raise it with the workflow input
|
||||
# once a full run has established a real baseline.
|
||||
# Whole-tree coverage is uneven -- src/symtab.c is the only file measured
|
||||
# on the push path, at 74.1%, and the rest is unmeasured, so a tighter
|
||||
# number here would be a guess. Raise it with the workflow input once a
|
||||
# full run has established a real baseline.
|
||||
#
|
||||
# The two inputs arrive through the environment rather than being
|
||||
# interpolated straight into the script. ${{ }} substitution happens before
|
||||
|
||||
Reference in New Issue
Block a user