- Add Warning field to CheckResult for soft failures - Implement runNixHashCheck() that detects go.sum changes - Warnings (⚠) shown separately from failures (✗) - Warnings don't fail the overall preflight result - Summary shows warning count separately - Add test for warning state 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Executed-By: beads/crew/dave Rig: beads Role: crew
186 lines
4.3 KiB
Go
186 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCheckResult_Passed(t *testing.T) {
|
|
r := CheckResult{
|
|
Name: "Tests pass",
|
|
Passed: true,
|
|
Command: "go test ./...",
|
|
Output: "",
|
|
}
|
|
|
|
if !r.Passed {
|
|
t.Error("Expected result to be passed")
|
|
}
|
|
if r.Name != "Tests pass" {
|
|
t.Errorf("Expected name 'Tests pass', got %q", r.Name)
|
|
}
|
|
}
|
|
|
|
func TestPrintCheckResult_Failed(t *testing.T) {
|
|
r := CheckResult{
|
|
Name: "tests",
|
|
Passed: false,
|
|
Command: "go test ./...",
|
|
Output: "--- FAIL: TestSomething\nexpected X got Y",
|
|
}
|
|
|
|
if r.Passed {
|
|
t.Error("Expected result to be failed")
|
|
}
|
|
if !strings.Contains(r.Output, "FAIL") {
|
|
t.Error("Expected output to contain FAIL")
|
|
}
|
|
}
|
|
|
|
func TestCheckResult_JSONFields(t *testing.T) {
|
|
r := CheckResult{
|
|
Name: "tests",
|
|
Passed: true,
|
|
Command: "go test -short ./...",
|
|
Output: "ok github.com/example/pkg 0.123s",
|
|
}
|
|
|
|
// Verify JSON struct tags are correct by checking field names
|
|
if r.Name == "" {
|
|
t.Error("Name should not be empty")
|
|
}
|
|
if r.Command == "" {
|
|
t.Error("Command should not be empty")
|
|
}
|
|
}
|
|
|
|
func TestPreflightResult_AllPassed(t *testing.T) {
|
|
results := PreflightResult{
|
|
Checks: []CheckResult{
|
|
{Name: "Tests pass", Passed: true, Command: "go test ./..."},
|
|
{Name: "Lint passes", Passed: true, Command: "golangci-lint run"},
|
|
},
|
|
Passed: true,
|
|
Summary: "2/2 checks passed",
|
|
}
|
|
|
|
if !results.Passed {
|
|
t.Error("Expected all checks to pass")
|
|
}
|
|
if len(results.Checks) != 2 {
|
|
t.Errorf("Expected 2 checks, got %d", len(results.Checks))
|
|
}
|
|
}
|
|
|
|
func TestPreflightResult_SomeFailed(t *testing.T) {
|
|
results := PreflightResult{
|
|
Checks: []CheckResult{
|
|
{Name: "Tests pass", Passed: true, Command: "go test ./..."},
|
|
{Name: "Lint passes", Passed: false, Command: "golangci-lint run", Output: "linting errors"},
|
|
},
|
|
Passed: false,
|
|
Summary: "1/2 checks passed",
|
|
}
|
|
|
|
if results.Passed {
|
|
t.Error("Expected some checks to fail")
|
|
}
|
|
|
|
passCount := 0
|
|
failCount := 0
|
|
for _, c := range results.Checks {
|
|
if c.Passed {
|
|
passCount++
|
|
} else {
|
|
failCount++
|
|
}
|
|
}
|
|
if passCount != 1 || failCount != 1 {
|
|
t.Errorf("Expected 1 pass and 1 fail, got %d pass and %d fail", passCount, failCount)
|
|
}
|
|
}
|
|
|
|
func TestPreflightResult_WithSkipped(t *testing.T) {
|
|
results := PreflightResult{
|
|
Checks: []CheckResult{
|
|
{Name: "Tests pass", Passed: true, Command: "go test ./..."},
|
|
{Name: "Lint passes", Passed: false, Skipped: true, Command: "golangci-lint run", Output: "not installed"},
|
|
},
|
|
Passed: true,
|
|
Summary: "1/1 checks passed (1 skipped)",
|
|
}
|
|
|
|
// Skipped checks don't count as failures
|
|
if !results.Passed {
|
|
t.Error("Expected result to pass (skipped doesn't count as failure)")
|
|
}
|
|
|
|
skipCount := 0
|
|
for _, c := range results.Checks {
|
|
if c.Skipped {
|
|
skipCount++
|
|
}
|
|
}
|
|
if skipCount != 1 {
|
|
t.Errorf("Expected 1 skipped, got %d", skipCount)
|
|
}
|
|
}
|
|
|
|
func TestPreflightResult_WithWarning(t *testing.T) {
|
|
results := PreflightResult{
|
|
Checks: []CheckResult{
|
|
{Name: "Tests pass", Passed: true, Command: "go test ./..."},
|
|
{Name: "Nix hash current", Passed: false, Warning: true, Command: "git diff HEAD -- go.sum", Output: "go.sum changed"},
|
|
},
|
|
Passed: true, // Warnings don't fail the overall result
|
|
Summary: "1/2 checks passed, 1 warning(s)",
|
|
}
|
|
|
|
// Warnings don't count as failures
|
|
if !results.Passed {
|
|
t.Error("Expected result to pass (warning doesn't count as failure)")
|
|
}
|
|
|
|
warnCount := 0
|
|
for _, c := range results.Checks {
|
|
if c.Warning {
|
|
warnCount++
|
|
}
|
|
}
|
|
if warnCount != 1 {
|
|
t.Errorf("Expected 1 warning, got %d", warnCount)
|
|
}
|
|
}
|
|
|
|
func TestTruncateOutput(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
maxLen int
|
|
wantTrunc bool
|
|
}{
|
|
{"short string", "hello world", 500, false},
|
|
{"exact length", strings.Repeat("x", 500), 500, false},
|
|
{"over length", strings.Repeat("x", 600), 500, true},
|
|
{"empty string", "", 500, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := truncateOutput(tt.input, tt.maxLen)
|
|
if tt.wantTrunc {
|
|
if !strings.Contains(result, "truncated") {
|
|
t.Error("Expected truncation marker in output")
|
|
}
|
|
if len(result) > tt.maxLen+20 { // allow some slack for marker
|
|
t.Errorf("Result too long: got %d chars", len(result))
|
|
}
|
|
} else {
|
|
if strings.Contains(result, "truncated") {
|
|
t.Error("Did not expect truncation marker")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|