Skip to content

Commit 903e501

Browse files
committed
Add tests for format package
Cover format config, table rendering, and helper functions. Achieves 88% test coverage for the new format package.
1 parent 6371686 commit 903e501

File tree

2 files changed

+317
-0
lines changed

2 files changed

+317
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package format
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/urfave/cli/v2"
10+
)
11+
12+
func TestConfig_IsJSON(t *testing.T) {
13+
tests := []struct {
14+
format string
15+
want bool
16+
}{
17+
{FormatJSON, true},
18+
{FormatTable, false},
19+
{FormatWide, false},
20+
{"", false},
21+
}
22+
23+
for _, tt := range tests {
24+
t.Run(tt.format, func(t *testing.T) {
25+
cfg := Config{Format: tt.format}
26+
assert.Equal(t, tt.want, cfg.IsJSON())
27+
})
28+
}
29+
}
30+
31+
func TestConfig_IsWide(t *testing.T) {
32+
tests := []struct {
33+
format string
34+
want bool
35+
}{
36+
{FormatWide, true},
37+
{FormatTable, false},
38+
{FormatJSON, false},
39+
{"", false},
40+
}
41+
42+
for _, tt := range tests {
43+
t.Run(tt.format, func(t *testing.T) {
44+
cfg := Config{Format: tt.format}
45+
assert.Equal(t, tt.want, cfg.IsWide())
46+
})
47+
}
48+
}
49+
50+
func TestConfig_IsTable(t *testing.T) {
51+
tests := []struct {
52+
format string
53+
want bool
54+
}{
55+
{FormatTable, true},
56+
{"", true},
57+
{FormatJSON, false},
58+
{FormatWide, false},
59+
}
60+
61+
for _, tt := range tests {
62+
t.Run(tt.format, func(t *testing.T) {
63+
cfg := Config{Format: tt.format}
64+
assert.Equal(t, tt.want, cfg.IsTable())
65+
})
66+
}
67+
}
68+
69+
func TestFromContext(t *testing.T) {
70+
app := &cli.App{
71+
Flags: []cli.Flag{OutputFlag, NoColorFlag},
72+
Action: func(c *cli.Context) error {
73+
cfg := FromContext(c)
74+
assert.Equal(t, FormatJSON, cfg.Format)
75+
assert.True(t, cfg.NoColor)
76+
return nil
77+
},
78+
Writer: &bytes.Buffer{},
79+
}
80+
81+
err := app.Run([]string{"test", "--output", "json", "--no-color"})
82+
assert.NoError(t, err)
83+
}
84+
85+
func TestFromContext_DefaultValues(t *testing.T) {
86+
app := &cli.App{
87+
Flags: []cli.Flag{OutputFlag, NoColorFlag},
88+
Action: func(c *cli.Context) error {
89+
cfg := FromContext(c)
90+
assert.Equal(t, FormatTable, cfg.Format)
91+
return nil
92+
},
93+
Writer: &bytes.Buffer{},
94+
}
95+
96+
err := app.Run([]string{"test"})
97+
assert.NoError(t, err)
98+
}
99+
100+
func TestFromContext_NoColorEnvVar(t *testing.T) {
101+
os.Setenv("NO_COLOR", "1")
102+
defer os.Unsetenv("NO_COLOR")
103+
104+
app := &cli.App{
105+
Flags: []cli.Flag{OutputFlag, NoColorFlag},
106+
Action: func(c *cli.Context) error {
107+
cfg := FromContext(c)
108+
assert.True(t, cfg.NoColor)
109+
return nil
110+
},
111+
Writer: &bytes.Buffer{},
112+
}
113+
114+
err := app.Run([]string{"test"})
115+
assert.NoError(t, err)
116+
}
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package format
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestNewTable(t *testing.T) {
13+
buf := &bytes.Buffer{}
14+
table := NewTable(buf, false)
15+
16+
assert.NotNil(t, table)
17+
assert.NotNil(t, table.Table)
18+
}
19+
20+
func TestTable_SetHeaders(t *testing.T) {
21+
buf := &bytes.Buffer{}
22+
table := NewTable(buf, true)
23+
24+
table.SetHeaders("COL1", "COL2", "COL3")
25+
table.Append([]string{"a", "b", "c"})
26+
table.Render()
27+
28+
output := buf.String()
29+
assert.Contains(t, output, "COL1")
30+
assert.Contains(t, output, "COL2")
31+
assert.Contains(t, output, "COL3")
32+
}
33+
34+
func TestTable_Render(t *testing.T) {
35+
buf := &bytes.Buffer{}
36+
table := NewTable(buf, true)
37+
38+
table.SetHeaders("ID", "NAME")
39+
table.Append([]string{"1", "test1"})
40+
table.Append([]string{"2", "test2"})
41+
table.Render()
42+
43+
output := buf.String()
44+
assert.Contains(t, output, "1")
45+
assert.Contains(t, output, "test1")
46+
assert.Contains(t, output, "2")
47+
assert.Contains(t, output, "test2")
48+
}
49+
50+
func TestFormatStatus(t *testing.T) {
51+
tests := []struct {
52+
code string
53+
noColor bool
54+
want string
55+
}{
56+
{"OK", true, "OK"},
57+
{"READY", true, "READY"},
58+
{"CREATING", true, "CREATING"},
59+
{"WARNING", true, "WARNING"},
60+
{"FATAL", true, "FATAL"},
61+
{"UNKNOWN", true, "UNKNOWN"},
62+
}
63+
64+
for _, tt := range tests {
65+
t.Run(tt.code, func(t *testing.T) {
66+
got := FormatStatus(tt.code, tt.noColor)
67+
assert.Equal(t, tt.want, got)
68+
})
69+
}
70+
}
71+
72+
func TestFormatStatus_WithColor(t *testing.T) {
73+
// color library auto-disables in non-TTY, so we just verify the function works
74+
got := FormatStatus("OK", false)
75+
assert.Contains(t, got, "OK")
76+
}
77+
78+
func TestFormatTime(t *testing.T) {
79+
tests := []struct {
80+
name string
81+
time time.Time
82+
want string
83+
}{
84+
{"zero time", time.Time{}, "-"},
85+
{"recent time", time.Now().Add(-5 * time.Minute), "5 minutes ago"},
86+
{"hour ago", time.Now().Add(-1 * time.Hour), "1 hour ago"},
87+
}
88+
89+
for _, tt := range tests {
90+
t.Run(tt.name, func(t *testing.T) {
91+
got := FormatTime(tt.time)
92+
if tt.time.IsZero() {
93+
assert.Equal(t, tt.want, got)
94+
} else {
95+
assert.Contains(t, got, "ago")
96+
}
97+
})
98+
}
99+
}
100+
101+
func TestFormatTimeAbs(t *testing.T) {
102+
tests := []struct {
103+
name string
104+
time time.Time
105+
want string
106+
}{
107+
{"zero time", time.Time{}, "-"},
108+
{"specific time", time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), "2024-01-15 10:30:00"},
109+
}
110+
111+
for _, tt := range tests {
112+
t.Run(tt.name, func(t *testing.T) {
113+
got := FormatTimeAbs(tt.time)
114+
assert.Equal(t, tt.want, got)
115+
})
116+
}
117+
}
118+
119+
func TestFormatBytes(t *testing.T) {
120+
tests := []struct {
121+
bytes uint64
122+
want string
123+
}{
124+
{0, "-"},
125+
{1024, "1.0 kB"},
126+
{1048576, "1.0 MB"},
127+
{1073741824, "1.1 GB"},
128+
}
129+
130+
for _, tt := range tests {
131+
t.Run(tt.want, func(t *testing.T) {
132+
got := FormatBytes(tt.bytes)
133+
assert.Equal(t, tt.want, got)
134+
})
135+
}
136+
}
137+
138+
func TestFormatBool(t *testing.T) {
139+
tests := []struct {
140+
value bool
141+
noColor bool
142+
want string
143+
}{
144+
{true, true, "yes"},
145+
{false, true, "-"},
146+
{false, false, "-"},
147+
}
148+
149+
for _, tt := range tests {
150+
t.Run(tt.want, func(t *testing.T) {
151+
got := FormatBool(tt.value, tt.noColor)
152+
assert.Equal(t, tt.want, got)
153+
})
154+
}
155+
}
156+
157+
func TestFormatBool_WithColor(t *testing.T) {
158+
got := FormatBool(true, false)
159+
assert.Contains(t, got, "✓")
160+
}
161+
162+
func TestTruncate(t *testing.T) {
163+
tests := []struct {
164+
input string
165+
max int
166+
want string
167+
}{
168+
{"short", 10, "short"},
169+
{"exactly10!", 10, "exactly10!"},
170+
{"this is a long string", 10, "this is..."},
171+
{"abc", 3, "abc"},
172+
{"abcd", 3, "abc"},
173+
{"ab", 5, "ab"},
174+
}
175+
176+
for _, tt := range tests {
177+
t.Run(tt.input, func(t *testing.T) {
178+
got := Truncate(tt.input, tt.max)
179+
assert.Equal(t, tt.want, got)
180+
assert.LessOrEqual(t, len(got), tt.max)
181+
})
182+
}
183+
}
184+
185+
func TestRepeat(t *testing.T) {
186+
colors := repeat(nil, 3)
187+
assert.Len(t, colors, 3)
188+
}
189+
190+
func TestTable_NoColorHeaders(t *testing.T) {
191+
buf := &bytes.Buffer{}
192+
table := NewTable(buf, true)
193+
194+
table.SetHeaders("A", "B")
195+
table.Append([]string{"1", "2"})
196+
table.Render()
197+
198+
output := buf.String()
199+
assert.True(t, strings.Contains(output, "A"))
200+
assert.True(t, strings.Contains(output, "B"))
201+
}

0 commit comments

Comments
 (0)