cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists ๐Ÿƒ
charm leaflet readability golang

build: test command execution

+116 -15
+7 -3
cmd/commands.go
··· 308 308 Aliases: []string{"new"}, 309 309 RunE: func(cmd *cobra.Command, args []string) error { 310 310 interactive, _ := cmd.Flags().GetBool("interactive") 311 + editor, _ := cmd.Flags().GetBool("editor") 311 312 filePath, _ := cmd.Flags().GetString("file") 312 313 313 314 var title, content string ··· 319 320 } 320 321 321 322 defer c.handler.Close() 322 - return c.handler.Create(cmd.Context(), title, content, filePath, interactive) 323 + return c.handler.CreateWithOptions(cmd.Context(), title, content, filePath, interactive, editor) 323 324 }, 324 325 } 325 326 createCmd.Flags().BoolP("interactive", "i", false, "Open interactive editor") 327 + createCmd.Flags().BoolP("editor", "e", false, "Prompt to open note in editor after creation") 326 328 createCmd.Flags().StringP("file", "f", "", "Create note from markdown file") 327 329 root.AddCommand(createCmd) 328 330 329 331 listCmd := &cobra.Command{ 330 - Use: "list [--archived] [--tags=tag1,tag2]", 332 + Use: "list [--archived] [--static] [--tags=tag1,tag2]", 331 333 Short: "Opens interactive TUI browser for navigating and viewing notes", 332 334 Aliases: []string{"ls"}, 333 335 RunE: func(cmd *cobra.Command, args []string) error { 334 336 archived, _ := cmd.Flags().GetBool("archived") 337 + static, _ := cmd.Flags().GetBool("static") 335 338 tagsStr, _ := cmd.Flags().GetString("tags") 336 339 337 340 var tags []string ··· 343 346 } 344 347 345 348 defer c.handler.Close() 346 - return c.handler.List(cmd.Context(), false, archived, tags) 349 + return c.handler.List(cmd.Context(), static, archived, tags) 347 350 }, 348 351 } 349 352 listCmd.Flags().BoolP("archived", "a", false, "Show archived notes") 353 + listCmd.Flags().BoolP("static", "s", false, "Show static list instead of interactive TUI") 350 354 listCmd.Flags().String("tags", "", "Filter by tags (comma-separated)") 351 355 root.AddCommand(listCmd) 352 356
+90 -1
cmd/commands_test.go
··· 260 260 261 261 expectedSubcommands := []string{ 262 262 "create [title] [content...]", 263 - "list [--archived] [--tags=tag1,tag2]", 263 + "list [--archived] [--static] [--tags=tag1,tag2]", 264 264 "read [note-id]", 265 265 "edit [note-id]", 266 266 "remove [note-id]", ··· 354 354 }) 355 355 356 356 } 357 + 358 + func TestCommandExecution(t *testing.T) { 359 + t.Run("Movie Commands", func(t *testing.T) { 360 + handler, cleanup := createTestMovieHandler(t) 361 + defer cleanup() 362 + 363 + t.Run("list command - default", func(t *testing.T) { 364 + cmd := NewMovieCommand(handler).Create() 365 + cmd.SetArgs([]string{"list"}) 366 + err := cmd.Execute() 367 + if err != nil { 368 + t.Errorf("movie list command failed: %v", err) 369 + } 370 + }) 371 + 372 + t.Run("add command with empty args", func(t *testing.T) { 373 + cmd := NewMovieCommand(handler).Create() 374 + cmd.SetArgs([]string{"add"}) 375 + err := cmd.Execute() 376 + if err == nil { 377 + t.Error("expected movie add command to fail with empty args") 378 + } 379 + }) 380 + }) 381 + 382 + t.Run("TV Commands", func(t *testing.T) { 383 + handler, cleanup := createTestTVHandler(t) 384 + defer cleanup() 385 + 386 + t.Run("list command - default", func(t *testing.T) { 387 + cmd := NewTVCommand(handler).Create() 388 + cmd.SetArgs([]string{"list"}) 389 + err := cmd.Execute() 390 + if err != nil { 391 + t.Errorf("tv list command failed: %v", err) 392 + } 393 + }) 394 + 395 + t.Run("add command with empty args", func(t *testing.T) { 396 + cmd := NewTVCommand(handler).Create() 397 + cmd.SetArgs([]string{"add"}) 398 + err := cmd.Execute() 399 + if err == nil { 400 + t.Error("expected tv add command to fail with empty args") 401 + } 402 + }) 403 + }) 404 + 405 + t.Run("Book Commands", func(t *testing.T) { 406 + handler, cleanup := createTestBookHandler(t) 407 + defer cleanup() 408 + 409 + t.Run("list command - default", func(t *testing.T) { 410 + cmd := NewBookCommand(handler).Create() 411 + cmd.SetArgs([]string{"list"}) 412 + err := cmd.Execute() 413 + if err != nil { 414 + t.Errorf("book list command failed: %v", err) 415 + } 416 + }) 417 + }) 418 + 419 + t.Run("Note Commands", func(t *testing.T) { 420 + 421 + t.Run("create command - non-interactive", func(t *testing.T) { 422 + handler, cleanup := createTestNoteHandler(t) 423 + defer cleanup() 424 + 425 + cmd := NewNoteCommand(handler).Create() 426 + cmd.SetArgs([]string{"create", "test title", "test content"}) 427 + err := cmd.Execute() 428 + if err != nil { 429 + t.Errorf("note create command failed: %v", err) 430 + } 431 + }) 432 + 433 + t.Run("list command - static mode", func(t *testing.T) { 434 + handler, cleanup := createTestNoteHandler(t) 435 + defer cleanup() 436 + 437 + cmd := NewNoteCommand(handler).Create() 438 + cmd.SetArgs([]string{"list", "--static"}) 439 + err := cmd.Execute() 440 + if err != nil { 441 + t.Errorf("note list command failed: %v", err) 442 + } 443 + }) 444 + }) 445 + }
-1
go.mod
··· 82 82 golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect 83 83 golang.org/x/sys v0.36.0 // indirect 84 84 golang.org/x/text v0.29.0 85 - golang.org/x/tools v0.37.0 86 85 )
-2
go.sum
··· 230 230 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 231 231 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 232 232 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 233 - golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= 234 - golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= 235 233 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 236 234 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 237 235 google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+19 -8
internal/handlers/notes.go
··· 57 57 58 58 // Create handles note creation with optional title, content, and file path 59 59 func (h *NoteHandler) Create(ctx context.Context, title string, content string, filePath string, interactive bool) error { 60 + return h.CreateWithOptions(ctx, title, content, filePath, interactive, false) 61 + } 62 + 63 + // CreateWithOptions handles note creation with additional options 64 + func (h *NoteHandler) CreateWithOptions(ctx context.Context, title string, content string, filePath string, interactive bool, promptEditor bool) error { 60 65 if interactive || (title == "" && content == "" && filePath == "") { 61 66 return h.createInteractive(ctx) 62 67 } ··· 65 70 return h.createFromFile(ctx, filePath) 66 71 } 67 72 68 - return h.createFromArgs(ctx, title, content) 73 + return h.createFromArgsWithOptions(ctx, title, content, promptEditor) 69 74 } 70 75 71 76 func (h *NoteHandler) createInteractive(ctx context.Context) error { ··· 175 180 } 176 181 177 182 func (h *NoteHandler) createFromArgs(ctx context.Context, title, content string) error { 183 + return h.createFromArgsWithOptions(ctx, title, content, false) 184 + } 185 + 186 + func (h *NoteHandler) createFromArgsWithOptions(ctx context.Context, title, content string, promptEditor bool) error { 178 187 note := &models.Note{ 179 188 Title: title, 180 189 Content: content, ··· 187 196 188 197 fmt.Printf("Created note: %s (ID: %d)\n", title, id) 189 198 190 - editor := h.getEditor() 191 - if editor != "" { 192 - fmt.Print("Open in editor? [y/N]: ") 193 - var response string 194 - fmt.Scanln(&response) 195 - if strings.ToLower(response) == "y" || strings.ToLower(response) == "yes" { 196 - return h.Edit(ctx, id) 199 + if promptEditor { 200 + editor := h.getEditor() 201 + if editor != "" { 202 + fmt.Print("Open in editor? [y/N]: ") 203 + var response string 204 + fmt.Scanln(&response) 205 + if strings.ToLower(response) == "y" || strings.ToLower(response) == "yes" { 206 + return h.Edit(ctx, id) 207 + } 197 208 } 198 209 } 199 210