Fixed the coverage report's paths and scoping - #664
Merged
fdesbiens merged 1 commit intoAug 25, 2026
Conversation
The Cobertura XML embedded absolute machine paths, and the flag that looked like it scoped the report to one build configuration was doing nothing at all. Both coverage.sh scripts had the defect; both are fixed here, because the SMP report is published to the same Pages site as the ThreadX one. Paths. -r was the build directory and -f pointed outside it, so gcovr could not express the sources relative to the root and fell back to absolute paths. The result named files as /home/runner/work/threadx/threadx/common/src/... while the <source> element beside them said build/default_build_coverage, so the two halves of the same file disagreed and nothing could map coverage back to the repository. -r is the repository root now and -f an absolute path beneath it, which gives filename="common/src/tx_block_allocate.c". Both must be absolute: -r ../../.. -f common/src produces a report of zero files and exits 0, which is the worst failure mode available here. Scoping. --object-directory does not restrict which gcda files are found -- it tells gcovr how to get from a gcda file back to the compiler's working directory. Pointed at an empty directory it still produced the full 177-file report. That was harmless only by accident, because -r build/$1 constrained the search instead; moving -r to the repository root removes that accident, so the two changes have to land together. Measured, with a second instrumented configuration deliberately made sparser than the first: scoped by the positional search path 3221 of 3827 lines -- the truth no search path, -r at the repo root 3827 of 3827 -- silently merged --object-directory at the sparse tree 3827 of 3827 -- scopes nothing So the search path is load-bearing, and it matters ahead of instrumenting all five configurations: without it each configuration would have reported the union as its own. An empty report is not an error to gcovr -- it warns and exits 0 -- and it carries line-rate="1.0" next to lines-valid="0", so a consumer reads no data at all as fully covered. No coverage threshold can catch that, since an empty report passes any threshold. Hence the explicit assertion that the report has content, which fires with exit 1 on an object directory that exists but is empty, where the old shape returned 177 files and exit 0. Also says out loud that ports/linux/gnu/src is deliberately outside the filter. gcno files exist for it and it is dropped without a word today. Number-neutral, and that was the test. Over the same frozen gcda, changing only the gcovr invocation: ThreadX 3827 of 3827 lines and 1993 of 1994 branches across 177 files, SMP 4739 of 4791 and 2417 of 2430 across 185, before and after alike. Same answers on gcovr 7.0, 8.3 and 8.6, so the change is not wedged to the current pin. End to end through run.sh, 96 of 96 and 110 of 110 pass with the reports written. Assisted-by: Claude Opus 5 <noreply@anthropic.com>
fdesbiens
added a commit
that referenced
this pull request
Aug 26, 2026
The coverage summary reported a percentage and could not fail. Coverage could fall from 99.97% to anything at all and every check stayed green, against an AGENTS.md that asks for 100% test coverage -- a stated requirement measured with a gauge that had no failure mode. CodeCoverageSummary already takes thresholds and fail_below_min; neither was set. Both are now, through a new coverage_thresholds input on the template, because the two suites do not sit at the same figure: ThreadX 99, SMP 98. Three things were probed against the pinned action on a runner before picking those numbers, using the real merged.xml files from the dev push run of #666. The floor compares the line rate and nothing else. That mattered because branch coverage is around 78% in both suites while line coverage is 98.8-100%, so a floor aimed at the line figure would have been an immediate red wall had it tested branches or the lower of the two. The ThreadX report at 100.00% lines and 77.67% branches clears a floor of 99. The thresholds are whole numbers. '99.9 100' -- the value this was meant to be -- is rejected with 'System.ArgumentException - Threshold parameter set incorrectly.', and the step fails whether or not fail_below_min is set. So the choice is 99 or 100 with nothing between. 100 would fail on a race. tx_thread_system_resume.c:529 is reached by timing rather than by construction and flaps between runs of the same green tree, which is why #666 left it; 4502/4503 fails a floor of 100 and clears one of 99. A coverage gate that goes red on a coin toss is how coverage gates get switched off. SMP is 5114/5178 lines, 98.76%, with 64 uncovered lines across 11 files of common_smp/src -- #666 closed the equivalent gaps in common/src only. A shared floor of 99 would have failed that job on every run while ThreadX passed. One limit is recorded in the file rather than fixed: an empty report reads as 100%. gcovr writes line-rate="1.0" beside lines-valid="0" when it finds no data, and the action prints 'Line Rate = 100% (0 / 0)' and passes any floor. The check for that is the emptiness assertion #664 put in each suite's coverage.sh, not this one. Also corrected two stale filenames in the deploy job's comment: since #665 each coverage artifact carries merged.xml, not default_build_coverage.xml. Verified on the runner. Assisted-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Cobertura XML embeds absolute machine paths, and the flag that looks like it scopes the report to one build configuration is doing nothing at all. Both
coverage.shscripts carry the defect; both are fixed here, because the SMP report is published to the same Pages site as the ThreadX one.Paths
-rwas the build directory and-fpointed outside it, so gcovr could not express the sources relative to the root and fell back to absolute paths:The two halves of the same file disagree, and on a runner those paths are
/home/runner/work/threadx/threadx/..., so nothing that maps coverage back to the repository — PR annotations, Codecov, SonarQube — can follow them.irongut/CodeCoverageSummaryonly sums totals, which is why this has survived.-ris the repository root now and-fan absolute path beneath it, givingfilename="common/src/tx_block_allocate.c"under a<source>that agrees with it.Both have to be absolute.
-r ../../.. -f common/srcproduces a report of zero files and exits 0 — the worst failure mode available here, a green run carrying an empty report.Scoping
--object-directorydoes not restrict which.gcdafiles are found. It tells gcovr how to get from a.gcdafile back to the compiler's working directory. Pointed at an empty directory it still produced the full 177-file report, because gcovr searches-ras well.That was harmless only by accident:
-r build/$1constrained the search instead. Moving-rto the repository root removes the accident, so the two changes have to land together. Measured with a second instrumented configuration deliberately made sparser than the first:-rat the repo root--object-directoryat the sparse treeSo the positional search path is load-bearing, and it matters ahead of instrumenting all five configurations: without it, each configuration would report the union as its own.
An empty report reads as 100%
An empty report is not an error to gcovr — it warns and exits 0 — and it carries
line-rate="1.0"besidelines-valid="0":So a consumer reads no data at all as fully covered, and no coverage threshold can catch it, because an empty report passes any threshold. Hence the explicit assertion that the report has content. It fires with exit 1 on an object directory that exists but is empty — where the old shape returned 177 files and exit 0.
Also
Says out loud that
ports/linux/gnu/srcis deliberately outside the filter..gcnofiles exist for it and it is dropped today without a word.Verification
Number-neutral, and that was the test. Over the same frozen
.gcda, changing only the gcovr invocation:Comparing over frozen
.gcdarather than fresh runs is deliberate: the numerator moves run to run on its own. A later full run of the SMP suite reported 4741 rather than 4739 withlines-validunchanged at 4791, which is that same flicker and not this change.Same answers on gcovr 7.0, 8.3 and 8.6, so the change is not wedged to the current pin. End to end through
run.sh: 96 of 96 and 110 of 110 pass with the reports written.