mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-09-14 19:59:52 +08:00
840f85f9bc
* 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
98 lines
3.3 KiB
Go
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")
|
|
}
|
|
}
|