cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package main
2
3import (
4 "context"
5 "strings"
6 "testing"
7
8 "github.com/stormlightlabs/noteleaf/internal/handlers"
9)
10
11func createTestPublicationHandler(t *testing.T) (*handlers.PublicationHandler, func()) {
12 cleanup := setupCommandTest(t)
13 handler, err := handlers.NewPublicationHandler()
14 if err != nil {
15 cleanup()
16 t.Fatalf("Failed to create test publication handler: %v", err)
17 }
18 return handler, func() {
19 handler.Close()
20 cleanup()
21 }
22}
23
24func TestPublicationCommand(t *testing.T) {
25 t.Run("CommandGroup Interface", func(t *testing.T) {
26 handler, cleanup := createTestPublicationHandler(t)
27 defer cleanup()
28
29 var _ CommandGroup = NewPublicationCommand(handler)
30 })
31
32 t.Run("Create", func(t *testing.T) {
33 t.Run("creates command with correct structure", func(t *testing.T) {
34 handler, cleanup := createTestPublicationHandler(t)
35 defer cleanup()
36
37 cmd := NewPublicationCommand(handler).Create()
38
39 if cmd == nil {
40 t.Fatal("Create returned nil")
41 }
42 if cmd.Use != "pub" {
43 t.Errorf("Expected Use to be 'pub', got '%s'", cmd.Use)
44 }
45 if cmd.Short != "Manage leaflet publication sync" {
46 t.Errorf("Expected Short to be 'Manage leaflet publication sync', got '%s'", cmd.Short)
47 }
48 if !cmd.HasSubCommands() {
49 t.Error("Expected command to have subcommands")
50 }
51 })
52
53 t.Run("has all expected subcommands", func(t *testing.T) {
54 handler, cleanup := createTestPublicationHandler(t)
55 defer cleanup()
56
57 cmd := NewPublicationCommand(handler).Create()
58 subcommands := cmd.Commands()
59 subcommandNames := make([]string, len(subcommands))
60 for i, subcmd := range subcommands {
61 subcommandNames[i] = subcmd.Use
62 }
63
64 expectedSubcommands := []string{
65 "auth [handle]",
66 "pull",
67 "list [--published|--draft|--all]",
68 "status",
69 }
70
71 for _, expected := range expectedSubcommands {
72 if !findSubcommand(subcommandNames, expected) {
73 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames)
74 }
75 }
76 })
77 })
78
79 t.Run("Status Command", func(t *testing.T) {
80 t.Run("shows not authenticated initially", func(t *testing.T) {
81 handler, cleanup := createTestPublicationHandler(t)
82 defer cleanup()
83
84 cmd := NewPublicationCommand(handler).Create()
85 cmd.SetArgs([]string{"status"})
86 err := cmd.Execute()
87
88 if err != nil {
89 t.Errorf("status command failed: %v", err)
90 }
91 })
92 })
93
94 t.Run("List Command", func(t *testing.T) {
95 t.Run("default filter", func(t *testing.T) {
96 handler, cleanup := createTestPublicationHandler(t)
97 defer cleanup()
98
99 cmd := NewPublicationCommand(handler).Create()
100 cmd.SetArgs([]string{"list"})
101 err := cmd.Execute()
102
103 if err != nil {
104 t.Errorf("list command failed: %v", err)
105 }
106 })
107
108 t.Run("with published flag", func(t *testing.T) {
109 handler, cleanup := createTestPublicationHandler(t)
110 defer cleanup()
111
112 cmd := NewPublicationCommand(handler).Create()
113 cmd.SetArgs([]string{"list", "--published"})
114 err := cmd.Execute()
115
116 if err != nil {
117 t.Errorf("list --published failed: %v", err)
118 }
119 })
120
121 t.Run("with draft flag", func(t *testing.T) {
122 handler, cleanup := createTestPublicationHandler(t)
123 defer cleanup()
124
125 cmd := NewPublicationCommand(handler).Create()
126 cmd.SetArgs([]string{"list", "--draft"})
127 err := cmd.Execute()
128
129 if err != nil {
130 t.Errorf("list --draft failed: %v", err)
131 }
132 })
133
134 t.Run("with all flag", func(t *testing.T) {
135 handler, cleanup := createTestPublicationHandler(t)
136 defer cleanup()
137
138 cmd := NewPublicationCommand(handler).Create()
139 cmd.SetArgs([]string{"list", "--all"})
140 err := cmd.Execute()
141
142 if err != nil {
143 t.Errorf("list --all failed: %v", err)
144 }
145 })
146
147 t.Run("published takes precedence over draft", func(t *testing.T) {
148 handler, cleanup := createTestPublicationHandler(t)
149 defer cleanup()
150
151 cmd := NewPublicationCommand(handler).Create()
152 cmd.SetArgs([]string{"list", "--published", "--draft"})
153 err := cmd.Execute()
154
155 if err != nil {
156 t.Errorf("list with multiple flags failed: %v", err)
157 }
158 })
159 })
160
161 t.Run("Pull Command", func(t *testing.T) {
162 t.Run("fails when not authenticated", func(t *testing.T) {
163 handler, cleanup := createTestPublicationHandler(t)
164 defer cleanup()
165
166 cmd := NewPublicationCommand(handler).Create()
167 cmd.SetArgs([]string{"pull"})
168 err := cmd.Execute()
169
170 if err == nil {
171 t.Error("Expected pull to fail when not authenticated")
172 }
173 if err != nil && !strings.Contains(err.Error(), "not authenticated") {
174 t.Errorf("Expected 'not authenticated' error, got: %v", err)
175 }
176 })
177 })
178
179 t.Run("Command Help", func(t *testing.T) {
180 t.Run("root help", func(t *testing.T) {
181 handler, cleanup := createTestPublicationHandler(t)
182 defer cleanup()
183
184 cmd := NewPublicationCommand(handler).Create()
185 cmd.SetArgs([]string{"help"})
186 err := cmd.Execute()
187
188 if err != nil {
189 t.Errorf("help command failed: %v", err)
190 }
191 })
192
193 t.Run("auth help", func(t *testing.T) {
194 handler, cleanup := createTestPublicationHandler(t)
195 defer cleanup()
196
197 cmd := NewPublicationCommand(handler).Create()
198 cmd.SetArgs([]string{"auth", "--help"})
199 err := cmd.Execute()
200
201 if err != nil {
202 t.Errorf("auth help failed: %v", err)
203 }
204 })
205 })
206
207 t.Run("Command Aliases", func(t *testing.T) {
208 t.Run("list alias ls works", func(t *testing.T) {
209 handler, cleanup := createTestPublicationHandler(t)
210 defer cleanup()
211
212 cmd := NewPublicationCommand(handler).Create()
213 cmd.SetArgs([]string{"ls"})
214 err := cmd.Execute()
215
216 if err != nil {
217 t.Errorf("list alias 'ls' failed: %v", err)
218 }
219 })
220 })
221
222 t.Run("Handler Validation", func(t *testing.T) {
223 t.Run("auth validates empty handle", func(t *testing.T) {
224 handler, cleanup := createTestPublicationHandler(t)
225 defer cleanup()
226
227 ctx := context.Background()
228 err := handler.Auth(ctx, "", "password")
229
230 if err == nil {
231 t.Error("Expected error for empty handle")
232 }
233 if !strings.Contains(err.Error(), "handle is required") {
234 t.Errorf("Expected 'handle is required' error, got: %v", err)
235 }
236 })
237
238 t.Run("auth validates empty password", func(t *testing.T) {
239 handler, cleanup := createTestPublicationHandler(t)
240 defer cleanup()
241
242 ctx := context.Background()
243 err := handler.Auth(ctx, "test.bsky.social", "")
244
245 if err == nil {
246 t.Error("Expected error for empty password")
247 }
248 if !strings.Contains(err.Error(), "password is required") {
249 t.Errorf("Expected 'password is required' error, got: %v", err)
250 }
251 })
252 })
253}