test: Add test coverage for 16 files (40.3% → 45.5%) (#463)

* test: Add test coverage for 16 files (40.3% -> 45.5%)

Add comprehensive tests for previously untested packages:
- internal/agent/state_test.go
- internal/cmd/errors_test.go
- internal/crew/types_test.go
- internal/doctor/errors_test.go
- internal/dog/types_test.go
- internal/mail/bd_test.go
- internal/opencode/plugin_test.go
- internal/rig/overlay_test.go
- internal/runtime/runtime_test.go
- internal/session/town_test.go
- internal/style/style_test.go
- internal/ui/markdown_test.go
- internal/ui/terminal_test.go
- internal/wisp/io_test.go
- internal/wisp/types_test.go
- internal/witness/types_test.go

style_test.go uses func(...string) to match lipgloss variadic Render signature.

* fix(lint): remove unused error return from buildCVSummary

buildCVSummary always returned nil for its error value, causing
golangci-lint to fail with "result 1 (error) is always nil".

The function handles errors internally by returning partial data,
so the error return was misleading. Removed it and updated caller.
This commit is contained in:
Daniel Sauer
2026-01-13 22:19:27 +01:00
committed by GitHub
parent f42ec42268
commit fdd4b0aeb0
16 changed files with 2659 additions and 0 deletions

148
internal/dog/types_test.go Normal file
View File

@@ -0,0 +1,148 @@
package dog
import (
"encoding/json"
"testing"
"time"
)
func TestState_Constants(t *testing.T) {
tests := []struct {
name string
state State
want string
}{
{"idle state", StateIdle, "idle"},
{"working state", StateWorking, "working"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if string(tt.state) != tt.want {
t.Errorf("State constant = %q, want %q", tt.state, tt.want)
}
})
}
}
func TestDog_ZeroValues(t *testing.T) {
var dog Dog
// Test zero value behavior
if dog.Name != "" {
t.Errorf("zero value Dog.Name should be empty, got %q", dog.Name)
}
if dog.State != "" {
t.Errorf("zero value Dog.State should be empty, got %q", dog.State)
}
if dog.Worktrees == nil {
// Worktrees is a map, nil is expected for zero value
} else if len(dog.Worktrees) != 0 {
t.Errorf("zero value Dog.Worktrees should be empty, got %d items", len(dog.Worktrees))
}
}
func TestDogState_JSONMarshaling(t *testing.T) {
now := time.Now().Round(time.Second)
dogState := DogState{
Name: "test-dog",
State: StateWorking,
LastActive: now,
Work: "hq-abc123",
Worktrees: map[string]string{"gastown": "/path/to/worktree"},
CreatedAt: now,
UpdatedAt: now,
}
// Marshal to JSON
data, err := json.Marshal(dogState)
if err != nil {
t.Fatalf("json.Marshal() error = %v", err)
}
// Unmarshal back
var unmarshaled DogState
if err := json.Unmarshal(data, &unmarshaled); err != nil {
t.Fatalf("json.Unmarshal() error = %v", err)
}
if unmarshaled.Name != dogState.Name {
t.Errorf("After round-trip: Name = %q, want %q", unmarshaled.Name, dogState.Name)
}
if unmarshaled.State != dogState.State {
t.Errorf("After round-trip: State = %q, want %q", unmarshaled.State, dogState.State)
}
if unmarshaled.Work != dogState.Work {
t.Errorf("After round-trip: Work = %q, want %q", unmarshaled.Work, dogState.Work)
}
}
func TestDogState_OmitEmptyFields(t *testing.T) {
dogState := DogState{
Name: "test-dog",
State: StateIdle,
LastActive: time.Now(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
// Work and Worktrees left empty to test omitempty
}
data, err := json.Marshal(dogState)
if err != nil {
t.Fatalf("json.Marshal() error = %v", err)
}
// Check that empty fields are omitted
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
t.Fatalf("json.Unmarshal() to map error = %v", err)
}
if _, exists := raw["work"]; exists {
t.Error("Field 'work' should be omitted when empty")
}
if _, exists := raw["worktrees"]; exists {
t.Error("Field 'worktrees' should be omitted when empty")
}
// Required fields should be present
requiredFields := []string{"name", "state", "last_active", "created_at", "updated_at"}
for _, field := range requiredFields {
if _, exists := raw[field]; !exists {
t.Errorf("Required field '%s' should be present", field)
}
}
}
func TestDogState_WithWorktrees(t *testing.T) {
dogState := DogState{
Name: "alpha",
State: StateWorking,
Worktrees: map[string]string{"gastown": "/path/1", "beads": "/path/2"},
}
data, err := json.Marshal(dogState)
if err != nil {
t.Fatalf("json.Marshal() error = %v", err)
}
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
t.Fatalf("json.Unmarshal() to map error = %v", err)
}
worktrees, exists := raw["worktrees"]
if !exists {
t.Fatal("Field 'worktrees' should be present when non-empty")
}
// Verify it's a map
worktreesMap, ok := worktrees.(map[string]interface{})
if !ok {
t.Fatal("worktrees should be a JSON object")
}
if len(worktreesMap) != 2 {
t.Errorf("worktrees should have 2 entries, got %d", len(worktreesMap))
}
}