Record test coverage and effectiveness audit findings
This commit is contained in:
281
docs/roadmap/testing.md
Normal file
281
docs/roadmap/testing.md
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
# Test Coverage And Effectiveness Audit
|
||||||
|
|
||||||
|
Reviewed revision: `eb5a82f1f3a3286506c2d527e7980db7ccae5398`.
|
||||||
|
Audit date: 2026-10-25.
|
||||||
|
|
||||||
|
## Assessment And Architecture
|
||||||
|
|
||||||
|
The suite broadly follows the [testing policy](../policy/testing.md): real
|
||||||
|
parsing, composition, decoding, and filesystem fixtures dominate; narrow doubles
|
||||||
|
control I/O and environment failures. Engine tests own mechanisms and semantics,
|
||||||
|
root tests protect public conversions and integration, and maintained consumers
|
||||||
|
exercise representative workflows. The private document tree and YAML adapter
|
||||||
|
support the synchronous engine behind the root-owned public facade; see the
|
||||||
|
[component overview](../internal/overview.md).
|
||||||
|
|
||||||
|
Strengths include presence/default/zero distinctions, strict composition versus
|
||||||
|
precedence, collection policy, inheritance/history agreement, safe rendering and
|
||||||
|
bilateral diff sensitivity, independent loads, reader claims, callback ordering,
|
||||||
|
bootstrap partial failures, and realistic source/containment behavior. Parser and
|
||||||
|
path fuzz targets have deterministic seeds in the ordinary suite. Architecture,
|
||||||
|
documentation, and development-check tests protect explicit repository contracts.
|
||||||
|
|
||||||
|
Six targeted findings follow: four coverage/assertion improvements and two areas
|
||||||
|
for removal or consolidation. They do not justify a wholesale test purge, a
|
||||||
|
percentage target, or another test for every private helper. No new production
|
||||||
|
defect was established during this pass; the existing audits own their findings.
|
||||||
|
|
||||||
|
## Coverage Evidence
|
||||||
|
|
||||||
|
On Go 1.26.10, Linux amd64, the ordinary suite listed 771 `Test` functions, three
|
||||||
|
fuzz targets, and 29 executable examples. These counts exclude Windows-only
|
||||||
|
compiled tests and do not count table cases as separate test functions.
|
||||||
|
|
||||||
|
Cross-package coverage, aggregated by source block across all test binaries, was:
|
||||||
|
|
||||||
|
| Package | Covered statements | Coverage |
|
||||||
|
| --- | ---: | ---: |
|
||||||
|
| Root public package | 348 / 428 | 81.3% |
|
||||||
|
| `internal/engine` | 9,089 / 9,987 | 91.0% |
|
||||||
|
| `internal/document` | 13 / 13 | 100.0% |
|
||||||
|
| `internal/yaml` | 151 / 168 | 89.9% |
|
||||||
|
| Maintained consumer examples | 259 / 327 | 79.2% |
|
||||||
|
| Total | 9,860 / 10,923 | 90.3% |
|
||||||
|
|
||||||
|
The document package has no standalone tests, but its code is covered through
|
||||||
|
real collaborators. The per-test-binary percentages printed by `-coverpkg=./...`
|
||||||
|
have a different denominator and must not be mistaken for these aggregate
|
||||||
|
package percentages. Statement coverage measures execution, not assertion
|
||||||
|
strength or state-space coverage: the current suite passes despite the defects
|
||||||
|
already recorded in the correctness, resource, error-handling, and security audits.
|
||||||
|
|
||||||
|
Some zero-coverage private functions have no production caller; trivial public
|
||||||
|
preset forwards are also unexecuted. Neither observation alone warrants adding
|
||||||
|
tests. Prioritize the behavioral risks below over filling those percentages.
|
||||||
|
|
||||||
|
## 1. Confirmed Exceptional Cases Lack Durable Regression Coverage
|
||||||
|
|
||||||
|
Status: open. Priority: medium. Category: gaps in state transitions and boundaries.
|
||||||
|
|
||||||
|
The earlier audits reproduced defects outside the checked-in suite. Relevant
|
||||||
|
tests exercise nearby ordinary cases but do not yet protect these transitions:
|
||||||
|
|
||||||
|
- **Schema and dynamic-value failure state.**
|
||||||
|
[schema_test.go](../../internal/engine/schema_test.go) covers ordinary recursive
|
||||||
|
structs; [projection_test.go](../../internal/engine/projection_test.go) checks
|
||||||
|
independent invalid values and cycles. Neither covers pointer-only recursive
|
||||||
|
descriptors, acyclic slice views sharing a starting pointer, or a second
|
||||||
|
dynamic/helper operation after a failed descriptor build in the same load.
|
||||||
|
Add the narrowly scoped regressions described by
|
||||||
|
[correctness findings 1–3](correctness.md), retaining null/acyclic success cases
|
||||||
|
and asserting safe classification and termination. Avoid an unbounded
|
||||||
|
stack-overflow/hang fixture in the default test process.
|
||||||
|
- **Exceptional callback exit.** The retained-context tests in
|
||||||
|
[resolution_test.go](../../internal/engine/resolution_test.go) and
|
||||||
|
[facade_context_test.go](../../facade_context_test.go) verify normal callback
|
||||||
|
return. File-close tests cover ordinary load failures. They do not exercise
|
||||||
|
external recovery after version/resolution/validation callback panic or an
|
||||||
|
imported version check while a host root is owned. Extend the existing owners
|
||||||
|
when fixing [correctness finding 4](correctness.md#4-callback-contexts-remain-active-after-panic-unwinding)
|
||||||
|
and [resource finding 3](resources.md#3-an-imported-version-check-panic-leaves-the-host-root-open).
|
||||||
|
Preserve propagation of the original panic and verify closure of the callback
|
||||||
|
state and the actually owned root independently; a native file-close counter
|
||||||
|
alone cannot verify an `os.Root` lifetime.
|
||||||
|
- **Budgets before allocation and through publication.**
|
||||||
|
`TestProjectionRejectsNonFiniteLimitsAndCodecFailuresSafely` checks a small
|
||||||
|
scalar tree against supplied limits. `TestHistoryNodeBudgetCountsSharedTreesOnce`
|
||||||
|
and the inheritance-history budget tests verify the accounting helper with
|
||||||
|
explicitly supplied roots. They cannot detect a container reservation before
|
||||||
|
charging, or roots omitted by the publication caller. Add bounded regressions
|
||||||
|
with [resource findings 1–2](resources.md): oversized zero-sized-element input
|
||||||
|
can avoid a huge input allocation, and a small controlled history allowance can
|
||||||
|
test the complete retained-root boundary. Keep count-once sharing coverage;
|
||||||
|
do not allocate millions of nodes just to cross the production default.
|
||||||
|
- **Nested finite link expansion.**
|
||||||
|
[filesystem_links_test.go](../../internal/engine/filesystem_links_test.go) and
|
||||||
|
the public finite-reuse test cover simple reuse and actual cycles, but not the
|
||||||
|
compact repeated-dependency graph in [security finding 1](security.md#1-finite-symlink-reuse-can-cause-exponential-import-resolution-work).
|
||||||
|
When that remediation is selected, use a small real link fixture and a bounded
|
||||||
|
operation observer at the filesystem boundary. Protect finite reuse and
|
||||||
|
nonrecursive discovery without running an exhaustion workload or adding a
|
||||||
|
wall-clock performance threshold.
|
||||||
|
|
||||||
|
These are test accompaniments to the original remediation owners, not duplicate
|
||||||
|
product fixes or a request for a broad new cross-product matrix. The existing
|
||||||
|
tests should remain where they protect distinct ordinary behavior.
|
||||||
|
|
||||||
|
## 2. Public Historical-Path Enumeration Is Not Exercised
|
||||||
|
|
||||||
|
Status: open. Priority: medium. Category: public facade integration.
|
||||||
|
|
||||||
|
**Relevant code/tests.** `Metadata.HistoricalPaths` in
|
||||||
|
[metadata.go](../../metadata.go), lines 49–56, has zero executed statements in
|
||||||
|
the aggregate profile. Every checked-in `HistoricalPaths` test call is in the
|
||||||
|
engine package. `TestMetadataHistoricalPaths` in
|
||||||
|
[metadata_test.go](../../internal/engine/metadata_test.go) thoroughly covers the
|
||||||
|
engine method, including removed descendants, escapes, contextual numeric
|
||||||
|
tokens, and detached results, but does not cross the public conversion.
|
||||||
|
|
||||||
|
**Risk.** Returning no paths or incorrectly converting the numeric segment intent
|
||||||
|
at the root boundary could leave that engine suite green while breaking the
|
||||||
|
documented consumer enumeration/query workflow. Coverage of `History` and
|
||||||
|
`Lookup` separately does not exercise enumeration's result conversion.
|
||||||
|
|
||||||
|
**Improvement.** Add one small external-package public-API test that enumerates
|
||||||
|
effective and removed paths, then uses the returned paths with `Lookup` and
|
||||||
|
`History`, including a numeric-key/sequence shape change. Check sorted unique
|
||||||
|
pointer spelling, zero metadata, and replacement of a returned slice element
|
||||||
|
without affecting later queries. Keep detailed path mutation and engine shape
|
||||||
|
cases with their existing owner; do not duplicate the complete internal matrix
|
||||||
|
or expose private segments to test the facade.
|
||||||
|
|
||||||
|
## 3. Native-Filesystem Failure Tests Observe Too Little
|
||||||
|
|
||||||
|
Status: open. Priority: medium. Category: doubles and inadequate assertions.
|
||||||
|
|
||||||
|
**Relevant tests.** `TestNativeFilesystemClosesFilesOnSuccessAndFailure`,
|
||||||
|
`observedFilesystem`, and `observedFile` in
|
||||||
|
[native_filesystem_test.go](../../internal/engine/native_filesystem_test.go),
|
||||||
|
especially lines 150–162 and 278–319. The fixture is also used by
|
||||||
|
`TestLoadingClosesNativeFilesAcrossPipelineOutcomes` in
|
||||||
|
[resource_context_test.go](../../internal/engine/resource_context_test.go).
|
||||||
|
|
||||||
|
**Deficiencies and plausible survivors.**
|
||||||
|
|
||||||
|
- Failure cases require only a non-nil error, not a nil result, the expected
|
||||||
|
diagnostic classification, or evidence identifying the intended failed
|
||||||
|
source. An unrelated early failure could satisfy the assertion.
|
||||||
|
- The non-disclosure check searches only `err.Error()` for the fixture canary.
|
||||||
|
`LoadError.Error` deliberately renders an error count, not diagnostic messages.
|
||||||
|
Accidentally forwarding the raw filesystem error into `Diagnostics()` could
|
||||||
|
therefore pass this check. The parser/callback canary tests cover different
|
||||||
|
failure-producing boundaries.
|
||||||
|
- `assertClosed` checks only total opens versus total `Close` calls. The counter
|
||||||
|
increments even for a repeated close, so one leaked handle and one double-close
|
||||||
|
can cancel out. It does not prove that each acquired handle was released.
|
||||||
|
- The double supplies immediate generic read/directory errors and successful
|
||||||
|
closes. It cannot model entries/data plus an error, or a close error whose
|
||||||
|
identity resembles absence. This leaves the
|
||||||
|
[directory failure-phase defect](error-handling.md#1-directory-read-and-close-failures-can-be-misclassified-as-absence)
|
||||||
|
unprotected on both the batched and fallback paths.
|
||||||
|
|
||||||
|
**Improvement.** Keep the real in-memory filesystem backing and small controlled
|
||||||
|
failure seams. Track each returned handle's close state, assert the relevant
|
||||||
|
structured load error and nil result, and inspect diagnostics/rendered diagnostics
|
||||||
|
for the canary. Add only the read/close phase cases needed by the existing
|
||||||
|
error-handling remediation, including a second successful directory so required
|
||||||
|
selection cannot mask the failed one. Preserve intentionally ignored read-only
|
||||||
|
regular-file close errors; do not invent a universal close-error contract.
|
||||||
|
|
||||||
|
## 4. Fuzz Detachment Assertions Miss Shared Descendants
|
||||||
|
|
||||||
|
Status: open. Priority: low. Category: ineffective ownership assertion.
|
||||||
|
|
||||||
|
**Relevant target.** `FuzzCompositionAndOverlay` in
|
||||||
|
[composition_fuzz_test.go](../../internal/engine/composition_fuzz_test.go),
|
||||||
|
lines 46–49 and 63–66, appends a new root mapping entry and then compares inputs
|
||||||
|
against their earlier copies to establish result detachment.
|
||||||
|
|
||||||
|
**Deficiency.** A shallow-copied root can still share existing entries, descendant
|
||||||
|
nodes, or sequence backing storage. Appending through the copied root's slice
|
||||||
|
header changes neither the input's header nor its existing elements; even reuse
|
||||||
|
of the backing array writes beyond the input's old length. The comparison can
|
||||||
|
pass while the result still shares mutable descendants. It primarily detects
|
||||||
|
aliasing the root object itself, not the deeper ownership property in its error
|
||||||
|
message.
|
||||||
|
|
||||||
|
**Improvement.** Within the existing bounded target, mutate an existing result
|
||||||
|
descendant or an element inside the original slice length, then check both
|
||||||
|
inputs. Keep empty-container cases separate and retain the existing input
|
||||||
|
immutability and commutativity properties. Deterministic tests in
|
||||||
|
[compose_test.go](../../internal/engine/compose_test.go),
|
||||||
|
[overlay_test.go](../../internal/engine/overlay_test.go), and
|
||||||
|
[recursive_merge_test.go](../../internal/engine/recursive_merge_test.go) already
|
||||||
|
give meaningful nested-mutation protection; improve the fuzz assertion rather
|
||||||
|
than adding a parallel matrix or claiming all ownership coverage is absent.
|
||||||
|
|
||||||
|
## 5. Remove Exact Stat-Call Choreography From The Ordering Test
|
||||||
|
|
||||||
|
Status: open. Priority: low. Category: removal/rewrite candidate.
|
||||||
|
|
||||||
|
`TestSelectNamedImportsChecksNormalizedPathsLexically` in
|
||||||
|
[import_selection_test.go](../../internal/engine/import_selection_test.go),
|
||||||
|
lines 151–166, asserts the exact trace `a.yaml,a.yaml,z.yaml,z.yaml`.
|
||||||
|
|
||||||
|
Lexically ordered target handling is meaningful. Performing exactly two `Stat`
|
||||||
|
calls per target is not an established requirement: reusing successful preflight
|
||||||
|
metadata or changing a filesystem helper could preserve selection, safe failure,
|
||||||
|
and ordering while failing this test. The selected-candidate assertion meanwhile
|
||||||
|
checks only the count, not the order or paths.
|
||||||
|
|
||||||
|
Remove the duplicated-stat trace expectation. Check ordered candidate paths and,
|
||||||
|
if first-failure order needs separate protection, the selected diagnostic site
|
||||||
|
using two failing targets. Consolidate that case into the existing selection
|
||||||
|
tests and delete this standalone test if its distinct protection is then
|
||||||
|
subsumed. Keep meaningful interaction assertions such as not opening excluded
|
||||||
|
file contents; those protect an actual resource/selection behavior.
|
||||||
|
|
||||||
|
## 6. Consolidate Redundant And Representation-Coupled Facade Scaffolding
|
||||||
|
|
||||||
|
Status: open. Priority: low. Category: removal/consolidation candidates.
|
||||||
|
|
||||||
|
- In [facade_compatibility_test.go](../../facade_compatibility_test.go), the
|
||||||
|
six-type package-ownership loop in `TestFacadeCompatibility` is a subset of
|
||||||
|
the comprehensive `TestFacadeValuesRemainRootOwned` loop in
|
||||||
|
[facade_candidate_test.go](../../facade_candidate_test.go). Remove the duplicate
|
||||||
|
loop while retaining the compile-time interface checks, public construction,
|
||||||
|
and any distinct lifecycle behavior. The runtime assertion that a freshly
|
||||||
|
constructed `Result.Config` still equals its literal field value adds no
|
||||||
|
protection beyond ordinary Go assignment and compilation.
|
||||||
|
- `TestWrappedPathsRetainEngineSegmentIntent` in
|
||||||
|
[facade_internal_test.go](../../facade_internal_test.go) compares private
|
||||||
|
`.value` representations for inequality. Distinct representations are not the
|
||||||
|
consumer contract; correct contextual mapping/index lookup is. Replace its
|
||||||
|
protection with public query behavior, coordinated with finding 2, then remove
|
||||||
|
the private-representation test. Keep the engine's own segment-intent tests.
|
||||||
|
- In that same file, `TestWrappedSourcesPreserveEngineOwnership` invokes
|
||||||
|
`engine.Load` directly through `source.toEngine()`. Its byte snapshot and
|
||||||
|
copied-reader risks are legitimate, but the facade test should use public
|
||||||
|
`Load` and root-owned errors. Consolidate overlapping reader behavior with
|
||||||
|
`TestRepeatedImportsAcrossTiersAndReaderConsumption` in
|
||||||
|
[facade_equivalence_test.go](../../facade_equivalence_test.go), preserving
|
||||||
|
explicit copied-source and byte-mutation coverage before deleting scaffolding.
|
||||||
|
- The clone portion of `TestSourceInfoDestinationConversionsAndCopies` in
|
||||||
|
[records_test.go](../../records_test.go), lines 39–42, replaces the whole copied
|
||||||
|
`Destination` field. A shallow struct copy passes this without proving nested
|
||||||
|
detachment. Remove that non-protective assertion or consolidate the relevant
|
||||||
|
returned-record ownership check into existing public source-snapshot tests;
|
||||||
|
retain conversion checks that protect fields at the facade boundary. `Path`
|
||||||
|
is opaque and immutable through its public builders, so exposing internals or
|
||||||
|
adding a new deep-copy guarantee is not justified by this test.
|
||||||
|
|
||||||
|
This is a small cleanup, not a recommendation to remove root integration tests
|
||||||
|
because the engine has tests. Public conversion, error typing, callback bridging,
|
||||||
|
source namespace identity, disclosure, and returned-record ownership have real
|
||||||
|
cross-package risks. The static public/dependency-boundary checks also protect
|
||||||
|
the expressly selected architecture and should remain.
|
||||||
|
|
||||||
|
## Validation And Limits Of This Review
|
||||||
|
|
||||||
|
The following passed using cached dependencies with automatic network/toolchain
|
||||||
|
acquisition disabled:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go test ./... -coverpkg=./... -covermode=atomic -coverprofile=/tmp/configkit-testing-audit.ZNsVuW/coverage.out -count=1
|
||||||
|
go tool cover -func=/tmp/configkit-testing-audit.ZNsVuW/coverage.out
|
||||||
|
go test ./... -shuffle=on -count=3
|
||||||
|
```
|
||||||
|
|
||||||
|
The profile stayed outside the repository. Coverage blocks were combined across
|
||||||
|
test binaries before calculating package totals. A separate JSON test run found
|
||||||
|
no individual skipped test/subtest on this Linux host; `internal/document` was
|
||||||
|
reported as having no standalone tests. This is not native macOS/Windows evidence.
|
||||||
|
Only the checked-in fuzz seeds were run; no extended fuzz campaign or mutation
|
||||||
|
testing was performed. Assertion weaknesses above are grounded in source-level
|
||||||
|
counterexamples, not a claimed measured mutation score.
|
||||||
|
|
||||||
|
No production code, tests, fixtures, dependencies, or release gates were changed.
|
||||||
|
Recommended additions should accompany the relevant fixes and existing test
|
||||||
|
owners. Use small controlled budgets and independent outcomes, retain selected
|
||||||
|
stable formatting/code/path contracts, and avoid making implementation details
|
||||||
|
or speculative guarantees into new policy through assertions.
|
||||||
Reference in New Issue
Block a user