Skip to content

Commit 9fdf4b5

Browse files
test(ui): add comprehensive unit test coverage
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 67b677b commit 9fdf4b5

5 files changed

Lines changed: 959 additions & 0 deletions

File tree

internal/ui/progress_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package ui
2+
3+
import (
4+
"sync"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestTruncate(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
input string
15+
maxLen int
16+
expected string
17+
}{
18+
{"within limit", "hello", 10, "hello"},
19+
{"exact limit", "hello", 5, "hello"},
20+
{"needs truncation with ellipsis", "hello world", 8, "hello..."},
21+
{"maxLen exactly 3", "hello", 3, "hel"},
22+
{"maxLen 4 adds ellipsis", "hello world", 4, "h..."},
23+
{"maxLen 2 no ellipsis", "hello", 2, "he"},
24+
{"empty string", "", 5, ""},
25+
{"empty string zero len", "", 0, ""},
26+
}
27+
28+
for _, tt := range tests {
29+
t.Run(tt.name, func(t *testing.T) {
30+
result := truncate(tt.input, tt.maxLen)
31+
assert.Equal(t, tt.expected, result)
32+
})
33+
}
34+
}
35+
36+
func TestFormatDuration(t *testing.T) {
37+
tests := []struct {
38+
name string
39+
input time.Duration
40+
expected string
41+
}{
42+
{"sub-second", 500 * time.Millisecond, "0.5s"},
43+
{"10 seconds", 10 * time.Second, "10.0s"},
44+
{"30.5 seconds", 30*time.Second + 500*time.Millisecond, "30.5s"},
45+
{"exactly 1 minute", 60 * time.Second, "1m0s"},
46+
{"1 minute 30 seconds", 90 * time.Second, "1m30s"},
47+
{"2 minutes", 120 * time.Second, "2m0s"},
48+
{"2 minutes 15 seconds", 135 * time.Second, "2m15s"},
49+
}
50+
51+
for _, tt := range tests {
52+
t.Run(tt.name, func(t *testing.T) {
53+
result := FormatDuration(tt.input)
54+
assert.Equal(t, tt.expected, result)
55+
})
56+
}
57+
}
58+
59+
func TestStickyProgressDefaults(t *testing.T) {
60+
sp := NewStickyProgress(10)
61+
62+
assert.Equal(t, 10, sp.total)
63+
assert.Equal(t, 0, sp.completed)
64+
assert.Equal(t, 0, sp.succeeded)
65+
assert.Equal(t, 0, sp.failed)
66+
assert.Equal(t, 0, sp.skipped)
67+
assert.False(t, sp.active)
68+
}
69+
70+
func TestStickyProgressIncrementWithStatus(t *testing.T) {
71+
sp := NewStickyProgress(5)
72+
73+
sp.IncrementWithStatus(true)
74+
sp.IncrementWithStatus(true)
75+
sp.IncrementWithStatus(false)
76+
77+
assert.Equal(t, 3, sp.completed)
78+
assert.Equal(t, 2, sp.succeeded)
79+
assert.Equal(t, 1, sp.failed)
80+
}
81+
82+
func TestStickyProgressIncrement(t *testing.T) {
83+
sp := NewStickyProgress(5)
84+
85+
sp.Increment()
86+
sp.Increment()
87+
88+
assert.Equal(t, 2, sp.completed)
89+
assert.Equal(t, 2, sp.succeeded)
90+
assert.Equal(t, 0, sp.failed)
91+
}
92+
93+
func TestStickyProgressSetSkipped(t *testing.T) {
94+
sp := NewStickyProgress(5)
95+
sp.SetSkipped(3)
96+
97+
assert.Equal(t, 3, sp.skipped)
98+
}
99+
100+
func TestStickyProgressCombined(t *testing.T) {
101+
sp := NewStickyProgress(10)
102+
103+
sp.Increment()
104+
sp.IncrementWithStatus(true)
105+
sp.IncrementWithStatus(false)
106+
sp.SetSkipped(4)
107+
108+
assert.Equal(t, 3, sp.completed)
109+
assert.Equal(t, 2, sp.succeeded)
110+
assert.Equal(t, 1, sp.failed)
111+
assert.Equal(t, 4, sp.skipped)
112+
}
113+
114+
func TestStickyProgressConcurrentSafety(t *testing.T) {
115+
const goroutines = 50
116+
sp := NewStickyProgress(goroutines * 2)
117+
118+
var wg sync.WaitGroup
119+
for i := 0; i < goroutines; i++ {
120+
wg.Add(2)
121+
go func() {
122+
defer wg.Done()
123+
sp.IncrementWithStatus(true)
124+
}()
125+
go func() {
126+
defer wg.Done()
127+
sp.IncrementWithStatus(false)
128+
}()
129+
}
130+
wg.Wait()
131+
132+
assert.Equal(t, goroutines*2, sp.completed)
133+
assert.Equal(t, goroutines, sp.succeeded)
134+
assert.Equal(t, goroutines, sp.failed)
135+
}
136+
137+
func TestStickyProgressSetCurrentDoesNotPanic(t *testing.T) {
138+
sp := NewStickyProgress(5)
139+
assert.NotPanics(t, func() {
140+
sp.SetCurrent("some-package")
141+
})
142+
}
143+
144+
func TestStickyProgressPauseResume(t *testing.T) {
145+
sp := NewStickyProgress(5)
146+
sp.mu.Lock()
147+
sp.active = true
148+
sp.mu.Unlock()
149+
150+
sp.PauseForInteractive()
151+
assert.False(t, sp.active)
152+
}

internal/ui/scanprogress_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package ui
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestFormatStepCount(t *testing.T) {
11+
tests := []struct {
12+
count int
13+
expected string
14+
}{
15+
{0, "0 found"},
16+
{1, "1 found"},
17+
{2, "2 found"},
18+
{100, "100 found"},
19+
}
20+
21+
for _, tt := range tests {
22+
result := formatStepCount(tt.count)
23+
assert.Equal(t, tt.expected, result)
24+
}
25+
}
26+
27+
func TestScanProgressFormatStepDuration(t *testing.T) {
28+
sp := &ScanProgress{}
29+
30+
tests := []struct {
31+
name string
32+
input time.Duration
33+
expected string
34+
}{
35+
{"zero", 0, "< 1s"},
36+
{"999ms", 999 * time.Millisecond, "< 1s"},
37+
{"exactly 1s", 1 * time.Second, "1.0s"},
38+
{"2.5s", 2500 * time.Millisecond, "2.5s"},
39+
{"10s", 10 * time.Second, "10.0s"},
40+
}
41+
42+
for _, tt := range tests {
43+
t.Run(tt.name, func(t *testing.T) {
44+
result := sp.formatStepDuration(tt.input)
45+
assert.Equal(t, tt.expected, result)
46+
})
47+
}
48+
}
49+
50+
func TestNewScanProgressInitialState(t *testing.T) {
51+
sp := NewScanProgress(5)
52+
defer close(sp.spinnerStop)
53+
54+
assert.Equal(t, 5, sp.totalSteps)
55+
assert.Equal(t, 5, len(sp.steps))
56+
assert.Equal(t, 0, sp.completedCount)
57+
58+
for _, s := range sp.steps {
59+
assert.Equal(t, "pending", s.status)
60+
}
61+
}

0 commit comments

Comments
 (0)