Files
gastown/internal/agent/state_test.go
Daniel Sauer fdd4b0aeb0 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.
2026-01-13 13:19:27 -08:00

190 lines
4.7 KiB
Go

package agent
import (
"os"
"path/filepath"
"testing"
)
func TestStateConstants(t *testing.T) {
tests := []struct {
name string
state State
value string
}{
{"StateStopped", StateStopped, "stopped"},
{"StateRunning", StateRunning, "running"},
{"StatePaused", StatePaused, "paused"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if string(tt.state) != tt.value {
t.Errorf("State constant = %q, want %q", tt.state, tt.value)
}
})
}
}
func TestStateManager_StateFile(t *testing.T) {
tmpDir := t.TempDir()
manager := NewStateManager[TestState](tmpDir, "test-state.json", func() *TestState {
return &TestState{Value: "default"}
})
expectedPath := filepath.Join(tmpDir, ".runtime", "test-state.json")
if manager.StateFile() != expectedPath {
t.Errorf("StateFile() = %q, want %q", manager.StateFile(), expectedPath)
}
}
func TestStateManager_Load_NoFile(t *testing.T) {
tmpDir := t.TempDir()
manager := NewStateManager[TestState](tmpDir, "nonexistent.json", func() *TestState {
return &TestState{Value: "default"}
})
state, err := manager.Load()
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if state.Value != "default" {
t.Errorf("Load() value = %q, want %q", state.Value, "default")
}
}
func TestStateManager_Load_Save_Load(t *testing.T) {
tmpDir := t.TempDir()
manager := NewStateManager[TestState](tmpDir, "test-state.json", func() *TestState {
return &TestState{Value: "default"}
})
// Save initial state
state := &TestState{Value: "test-value", Count: 42}
if err := manager.Save(state); err != nil {
t.Fatalf("Save() error = %v", err)
}
// Load it back
loaded, err := manager.Load()
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if loaded.Value != state.Value {
t.Errorf("Load() value = %q, want %q", loaded.Value, state.Value)
}
if loaded.Count != state.Count {
t.Errorf("Load() count = %d, want %d", loaded.Count, state.Count)
}
}
func TestStateManager_Load_CreatesDirectory(t *testing.T) {
tmpDir := t.TempDir()
manager := NewStateManager[TestState](tmpDir, "test-state.json", func() *TestState {
return &TestState{Value: "default"}
})
// Save should create .runtime directory
state := &TestState{Value: "test"}
if err := manager.Save(state); err != nil {
t.Fatalf("Save() error = %v", err)
}
// Verify directory was created
runtimeDir := filepath.Join(tmpDir, ".runtime")
if _, err := os.Stat(runtimeDir); err != nil {
t.Errorf("Save() should create .runtime directory: %v", err)
}
}
func TestStateManager_Load_InvalidJSON(t *testing.T) {
tmpDir := t.TempDir()
manager := NewStateManager[TestState](tmpDir, "test-state.json", func() *TestState {
return &TestState{Value: "default"}
})
// Write invalid JSON
statePath := manager.StateFile()
if err := os.MkdirAll(filepath.Dir(statePath), 0755); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
if err := os.WriteFile(statePath, []byte("invalid json"), 0644); err != nil {
t.Fatalf("Failed to write file: %v", err)
}
_, err := manager.Load()
if err == nil {
t.Error("Load() with invalid JSON should return error")
}
}
func TestState_String(t *testing.T) {
tests := []struct {
state State
want string
}{
{StateStopped, "stopped"},
{StateRunning, "running"},
{StatePaused, "paused"},
}
for _, tt := range tests {
if string(tt.state) != tt.want {
t.Errorf("State(%q) = %q, want %q", tt.state, string(tt.state), tt.want)
}
}
}
func TestStateManager_GenericType(t *testing.T) {
// Test that StateManager works with different types
type ComplexState struct {
Name string `json:"name"`
Values []int `json:"values"`
Enabled bool `json:"enabled"`
Nested struct {
X int `json:"x"`
} `json:"nested"`
}
tmpDir := t.TempDir()
manager := NewStateManager[ComplexState](tmpDir, "complex.json", func() *ComplexState {
return &ComplexState{Name: "default", Values: []int{}}
})
original := &ComplexState{
Name: "test",
Values: []int{1, 2, 3},
Enabled: true,
}
original.Nested.X = 42
if err := manager.Save(original); err != nil {
t.Fatalf("Save() error = %v", err)
}
loaded, err := manager.Load()
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if loaded.Name != original.Name {
t.Errorf("Name = %q, want %q", loaded.Name, original.Name)
}
if len(loaded.Values) != len(original.Values) {
t.Errorf("Values length = %d, want %d", len(loaded.Values), len(original.Values))
}
if loaded.Enabled != original.Enabled {
t.Errorf("Enabled = %v, want %v", loaded.Enabled, original.Enabled)
}
if loaded.Nested.X != original.Nested.X {
t.Errorf("Nested.X = %d, want %d", loaded.Nested.X, original.Nested.X)
}
}
// TestState is a simple type for testing
type TestState struct {
Value string `json:"value"`
Count int `json:"count"`
}