Skip to content

Commit 218307a

Browse files
Add CLI tests for attachments and help commands
- attachments_test.go: Tests for CollectAttachments function - help_test.go: Tests for help display functions (clampWidth, detectWidth, etc.) Coverage improved from 46.1% to 49.6% 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b963ad3 commit 218307a

2 files changed

Lines changed: 355 additions & 0 deletions

File tree

internal/cli/attachments_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/Dicklesworthstone/slb/internal/testutil"
10+
)
11+
12+
func TestCollectAttachments_EmptyFlags(t *testing.T) {
13+
_ = testutil.NewHarness(t) // Ensure test cleanup
14+
15+
flags := AttachmentFlags{}
16+
attachments, err := CollectAttachments(context.Background(), flags)
17+
18+
if err != nil {
19+
t.Fatalf("unexpected error: %v", err)
20+
}
21+
if len(attachments) != 0 {
22+
t.Errorf("expected 0 attachments with empty flags, got %d", len(attachments))
23+
}
24+
}
25+
26+
func TestCollectAttachments_FileAttachment(t *testing.T) {
27+
h := testutil.NewHarness(t)
28+
29+
// Create a test file
30+
testFile := filepath.Join(h.ProjectDir, "test.txt")
31+
if err := os.WriteFile(testFile, []byte("test content"), 0644); err != nil {
32+
t.Fatalf("failed to create test file: %v", err)
33+
}
34+
35+
flags := AttachmentFlags{
36+
Files: []string{testFile},
37+
}
38+
39+
attachments, err := CollectAttachments(context.Background(), flags)
40+
41+
if err != nil {
42+
t.Fatalf("unexpected error: %v", err)
43+
}
44+
if len(attachments) != 1 {
45+
t.Fatalf("expected 1 attachment, got %d", len(attachments))
46+
}
47+
// Attachment has Type, Content, and Metadata fields
48+
if attachments[0].Type != "file" {
49+
t.Errorf("expected type 'file', got %q", attachments[0].Type)
50+
}
51+
if attachments[0].Content == "" {
52+
t.Error("expected non-empty content")
53+
}
54+
}
55+
56+
func TestCollectAttachments_FileNotFound(t *testing.T) {
57+
_ = testutil.NewHarness(t)
58+
59+
flags := AttachmentFlags{
60+
Files: []string{"/nonexistent/path/file.txt"},
61+
}
62+
63+
_, err := CollectAttachments(context.Background(), flags)
64+
65+
if err == nil {
66+
t.Fatal("expected error for nonexistent file")
67+
}
68+
}
69+
70+
func TestCollectAttachments_MultipleFiles(t *testing.T) {
71+
h := testutil.NewHarness(t)
72+
73+
// Create test files
74+
file1 := filepath.Join(h.ProjectDir, "file1.txt")
75+
file2 := filepath.Join(h.ProjectDir, "file2.txt")
76+
if err := os.WriteFile(file1, []byte("content 1"), 0644); err != nil {
77+
t.Fatalf("failed to create test file: %v", err)
78+
}
79+
if err := os.WriteFile(file2, []byte("content 2"), 0644); err != nil {
80+
t.Fatalf("failed to create test file: %v", err)
81+
}
82+
83+
flags := AttachmentFlags{
84+
Files: []string{file1, file2},
85+
}
86+
87+
attachments, err := CollectAttachments(context.Background(), flags)
88+
89+
if err != nil {
90+
t.Fatalf("unexpected error: %v", err)
91+
}
92+
if len(attachments) != 2 {
93+
t.Errorf("expected 2 attachments, got %d", len(attachments))
94+
}
95+
}
96+
97+
func TestCollectAttachments_ContextCommand(t *testing.T) {
98+
_ = testutil.NewHarness(t)
99+
100+
flags := AttachmentFlags{
101+
Contexts: []string{"echo hello"},
102+
}
103+
104+
attachments, err := CollectAttachments(context.Background(), flags)
105+
106+
if err != nil {
107+
t.Fatalf("unexpected error: %v", err)
108+
}
109+
if len(attachments) != 1 {
110+
t.Fatalf("expected 1 attachment, got %d", len(attachments))
111+
}
112+
// Context commands produce a "context" type attachment
113+
if attachments[0].Type != "context" {
114+
t.Errorf("expected type 'context', got %q", attachments[0].Type)
115+
}
116+
}
117+
118+
func TestCollectAttachments_FailingContextCommand(t *testing.T) {
119+
_ = testutil.NewHarness(t)
120+
121+
flags := AttachmentFlags{
122+
Contexts: []string{"nonexistent-command-xyz"},
123+
}
124+
125+
_, err := CollectAttachments(context.Background(), flags)
126+
127+
// Command may or may not fail depending on shell behavior
128+
// Just verify no panic occurs
129+
_ = err
130+
}
131+
132+
func TestCollectAttachments_ScreenshotNotFound(t *testing.T) {
133+
_ = testutil.NewHarness(t)
134+
135+
flags := AttachmentFlags{
136+
Screenshots: []string{"/nonexistent/screenshot.png"},
137+
}
138+
139+
_, err := CollectAttachments(context.Background(), flags)
140+
141+
if err == nil {
142+
t.Fatal("expected error for nonexistent screenshot")
143+
}
144+
}
145+
146+
func TestAttachmentFlags_Struct(t *testing.T) {
147+
// Verify AttachmentFlags struct can be used properly
148+
flags := AttachmentFlags{
149+
Files: []string{"file1.txt", "file2.txt"},
150+
Contexts: []string{"ls -la", "git status"},
151+
Screenshots: []string{"screen.png"},
152+
}
153+
154+
if len(flags.Files) != 2 {
155+
t.Errorf("expected 2 files, got %d", len(flags.Files))
156+
}
157+
if len(flags.Contexts) != 2 {
158+
t.Errorf("expected 2 contexts, got %d", len(flags.Contexts))
159+
}
160+
if len(flags.Screenshots) != 1 {
161+
t.Errorf("expected 1 screenshot, got %d", len(flags.Screenshots))
162+
}
163+
}

internal/cli/help_test.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package cli
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/charmbracelet/lipgloss"
8+
)
9+
10+
func TestClampWidth(t *testing.T) {
11+
tests := []struct {
12+
input int
13+
expected int
14+
}{
15+
{50, 72}, // Below minimum, clamp to 72
16+
{72, 72}, // At minimum
17+
{80, 80}, // Normal width
18+
{100, 100}, // At maximum
19+
{120, 100}, // Above maximum, clamp to 100
20+
{200, 100}, // Well above maximum
21+
}
22+
23+
for _, tt := range tests {
24+
result := clampWidth(tt.input)
25+
if result != tt.expected {
26+
t.Errorf("clampWidth(%d) = %d, want %d", tt.input, result, tt.expected)
27+
}
28+
}
29+
}
30+
31+
func TestDetectWidth(t *testing.T) {
32+
// Test with COLUMNS env var
33+
originalColumns := os.Getenv("COLUMNS")
34+
defer os.Setenv("COLUMNS", originalColumns)
35+
36+
os.Setenv("COLUMNS", "120")
37+
width := detectWidth()
38+
// The result may vary depending on whether stdout is a terminal
39+
if width <= 0 {
40+
t.Errorf("detectWidth() returned %d, expected positive value", width)
41+
}
42+
43+
// Test with invalid COLUMNS
44+
os.Setenv("COLUMNS", "invalid")
45+
width = detectWidth()
46+
// Should fall back to default (80) or terminal width
47+
if width <= 0 {
48+
t.Errorf("detectWidth() returned %d, expected positive value", width)
49+
}
50+
51+
// Test with empty COLUMNS
52+
os.Setenv("COLUMNS", "")
53+
width = detectWidth()
54+
if width <= 0 {
55+
t.Errorf("detectWidth() returned %d, expected positive value", width)
56+
}
57+
}
58+
59+
func TestSupportsUnicode(t *testing.T) {
60+
// Save original environment
61+
originalTerm := os.Getenv("TERM")
62+
originalLcAll := os.Getenv("LC_ALL")
63+
originalLcCtype := os.Getenv("LC_CTYPE")
64+
originalLang := os.Getenv("LANG")
65+
66+
defer func() {
67+
os.Setenv("TERM", originalTerm)
68+
os.Setenv("LC_ALL", originalLcAll)
69+
os.Setenv("LC_CTYPE", originalLcCtype)
70+
os.Setenv("LANG", originalLang)
71+
}()
72+
73+
// Test with dumb terminal
74+
os.Setenv("TERM", "dumb")
75+
os.Setenv("LC_ALL", "")
76+
os.Setenv("LC_CTYPE", "")
77+
os.Setenv("LANG", "")
78+
if supportsUnicode() {
79+
t.Error("expected supportsUnicode() = false for dumb terminal")
80+
}
81+
82+
// Test with UTF-8 locale
83+
os.Setenv("TERM", "xterm")
84+
os.Setenv("LC_ALL", "en_US.UTF-8")
85+
if !supportsUnicode() {
86+
t.Error("expected supportsUnicode() = true for UTF-8 locale")
87+
}
88+
89+
// Test with utf8 in LANG
90+
os.Setenv("LC_ALL", "")
91+
os.Setenv("LANG", "C.utf8")
92+
if !supportsUnicode() {
93+
t.Error("expected supportsUnicode() = true for utf8 in LANG")
94+
}
95+
}
96+
97+
func TestGradientText(t *testing.T) {
98+
// Save original environment for Unicode check
99+
originalLang := os.Getenv("LANG")
100+
defer os.Setenv("LANG", originalLang)
101+
102+
os.Setenv("LANG", "en_US.UTF-8")
103+
os.Setenv("TERM", "xterm")
104+
105+
// Test with no colors
106+
result := gradientText("hello", nil)
107+
if result != "hello" {
108+
t.Errorf("expected 'hello' with no colors, got %q", result)
109+
}
110+
111+
// Test with colors - just verify no panic
112+
result = gradientText("hello", []lipgloss.Color{colorMauve, colorBlue})
113+
if result == "" {
114+
t.Error("expected non-empty result")
115+
}
116+
}
117+
118+
func TestBullet(t *testing.T) {
119+
result := bullet("slb run", "run a command")
120+
121+
// Should contain the command
122+
if result == "" {
123+
t.Error("expected non-empty bullet result")
124+
}
125+
126+
// Result should contain the command text
127+
// The styling makes exact matching difficult, but the content should be there
128+
}
129+
130+
func TestRenderSection(t *testing.T) {
131+
lines := []string{
132+
" line 1",
133+
" line 2",
134+
}
135+
136+
// Test with unicode
137+
result := renderSection(true, "🔷 Test Section", lines)
138+
if result == "" {
139+
t.Error("expected non-empty section result with unicode")
140+
}
141+
142+
// Test without unicode
143+
result = renderSection(false, "🔷 Test Section", lines)
144+
if result == "" {
145+
t.Error("expected non-empty section result without unicode")
146+
}
147+
}
148+
149+
func TestTierLegend(t *testing.T) {
150+
// Test with unicode
151+
result := tierLegend(true)
152+
if result == "" {
153+
t.Error("expected non-empty tier legend with unicode")
154+
}
155+
156+
// Test without unicode
157+
result = tierLegend(false)
158+
if result == "" {
159+
t.Error("expected non-empty tier legend without unicode")
160+
}
161+
}
162+
163+
func TestFlagLegend(t *testing.T) {
164+
// Test with unicode
165+
result := flagLegend(true)
166+
if result == "" {
167+
t.Error("expected non-empty flag legend with unicode")
168+
}
169+
170+
// Test without unicode
171+
result = flagLegend(false)
172+
if result == "" {
173+
t.Error("expected non-empty flag legend without unicode")
174+
}
175+
}
176+
177+
func TestFooterLegend(t *testing.T) {
178+
// Test with unicode
179+
result := footerLegend(true)
180+
if result == "" {
181+
t.Error("expected non-empty footer legend with unicode")
182+
}
183+
184+
// Test without unicode
185+
result = footerLegend(false)
186+
if result == "" {
187+
t.Error("expected non-empty footer legend without unicode")
188+
}
189+
}
190+
191+
// Ensure lipgloss import is used
192+
var _ lipgloss.Color

0 commit comments

Comments
 (0)