Files
kite 840f85f9bc test: raise statement coverage to 90% and enforce it in CI (#747)
* test: raise statement coverage to 90% and enforce it in CI

Add unit tests across the cmd and internal packages to bring total
statement coverage above 90%, and gate future regressions.

- Cover CLI helpers, provider TUI handlers, resume/manifest paths, and
  error branches in config, llm, llmloop, scan, session, agent, viewer,
  mcp, pathutil, and telemetry.
- Raise the coverage threshold from 80% to 90% in the Makefile
  (COVERAGE_THRESHOLD) and in the CI "Check coverage threshold" step.
- Ignore generated coverage.out and coverage.html artifacts.

Total statement coverage is now 90.5%, measured consistently by both
`make coverage` and the CI `go test ./...` scope.

* test: widen statement coverage margin with environment-independent unit tests

Add table-driven unit tests for pure, environment-independent functions to
raise the statement-coverage safety margin above the 90% threshold:

- session.ResumeState.ValidateScanOptions (70% -> 100%)
- rules.SystemRule.UnmarshalJSON error branches (71% -> 82%)
- llmloop.stripMarkdownFences no-newline branch (82% -> 100%)
- diff.firstLine empty/blank-input branch
- diff.extractCodeBlock missing-newline and no-closing-fence branches
- main.truncate n<=1 and normalization branches
- agent.Agent nil-receiver accessor guards
2026-08-06 12:55:44 +08:00

98 lines
3.3 KiB
Go

// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 alibaba/open-code-review Contributors
package session
import (
"errors"
"testing"
)
// TestManifestBuilderNilReceiver covers the `if b == nil` guard on every
// exported ManifestBuilder method: a nil builder must never panic, the mutating
// error-returning methods return errNilBuilder, and the boolean/void methods
// degrade quietly.
func TestManifestBuilderNilReceiver(t *testing.T) {
var b *ManifestBuilder
// Void setters: must not panic on a nil receiver.
b.SetParentRunID("parent")
b.SetRepository(ManifestRepository{})
b.SetInput(ManifestInput{Mode: InputModeWorkspace})
b.SetExecution(ManifestExecution{})
// Error-returning methods: must report errNilBuilder.
errReturners := map[string]error{
"SetRunFailure": b.SetRunFailure(RunFailureBudget, "r"),
"SetPendingFailureCause": b.SetPendingFailureCause(FailureBudget, "r"),
"RegisterSelected": b.RegisterSelected(CoverageItem{ItemID: "a"}),
"SealSelected": b.SealSelected(),
"MarkCompleted": b.MarkCompleted("a"),
"MarkReused": b.MarkReused("a"),
"MarkFailed": b.MarkFailed("a", FailureProvider, "r"),
"MarkWaived": b.MarkWaived("a", "r"),
}
for name, err := range errReturners {
if !errors.Is(err, errNilBuilder) {
t.Errorf("%s on nil builder: got %v, want errNilBuilder", name, err)
}
}
if _, err := b.Finalize(0); !errors.Is(err, errNilBuilder) {
t.Errorf("Finalize on nil builder: got %v, want errNilBuilder", err)
}
// Boolean predicates: must report false on a nil receiver.
if b.Sealed() {
t.Error("Sealed on nil builder should be false")
}
if b.Frozen() {
t.Error("Frozen on nil builder should be false")
}
}
// TestManifestBuilderFrozenNoOp covers the frozen-branch no-ops of the void
// setters and the errFrozen paths of the mutating methods after Finalize has
// frozen the builder.
func TestManifestBuilderFrozenNoOp(t *testing.T) {
b := NewManifestBuilder("run-frozen", "review")
b.SetInput(ManifestInput{Mode: InputModeWorkspace})
b.SetParentRunID("orig-parent")
if _, err := b.Finalize(0); err != nil {
t.Fatalf("Finalize: %v", err)
}
if !b.Frozen() {
t.Fatal("builder should be frozen after Finalize")
}
// Void setters must silently no-op once frozen (no panic, no mutation).
b.SetParentRunID("changed")
b.SetRepository(ManifestRepository{})
b.SetInput(ManifestInput{Mode: InputModeCommit})
b.SetExecution(ManifestExecution{})
// Mutating methods must report errFrozen.
frozenReturners := map[string]error{
"SetRunFailure": b.SetRunFailure(RunFailureBudget, "r"),
"SetPendingFailureCause": b.SetPendingFailureCause(FailureBudget, "r"),
"RegisterSelected": b.RegisterSelected(CoverageItem{ItemID: "z"}),
"SealSelected": b.SealSelected(),
"MarkCompleted": b.MarkCompleted("a"),
}
for name, err := range frozenReturners {
if !errors.Is(err, errFrozen) {
t.Errorf("%s after freeze: got %v, want errFrozen", name, err)
}
}
// The frozen manifest must still report the original parent, proving the
// post-freeze SetParentRunID was a no-op.
m, err := b.Finalize(0)
if err != nil {
t.Fatalf("idempotent Finalize: %v", err)
}
if m.ParentRunID != "orig-parent" {
t.Errorf("parent_run_id = %q, want unchanged %q", m.ParentRunID, "orig-parent")
}
}