Skip to content

test: drive coverage to the code that could not prove itself - #68

Merged
bgard68 merged 1 commit into
mainfrom
test/coverage-push
Aug 24, 2026
Merged

test: drive coverage to the code that could not prove itself#68
bgard68 merged 1 commit into
mainfrom
test/coverage-push

Conversation

@bgard68

@bgard68 bgard68 commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Coverage was never measured in this repository. First measurement: backend 77.6%, frontend 87.9%. After this PR: backend 92.4%, frontend 95% (authored code; generated *.g.cs/*.generated.cs, bootstrap main.tsx, and type-only models.ts excluded as not-authored).

Tests: backend 218 → 265, frontend 22 → 27. None of it is padding — each addition reaches a path that previously ran only in production:

The OpenAI live path was unprovable offline (14%)

The provider built its ChatClient internally, so everything between "request sent" and "containment gate" could not run under test. The one line that leaves the process is now an injectable delegate (CompleteChat); the public constructor wraps the real client, an internal one substitutes transport. The replay corpus now drives the entire provider — all ten recorded replies, injection cases included, must produce the user-visible outcome their gate verdict implies. Plus: prompt content, context truncation, timeout envelope, malformed JSON, transport failure, missing key.

The GitHub layer was 4–65% covered

Reader, token provider and action-reference resolver are faked at the HttpClient layer, so the real request pipeline executes: URL construction, bearer headers, allowlist refusals before any request, base64 decoding, annotated-tag dereferencing, branch fallback, and the tag-loop ceiling. The token cache is pinned in both directions: fresh token → no second exchange; nearly-expired → must exchange.

/api/github endpoints were structurally untestable

Program read GitHubOptions from configuration before Build() — and WebApplicationFactory configuration lands after that read, so the endpoints captured a snapshot no test host could influence. Options now resolve from DI per request (one source of truth; the captured copy could disagree with the container's if registration ever changed). Ten integration tests now cover the status ladder, 403 allowlist refusals, 404s, and analysis of retrieved content with and without AI.

Frontend

The unlock flow — including the wrong-key-stored-as-though-it-worked regression this app actually had — lock/clear, and the export download path (server-supplied filename, object-URL lifecycle, failure without download).

Async methods: verified, not assumed

Inventory against the pre-refactor baseline: 20 async methods then, 22 now, zero removed (the two added are the public-scan pair). CS1998/CS4014 remain unsuppressed under TreatWarningsAsErrors, so a silently de-asynced or unawaited method fails the build — the guarantee holds going forward.

Verification

265 + 27 = 292 tests, all green, 0 warnings. Full suite run after every structural change.

Backend authored-code line coverage 77.6% -> 92.4%; frontend 87.9% -> 95%.
Backend tests 218 -> 265, frontend 22 -> 27. Not padding — every addition
exercises a path that previously ran only in production:

The OpenAI live path (14% covered) constructed its ChatClient internally, so
everything between "request sent" and "containment gate" was unprovable
offline. The one line that leaves the process is now an injectable delegate,
and the full pipeline — prompt assembly, timeout envelope, deserialization,
gate, every fallback — runs under test. The replay corpus now drives the whole
provider: all ten recorded replies, including the injection cases, must reach
the same user-visible outcome the gate verdict implies.

The GitHub layer (reader 4%, token provider 13%, resolver 65%) is faked at the
HttpClient layer so real URL construction, auth headers, allowlist gates,
base64 decoding, annotated-tag walks and the tag-loop ceiling all execute.
The token cache is pinned: a fresh token makes no second exchange, a
nearly-expired one must.

The /api/github endpoints could not be integration-tested at all: Program read
GitHubOptions from configuration before Build(), so the endpoints captured a
snapshot no test host could influence. Options now resolve from DI per
request — one source of truth — and ten endpoint tests cover the status
ladder, allowlist refusals, and analysis of retrieved content.

Frontend: the unlock flow (including the wrong-key regression this app
actually had), lock/clear, and the export download path.

Measured with the built-in collector, generated code (*.g.cs, *.generated.cs)
excluded as not-authored. Honest remainder: bootstrap main.tsx, type-only
models.ts, Kestrel/CORS wiring in Program, and defensive branches whose
triggers are not constructible in-process.

Async inventory verified against the pre-refactor baseline: 20 methods then,
22 now, zero removed — and CS1998/CS4014 stay unsuppressed under
TreatWarningsAsErrors, so a silently de-asynced method fails the build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

public void Dispose()
{
try { Directory.Delete(_keyDirectory, recursive: true); } catch { /* best effort */ }
@bgard68
bgard68 merged commit 25f0895 into main Aug 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants