docs(coverage): regenerate the measured table from the command that measures it
This commit is contained in:
1 parent
b7d0f901cc
commit
19c8d4368d
3 files changed
+147
-50
No files matched your search
+43
-48
@@ -3,6 +3,13 @@
|
||||
`plot` measures line coverage of the compiled library bodies under `src/` and enforces a floor on
|
||||
it, so a regression fails a command instead of quietly lowering a number in a document.
|
||||
|
||||
**The table and the floor verdict below are generated.** `tools/coverage.sh` rewrites the region
|
||||
between `<!-- BEGIN GENERATED: tools/coverage.sh -->` and
|
||||
`<!-- END GENERATED: tools/coverage.sh -->` from the report that run just captured, by calling
|
||||
`tools/coverage_floor.py --write-doc`. Do not edit inside those markers: the numbers there come
|
||||
from the command, not from a hand-typed copy, and a run on an unchanged tree rewrites the region
|
||||
with identical content.
|
||||
|
||||
## The one command
|
||||
|
||||
```sh
|
||||
@@ -12,12 +19,10 @@ cmake --build build/cov --target coverage # the same thing, through CMake
|
||||
|
||||
The script configures `build/cov` from the `linux-coverage` preset, builds it, runs the whole
|
||||
`ctest` suite, captures `src/**` with `lcov` into `build/cov/coverage.info`, renders the HTML report
|
||||
to `build/cov/html/index.html`, prints the per-file table below, and **exits non-zero when a floor
|
||||
is violated**. It needs `cmake`, `ninja`, `ctest`, `lcov`, `genhtml` and `python3`
|
||||
(Arch: `pacman -S cmake ninja lcov python`); it exits `2` with a message when one is missing.
|
||||
|
||||
A clean run of it — no build tree, all 26 translation units under `src/` compiled, 274 cases — takes
|
||||
about two minutes here, of which the suite is ~107 s.
|
||||
to `build/cov/html/index.html`, prints the per-file table, rewrites the generated region of this
|
||||
file, and **exits non-zero when a floor is violated**. It needs `cmake`, `ninja`, `ctest`, `lcov`,
|
||||
`genhtml` and `python3` (Arch: `pacman -S cmake ninja lcov python`); it exits `2` with a message
|
||||
when one is missing.
|
||||
|
||||
## The floors
|
||||
|
||||
@@ -35,18 +40,20 @@ about two minutes here, of which the suite is ~107 s.
|
||||
|
||||
## The measured table
|
||||
|
||||
Measured on 2026-09-28 with GCC 16.2.1 from a clean `build/cov`, over the full test suite.
|
||||
`coverage.sh` prints exactly this table on every run.
|
||||
<!-- BEGIN GENERATED: tools/coverage.sh -->
|
||||
|
||||
```
|
||||
coverage_floor: ok -- 23 files under src/, aggregate 95.3% lines (3284/3447), every file at or above 80%, aggregate target 90%
|
||||
```
|
||||
|
||||
<!-- BEGIN GENERATED TABLE (tools/coverage_floor.py --table --format markdown) -->
|
||||
| File | Lines | Line rate | Functions |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| `src/data/array_series.cpp` | 43/43 | 100.0% | 100.0% |
|
||||
| `src/data/minmax_pyramid.cpp` | 163/163 | 100.0% | 100.0% |
|
||||
| `src/data/series.cpp` | 105/107 | 98.1% | 100.0% |
|
||||
| `src/data/stream_series.cpp` | 39/39 | 100.0% | 100.0% |
|
||||
| `src/gl/handle.cpp` | 214/256 | 83.6% | 100.0% |
|
||||
| `src/gl/loader.cpp` | 53/81 | 65.4% | 77.8% |
|
||||
| `src/gl/handle.cpp` | 256/256 | 100.0% | 100.0% |
|
||||
| `src/gl/loader.cpp` | 81/81 | 100.0% | 100.0% |
|
||||
| `src/input/controller.cpp` | 327/341 | 95.9% | 100.0% |
|
||||
| `src/math/transform.cpp` | 28/28 | 100.0% | 100.0% |
|
||||
| `src/plot/axis.cpp` | 12/12 | 100.0% | 100.0% |
|
||||
@@ -55,25 +62,18 @@ Measured on 2026-09-28 with GCC 16.2.1 from a clean `build/cov`, over the full t
|
||||
| `src/plot/measure.cpp` | 21/21 | 100.0% | 100.0% |
|
||||
| `src/plot/plot.cpp` | 733/753 | 97.3% | 98.9% |
|
||||
| `src/plot/ticks.cpp` | 93/99 | 93.9% | 100.0% |
|
||||
| `src/render/buffer.cpp` | 87/98 | 88.8% | 100.0% |
|
||||
| `src/render/buffer.cpp` | 88/98 | 89.8% | 100.0% |
|
||||
| `src/render/embedded_mono_font.cpp` | 45/45 | 100.0% | 100.0% |
|
||||
| `src/render/primitives.cpp` | 71/75 | 94.7% | 100.0% |
|
||||
| `src/render/program.cpp` | 26/27 | 96.3% | 100.0% |
|
||||
| `src/render/renderer.cpp` | 529/604 | 87.6% | 93.7% |
|
||||
| `src/render/text.cpp` | 27/30 | 90.0% | 100.0% |
|
||||
| `src/render/text_atlas.cpp` | 40/41 | 97.6% | 100.0% |
|
||||
| `src/render/vertex_array.cpp` | 49/59 | 83.1% | 100.0% |
|
||||
| `src/render/vertex_array.cpp` | 59/59 | 100.0% | 100.0% |
|
||||
| `src/text/true_type_font.cpp` | 270/291 | 92.8% | 96.8% |
|
||||
| **src/ aggregate** | **3203/3447** | **92.9%** | **97.8%** |
|
||||
<!-- END GENERATED TABLE -->
|
||||
| **src/ aggregate** | **3284/3447** | **95.3%** | **98.3%** |
|
||||
|
||||
**The floor currently fails, and that is the point.** `src/gl/loader.cpp` sits at 65.4% lines
|
||||
(53/81) — below the 80% per-file floor — so `tools/coverage.sh` exits `1` on today's tree. What is
|
||||
uncovered there is the loader's error paths and its extension scanner; `src/gl/handle.cpp` (83.6%)
|
||||
and `src/render/vertex_array.cpp` (83.1%) are the same kind of gap, just above the line. Those tests
|
||||
are Task 2 of `docs/superpowers/plans/2026-09-28-plot-docs-and-coverage.md`; the floor went in first
|
||||
so the fix has something to satisfy rather than something to negotiate with, and so the *next*
|
||||
regression in that area is a failing command rather than a number nobody reads.
|
||||
<!-- END GENERATED: tools/coverage.sh -->
|
||||
|
||||
## What the report measures
|
||||
|
||||
@@ -118,40 +118,35 @@ before `genhtml` re-creates it.
|
||||
per-file `LF`/`LH`/`FNF`/`FNH` tallies that are identical for all 23 files — verified by diffing the
|
||||
two tracefiles — but the per-line hit *counts* differ by a few parts per million, because a handful
|
||||
of tests drive a producer thread whose iteration count follows wall-clock timing. Everything the
|
||||
floor reads (the `LF`/`LH` tallies, and therefore every rate in the table above) is unaffected.
|
||||
floor reads (the `LF`/`LH` tallies, and therefore every rate in the generated table above) is
|
||||
unaffected.
|
||||
|
||||
## Adjusting the floors, and seeing the gate fail
|
||||
|
||||
Both floors are flags, which is how the failure path is demonstrated — and how a later task tightens
|
||||
the contract. Against `build/cov/coverage.info` from the table above:
|
||||
the contract. Against the report in the generated table above, a floor raised above every file's
|
||||
rate fails the check and names each offender:
|
||||
|
||||
```sh
|
||||
$ python3 tools/coverage_floor.py build/cov/coverage.info # the real floors
|
||||
coverage_floor: FAILED -- 1 floor(s) violated in build/cov/coverage.info:
|
||||
src/gl/loader.cpp: 65.4% lines (53/81) is below the 80% per-file floor
|
||||
$ echo $?
|
||||
1
|
||||
# Any file not at 100% fails: a floor that is guaranteed to bite, whatever the
|
||||
# current rates are. The list of offenders is the files in the table above whose
|
||||
# rate is below 100%.
|
||||
python3 tools/coverage_floor.py --per-file 100 build/cov/coverage.info
|
||||
# coverage_floor: FAILED -- <n> floor(s) violated in build/cov/coverage.info:
|
||||
# <file>: <rate>% lines (<hit>/<found>) is below the 100% per-file floor
|
||||
# ...
|
||||
# $? == 1
|
||||
|
||||
$ python3 tools/coverage_floor.py --per-file 95 build/cov/coverage.info # floor raised above rates
|
||||
coverage_floor: FAILED -- 10 floor(s) violated in build/cov/coverage.info:
|
||||
src/gl/handle.cpp: 83.6% lines (214/256) is below the 95% per-file floor
|
||||
src/gl/loader.cpp: 65.4% lines (53/81) is below the 95% per-file floor
|
||||
src/plot/grid.cpp: 93.8% lines (15/16) is below the 95% per-file floor
|
||||
src/plot/ticks.cpp: 93.9% lines (93/99) is below the 95% per-file floor
|
||||
src/render/buffer.cpp: 88.8% lines (87/98) is below the 95% per-file floor
|
||||
src/render/primitives.cpp: 94.7% lines (71/75) is below the 95% per-file floor
|
||||
src/render/renderer.cpp: 87.6% lines (529/604) is below the 95% per-file floor
|
||||
src/render/text.cpp: 90.0% lines (27/30) is below the 95% per-file floor
|
||||
src/render/vertex_array.cpp: 83.1% lines (49/59) is below the 95% per-file floor
|
||||
src/text/true_type_font.cpp: 92.8% lines (270/291) is below the 95% per-file floor
|
||||
$ echo $?
|
||||
1
|
||||
# The same, for the aggregate: a target above the measured aggregate fails with one line.
|
||||
python3 tools/coverage_floor.py --aggregate 99 build/cov/coverage.info
|
||||
# coverage_floor: FAILED -- 1 floor(s) violated in build/cov/coverage.info:
|
||||
# src/ aggregate: <rate>% lines (<hit>/<found>) is below the 99% aggregate floor
|
||||
# $? == 1
|
||||
|
||||
$ python3 tools/coverage_floor.py --per-file 60 --aggregate 90 build/cov/coverage.info
|
||||
coverage_floor: ok -- 23 files under src/, aggregate 92.9% lines (3203/3447), every file at or
|
||||
above 60%, aggregate target 90%
|
||||
$ echo $?
|
||||
0
|
||||
# A floor at or below the measured rates passes.
|
||||
python3 tools/coverage_floor.py build/cov/coverage.info
|
||||
# coverage_floor: ok -- ...
|
||||
# $? == 0
|
||||
```
|
||||
|
||||
## Why the check is a CMake target and not a ctest case
|
||||
|
||||
Reference in new issue
Block a user