cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
29
fork

Configure Feed

Select the types of activity you want to include in your feed.

at d2c4ecc217c2c1655026bba3b364c124b3a95a8a 821 lines 23 kB view raw
1package main 2 3import ( 4 "context" 5 "os" 6 "slices" 7 "strings" 8 "testing" 9 10 "github.com/stormlightlabs/noteleaf/internal/handlers" 11 "github.com/stormlightlabs/noteleaf/internal/services" 12) 13 14func setupCommandTest(t *testing.T) func() { 15 tempDir, err := os.MkdirTemp("", "noteleaf-cmd-test-*") 16 if err != nil { 17 t.Fatalf("Failed to create temp dir: %v", err) 18 } 19 20 oldConfigHome := os.Getenv("XDG_CONFIG_HOME") 21 os.Setenv("XDG_CONFIG_HOME", tempDir) 22 23 cleanup := func() { 24 os.Setenv("XDG_CONFIG_HOME", oldConfigHome) 25 os.RemoveAll(tempDir) 26 } 27 28 ctx := context.Background() 29 err = handlers.Setup(ctx, []string{}) 30 if err != nil { 31 cleanup() 32 t.Fatalf("Failed to setup database: %v", err) 33 } 34 35 return cleanup 36} 37 38func createTestTaskHandler(t *testing.T) (*handlers.TaskHandler, func()) { 39 cleanup := setupCommandTest(t) 40 handler, err := handlers.NewTaskHandler() 41 if err != nil { 42 cleanup() 43 t.Fatalf("Failed to create test task handler: %v", err) 44 } 45 return handler, func() { 46 handler.Close() 47 cleanup() 48 } 49} 50 51func createTestMovieHandler(t *testing.T) (*handlers.MovieHandler, func()) { 52 cleanup := setupCommandTest(t) 53 handler, err := handlers.NewMovieHandler() 54 if err != nil { 55 cleanup() 56 t.Fatalf("Failed to create test movie handler: %v", err) 57 } 58 return handler, func() { 59 handler.Close() 60 cleanup() 61 } 62} 63 64func createTestTVHandler(t *testing.T) (*handlers.TVHandler, func()) { 65 cleanup := setupCommandTest(t) 66 handler, err := handlers.NewTVHandler() 67 if err != nil { 68 cleanup() 69 t.Fatalf("Failed to create test TV handler: %v", err) 70 } 71 return handler, func() { 72 handler.Close() 73 cleanup() 74 } 75} 76 77func createTestNoteHandler(t *testing.T) (*handlers.NoteHandler, func()) { 78 cleanup := setupCommandTest(t) 79 handler, err := handlers.NewNoteHandler() 80 if err != nil { 81 cleanup() 82 t.Fatalf("Failed to create test note handler: %v", err) 83 } 84 return handler, func() { 85 handler.Close() 86 cleanup() 87 } 88} 89 90func createTestBookHandler(t *testing.T) (*handlers.BookHandler, func()) { 91 cleanup := setupCommandTest(t) 92 handler, err := handlers.NewBookHandler() 93 if err != nil { 94 cleanup() 95 t.Fatalf("Failed to create test book handler: %v", err) 96 } 97 return handler, func() { 98 handler.Close() 99 cleanup() 100 } 101} 102 103func createTestArticleHandler(t *testing.T) (*handlers.ArticleHandler, func()) { 104 cleanup := setupCommandTest(t) 105 handler, err := handlers.NewArticleHandler() 106 if err != nil { 107 cleanup() 108 t.Fatalf("Failed to create test article handler: %v", err) 109 } 110 return handler, func() { 111 handler.Close() 112 cleanup() 113 } 114} 115 116func findSubcommand(commands []string, target string) bool { 117 return slices.Contains(commands, target) 118} 119 120func TestCommandGroup(t *testing.T) { 121 t.Run("Interface Implementations", func(t *testing.T) { 122 taskHandler, taskCleanup := createTestTaskHandler(t) 123 defer taskCleanup() 124 125 movieHandler, movieCleanup := createTestMovieHandler(t) 126 defer movieCleanup() 127 128 tvHandler, tvCleanup := createTestTVHandler(t) 129 defer tvCleanup() 130 131 noteHandler, noteCleanup := createTestNoteHandler(t) 132 defer noteCleanup() 133 134 bookHandler, bookCleanup := createTestBookHandler(t) 135 defer bookCleanup() 136 137 articleHandler, articleCleanup := createTestArticleHandler(t) 138 defer articleCleanup() 139 140 var _ CommandGroup = NewTaskCommand(taskHandler) 141 var _ CommandGroup = NewMovieCommand(movieHandler) 142 var _ CommandGroup = NewTVCommand(tvHandler) 143 var _ CommandGroup = NewNoteCommand(noteHandler) 144 var _ CommandGroup = NewBookCommand(bookHandler) 145 var _ CommandGroup = NewArticleCommand(articleHandler) 146 }) 147 148 t.Run("Create", func(t *testing.T) { 149 t.Run("TaskCommand", func(t *testing.T) { 150 handler, cleanup := createTestTaskHandler(t) 151 defer cleanup() 152 153 commands := NewTaskCommand(handler) 154 cmd := commands.Create() 155 156 if cmd == nil { 157 t.Fatal("Create returned nil") 158 } 159 if cmd.Use != "todo" { 160 t.Errorf("Expected Use to be 'todo', got '%s'", cmd.Use) 161 } 162 if len(cmd.Aliases) != 1 || cmd.Aliases[0] != "task" { 163 t.Errorf("Expected aliases to be ['task'], got %v", cmd.Aliases) 164 } 165 if cmd.Short != "task management" { 166 t.Errorf("Expected Short to be 'task management', got '%s'", cmd.Short) 167 } 168 if !cmd.HasSubCommands() { 169 t.Error("Expected command to have subcommands") 170 } 171 }) 172 173 t.Run("MovieCommand", func(t *testing.T) { 174 handler, cleanup := createTestMovieHandler(t) 175 defer cleanup() 176 177 commands := NewMovieCommand(handler) 178 cmd := commands.Create() 179 180 if cmd == nil { 181 t.Fatal("Create returned nil") 182 } 183 if cmd.Use != "movie" { 184 t.Errorf("Expected Use to be 'movie', got '%s'", cmd.Use) 185 } 186 if cmd.Short != "Manage movie watch queue" { 187 t.Errorf("Expected Short to be 'Manage movie watch queue', got '%s'", cmd.Short) 188 } 189 if !cmd.HasSubCommands() { 190 t.Error("Expected command to have subcommands") 191 } 192 193 subcommands := cmd.Commands() 194 subcommandNames := make([]string, len(subcommands)) 195 for i, subcmd := range subcommands { 196 subcommandNames[i] = subcmd.Use 197 } 198 199 expectedSubcommands := []string{ 200 "add [search query...]", 201 "list [--all|--watched|--queued]", 202 "watched [id]", 203 "remove [id]", 204 } 205 206 for _, expected := range expectedSubcommands { 207 if !findSubcommand(subcommandNames, expected) { 208 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames) 209 } 210 } 211 }) 212 213 t.Run("TVCommand", func(t *testing.T) { 214 handler, cleanup := createTestTVHandler(t) 215 defer cleanup() 216 217 commands := NewTVCommand(handler) 218 cmd := commands.Create() 219 220 if cmd == nil { 221 t.Fatal("Create returned nil") 222 } 223 if cmd.Use != "tv" { 224 t.Errorf("Expected Use to be 'tv', got '%s'", cmd.Use) 225 } 226 if cmd.Short != "Manage TV show watch queue" { 227 t.Errorf("Expected Short to be 'Manage TV show watch queue', got '%s'", cmd.Short) 228 } 229 if !cmd.HasSubCommands() { 230 t.Error("Expected command to have subcommands") 231 } 232 233 subcommands := cmd.Commands() 234 subcommandNames := make([]string, len(subcommands)) 235 for i, subcmd := range subcommands { 236 subcommandNames[i] = subcmd.Use 237 } 238 239 expectedSubcommands := []string{ 240 "add [search query...]", 241 "list [--all|--queued|--watching|--watched]", 242 "watching [id]", 243 "watched [id]", 244 "remove [id]", 245 } 246 247 for _, expected := range expectedSubcommands { 248 if !findSubcommand(subcommandNames, expected) { 249 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames) 250 } 251 } 252 }) 253 254 t.Run("NoteCommand", func(t *testing.T) { 255 handler, cleanup := createTestNoteHandler(t) 256 defer cleanup() 257 258 commands := NewNoteCommand(handler) 259 cmd := commands.Create() 260 261 if cmd == nil { 262 t.Fatal("Create returned nil") 263 } 264 if cmd.Use != "note" { 265 t.Errorf("Expected Use to be 'note', got '%s'", cmd.Use) 266 } 267 if cmd.Short != "Manage notes" { 268 t.Errorf("Expected Short to be 'Manage notes', got '%s'", cmd.Short) 269 } 270 if !cmd.HasSubCommands() { 271 t.Error("Expected command to have subcommands") 272 } 273 274 subcommands := cmd.Commands() 275 subcommandNames := make([]string, len(subcommands)) 276 for i, subcmd := range subcommands { 277 subcommandNames[i] = subcmd.Use 278 } 279 280 expectedSubcommands := []string{ 281 "create [title] [content...]", 282 "list [--archived] [--static] [--tags=tag1,tag2]", 283 "read [note-id]", 284 "edit [note-id]", 285 "remove [note-id]", 286 } 287 288 for _, expected := range expectedSubcommands { 289 if !findSubcommand(subcommandNames, expected) { 290 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames) 291 } 292 } 293 }) 294 295 t.Run("BookCommand", func(t *testing.T) { 296 handler, cleanup := createTestBookHandler(t) 297 defer cleanup() 298 299 commands := NewBookCommand(handler) 300 cmd := commands.Create() 301 302 if cmd == nil { 303 t.Fatal("Create returned nil") 304 } 305 if cmd.Use != "book" { 306 t.Errorf("Expected Use to be 'book', got '%s'", cmd.Use) 307 } 308 if cmd.Short != "Manage reading list" { 309 t.Errorf("Expected Short to be 'Manage reading list', got '%s'", cmd.Short) 310 } 311 if !cmd.HasSubCommands() { 312 t.Error("Expected command to have subcommands") 313 } 314 315 subcommands := cmd.Commands() 316 subcommandNames := make([]string, len(subcommands)) 317 for i, subcmd := range subcommands { 318 subcommandNames[i] = subcmd.Use 319 } 320 321 expectedSubcommands := []string{ 322 "add [search query...]", 323 "list [--all|--reading|--finished|--queued]", 324 "reading <id>", 325 "finished <id>", 326 "remove <id>", 327 "progress <id> <percentage>", 328 "update <id> <status>", 329 } 330 331 for _, expected := range expectedSubcommands { 332 if !findSubcommand(subcommandNames, expected) { 333 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames) 334 } 335 } 336 }) 337 338 t.Run("ArticleCommand", func(t *testing.T) { 339 handler, cleanup := createTestArticleHandler(t) 340 defer cleanup() 341 342 commands := NewArticleCommand(handler) 343 cmd := commands.Create() 344 345 if cmd == nil { 346 t.Fatal("Create returned nil") 347 } 348 if cmd.Use != "article" { 349 t.Errorf("Expected Use to be 'article', got '%s'", cmd.Use) 350 } 351 if cmd.Short != "Manage saved articles" { 352 t.Errorf("Expected Short to be 'Manage saved articles', got '%s'", cmd.Short) 353 } 354 if !cmd.HasSubCommands() { 355 t.Error("Expected command to have subcommands") 356 } 357 358 subcommands := cmd.Commands() 359 subcommandNames := make([]string, len(subcommands)) 360 for i, subcmd := range subcommands { 361 subcommandNames[i] = subcmd.Use 362 } 363 364 for _, expected := range []string{"add <url>", "list [query]", "view <id>", "remove <id>"} { 365 if !findSubcommand(subcommandNames, expected) { 366 t.Errorf("Expected subcommand '%s' not found in %v", expected, subcommandNames) 367 } 368 } 369 }) 370 371 t.Run("all command groups implement Create", func(t *testing.T) { 372 taskHandler, taskCleanup := createTestTaskHandler(t) 373 defer taskCleanup() 374 375 movieHandler, movieCleanup := createTestMovieHandler(t) 376 defer movieCleanup() 377 378 tvHandler, tvCleanup := createTestTVHandler(t) 379 defer tvCleanup() 380 381 noteHandler, noteCleanup := createTestNoteHandler(t) 382 defer noteCleanup() 383 384 bookHandler, bookCleanup := createTestBookHandler(t) 385 defer bookCleanup() 386 387 articleHandler, articleCleanup := createTestArticleHandler(t) 388 defer articleCleanup() 389 390 groups := []CommandGroup{ 391 NewTaskCommand(taskHandler), 392 NewMovieCommand(movieHandler), 393 NewTVCommand(tvHandler), 394 NewNoteCommand(noteHandler), 395 NewBookCommand(bookHandler), 396 NewArticleCommand(articleHandler), 397 } 398 399 for i, group := range groups { 400 cmd := group.Create() 401 if cmd == nil { 402 t.Errorf("CommandGroup %d returned nil from Create()", i) 403 continue 404 } 405 if cmd.Use == "" { 406 t.Errorf("CommandGroup %d returned command with empty Use", i) 407 } 408 } 409 }) 410 }) 411 412} 413 414func TestCommandExecution(t *testing.T) { 415 t.Run("Movie Commands", func(t *testing.T) { 416 handler, cleanup := createTestMovieHandler(t) 417 defer cleanup() 418 419 t.Run("list command - default", func(t *testing.T) { 420 cmd := NewMovieCommand(handler).Create() 421 cmd.SetArgs([]string{"list"}) 422 err := cmd.Execute() 423 if err != nil { 424 t.Errorf("movie list command failed: %v", err) 425 } 426 }) 427 428 t.Run("add command with empty args", func(t *testing.T) { 429 cmd := NewMovieCommand(handler).Create() 430 cmd.SetArgs([]string{"add"}) 431 err := cmd.Execute() 432 if err == nil { 433 t.Error("expected movie add command to fail with empty args") 434 } 435 }) 436 437 t.Run("add command with valid args - successful search", func(t *testing.T) { 438 cleanup := services.SetupSuccessfulMovieMocks(t) 439 defer cleanup() 440 441 cmd := NewMovieCommand(handler).Create() 442 cmd.SetArgs([]string{"add", "Fantastic Four"}) 443 err := cmd.Execute() 444 445 // NOTE: The command will find results but fail due to no user input in test environment 446 if err == nil { 447 t.Error("expected movie add command to fail due to no user input in test environment") 448 } 449 if !strings.Contains(err.Error(), "invalid input") { 450 t.Errorf("expected 'invalid input' error, got: %v", err) 451 } 452 }) 453 454 t.Run("add command with valid args - search failure", func(t *testing.T) { 455 cleanup := services.SetupFailureMocks(t, "search failed") 456 defer cleanup() 457 458 cmd := NewMovieCommand(handler).Create() 459 cmd.SetArgs([]string{"add", "some movie"}) 460 err := cmd.Execute() 461 if err == nil { 462 t.Error("expected movie add command to fail when search fails") 463 } 464 services.AssertErrorContains(t, err, "search failed") 465 }) 466 467 t.Run("remove command with non-existent movie ID", func(t *testing.T) { 468 cmd := NewMovieCommand(handler).Create() 469 cmd.SetArgs([]string{"remove", "999"}) 470 err := cmd.Execute() 471 if err == nil { 472 t.Error("expected movie remove command to fail with non-existent ID") 473 } 474 }) 475 476 t.Run("remove command with non-numeric ID", func(t *testing.T) { 477 cmd := NewMovieCommand(handler).Create() 478 cmd.SetArgs([]string{"remove", "invalid"}) 479 err := cmd.Execute() 480 if err == nil { 481 t.Error("expected movie remove command to fail with non-numeric ID") 482 } 483 }) 484 }) 485 486 t.Run("TV Commands", func(t *testing.T) { 487 handler, cleanup := createTestTVHandler(t) 488 defer cleanup() 489 490 t.Run("list command - default", func(t *testing.T) { 491 cmd := NewTVCommand(handler).Create() 492 cmd.SetArgs([]string{"list"}) 493 err := cmd.Execute() 494 if err != nil { 495 t.Errorf("tv list command failed: %v", err) 496 } 497 }) 498 499 t.Run("add command with empty args", func(t *testing.T) { 500 cmd := NewTVCommand(handler).Create() 501 cmd.SetArgs([]string{"add"}) 502 err := cmd.Execute() 503 if err == nil { 504 t.Error("expected tv add command to fail with empty args") 505 } 506 }) 507 508 t.Run("add command with valid args - successful search", func(t *testing.T) { 509 cleanup := services.SetupSuccessfulTVMocks(t) 510 defer cleanup() 511 512 cmd := NewTVCommand(handler).Create() 513 cmd.SetArgs([]string{"add", "Peacemaker"}) 514 err := cmd.Execute() 515 516 // NOTE: The command will find results but fail due to no user input in test environment 517 if err == nil { 518 t.Error("expected tv add command to fail due to no user input in test environment") 519 } 520 if !strings.Contains(err.Error(), "invalid input") { 521 t.Errorf("expected 'invalid input' error, got: %v", err) 522 } 523 }) 524 525 t.Run("add command with valid args - search failure", func(t *testing.T) { 526 cleanup := services.SetupFailureMocks(t, "tv search failed") 527 defer cleanup() 528 529 cmd := NewTVCommand(handler).Create() 530 cmd.SetArgs([]string{"add", "some show"}) 531 err := cmd.Execute() 532 if err == nil { 533 t.Error("expected tv add command to fail when search fails") 534 } 535 services.AssertErrorContains(t, err, "tv search failed") 536 }) 537 538 t.Run("remove command with non-existent TV show ID", func(t *testing.T) { 539 cmd := NewTVCommand(handler).Create() 540 cmd.SetArgs([]string{"remove", "999"}) 541 err := cmd.Execute() 542 if err == nil { 543 t.Error("expected tv remove command to fail with non-existent ID") 544 } 545 }) 546 547 t.Run("remove command with non-numeric ID", func(t *testing.T) { 548 cmd := NewTVCommand(handler).Create() 549 cmd.SetArgs([]string{"remove", "invalid"}) 550 err := cmd.Execute() 551 if err == nil { 552 t.Error("expected tv remove command to fail with non-numeric ID") 553 } 554 }) 555 }) 556 557 t.Run("Book Commands", func(t *testing.T) { 558 handler, cleanup := createTestBookHandler(t) 559 defer cleanup() 560 561 t.Run("list command - default", func(t *testing.T) { 562 cmd := NewBookCommand(handler).Create() 563 cmd.SetArgs([]string{"list"}) 564 err := cmd.Execute() 565 if err != nil { 566 t.Errorf("book list command failed: %v", err) 567 } 568 }) 569 570 t.Run("remove command with non-existent book ID", func(t *testing.T) { 571 cmd := NewBookCommand(handler).Create() 572 cmd.SetArgs([]string{"remove", "999"}) 573 err := cmd.Execute() 574 if err == nil { 575 t.Error("expected book remove command to fail with non-existent ID") 576 } 577 }) 578 579 t.Run("remove command with non-numeric ID", func(t *testing.T) { 580 cmd := NewBookCommand(handler).Create() 581 cmd.SetArgs([]string{"remove", "invalid"}) 582 err := cmd.Execute() 583 if err == nil { 584 t.Error("expected book remove command to fail with non-numeric ID") 585 } 586 }) 587 588 t.Run("update command with removed status", func(t *testing.T) { 589 cmd := NewBookCommand(handler).Create() 590 cmd.SetArgs([]string{"update", "999", "removed"}) 591 err := cmd.Execute() 592 if err == nil { 593 t.Error("expected book update command to fail with non-existent ID") 594 } 595 }) 596 597 t.Run("update command with invalid status", func(t *testing.T) { 598 cmd := NewBookCommand(handler).Create() 599 cmd.SetArgs([]string{"update", "1", "invalid_status"}) 600 err := cmd.Execute() 601 if err == nil { 602 t.Error("expected book update command to fail with invalid status") 603 } 604 }) 605 }) 606 607 t.Run("Article Commands", func(t *testing.T) { 608 handler, cleanup := createTestArticleHandler(t) 609 defer cleanup() 610 611 t.Run("list command - default", func(t *testing.T) { 612 cmd := NewArticleCommand(handler).Create() 613 cmd.SetArgs([]string{"list"}) 614 err := cmd.Execute() 615 if err != nil { 616 t.Errorf("article list command failed: %v", err) 617 } 618 }) 619 620 t.Run("help command", func(t *testing.T) { 621 cmd := NewArticleCommand(handler).Create() 622 cmd.SetArgs([]string{"help"}) 623 err := cmd.Execute() 624 if err != nil { 625 t.Errorf("article help command failed: %v", err) 626 } 627 }) 628 629 t.Run("add command with empty args", func(t *testing.T) { 630 cmd := NewArticleCommand(handler).Create() 631 cmd.SetArgs([]string{"add"}) 632 err := cmd.Execute() 633 if err == nil { 634 t.Error("expected article add command to fail with empty args") 635 } 636 }) 637 638 t.Run("add command with invalid URL", func(t *testing.T) { 639 cmd := NewArticleCommand(handler).Create() 640 cmd.SetArgs([]string{"add", "not-a-url"}) 641 err := cmd.Execute() 642 if err == nil { 643 t.Error("expected article add command to fail with invalid URL") 644 } 645 }) 646 647 t.Run("view command with non-existent article ID", func(t *testing.T) { 648 cmd := NewArticleCommand(handler).Create() 649 cmd.SetArgs([]string{"view", "999"}) 650 err := cmd.Execute() 651 if err == nil { 652 t.Error("expected article view command to fail with non-existent ID") 653 } 654 }) 655 656 t.Run("view command with non-numeric ID", func(t *testing.T) { 657 cmd := NewArticleCommand(handler).Create() 658 cmd.SetArgs([]string{"view", "invalid"}) 659 err := cmd.Execute() 660 if err == nil { 661 t.Error("expected article view command to fail with non-numeric ID") 662 } 663 }) 664 665 t.Run("remove command with non-existent article ID", func(t *testing.T) { 666 cmd := NewArticleCommand(handler).Create() 667 cmd.SetArgs([]string{"remove", "999"}) 668 err := cmd.Execute() 669 if err == nil { 670 t.Error("expected article remove command to fail with non-existent ID") 671 } 672 }) 673 674 t.Run("remove command with non-numeric ID", func(t *testing.T) { 675 cmd := NewArticleCommand(handler).Create() 676 cmd.SetArgs([]string{"remove", "invalid"}) 677 err := cmd.Execute() 678 if err == nil { 679 t.Error("expected article remove command to fail with non-numeric ID") 680 } 681 }) 682 }) 683 684 t.Run("Note Commands", func(t *testing.T) { 685 t.Run("create command - non-interactive", func(t *testing.T) { 686 handler, cleanup := createTestNoteHandler(t) 687 defer cleanup() 688 689 cmd := NewNoteCommand(handler).Create() 690 cmd.SetArgs([]string{"create", "test title", "test content"}) 691 err := cmd.Execute() 692 if err != nil { 693 t.Errorf("note create command failed: %v", err) 694 } 695 }) 696 697 t.Run("list command - static mode", func(t *testing.T) { 698 handler, cleanup := createTestNoteHandler(t) 699 defer cleanup() 700 701 cmd := NewNoteCommand(handler).Create() 702 cmd.SetArgs([]string{"list", "--static"}) 703 err := cmd.Execute() 704 if err != nil { 705 t.Errorf("note list command failed: %v", err) 706 } 707 }) 708 709 t.Run("read command with valid note ID", func(t *testing.T) { 710 handler, cleanup := createTestNoteHandler(t) 711 defer cleanup() 712 713 err := handler.CreateWithOptions(context.Background(), "test note", "test content", "", false, false) 714 if err != nil { 715 t.Fatalf("failed to create test note: %v", err) 716 } 717 718 cmd := NewNoteCommand(handler).Create() 719 cmd.SetArgs([]string{"read", "1"}) 720 err = cmd.Execute() 721 if err != nil { 722 t.Errorf("note read command failed: %v", err) 723 } 724 }) 725 726 t.Run("edit command with valid note ID", func(t *testing.T) { 727 t.Skip("edit command requires interactive editor") 728 }) 729 730 t.Run("remove command with valid note ID", func(t *testing.T) { 731 handler, cleanup := createTestNoteHandler(t) 732 defer cleanup() 733 734 err := handler.CreateWithOptions(context.Background(), "test note", "test content", "", false, false) 735 if err != nil { 736 t.Fatalf("failed to create test note: %v", err) 737 } 738 739 cmd := NewNoteCommand(handler).Create() 740 cmd.SetArgs([]string{"remove", "1"}) 741 err = cmd.Execute() 742 if err != nil { 743 t.Errorf("note remove command failed: %v", err) 744 } 745 }) 746 }) 747 748 t.Run("Task Commands", func(t *testing.T) { 749 t.Run("list command - static", func(t *testing.T) { 750 handler, cleanup := createTestTaskHandler(t) 751 defer cleanup() 752 753 cmd := NewTaskCommand(handler).Create() 754 cmd.SetArgs([]string{"list", "--static"}) 755 err := cmd.Execute() 756 if err != nil { 757 t.Errorf("task list command failed: %v", err) 758 } 759 }) 760 761 t.Run("add command with valid args", func(t *testing.T) { 762 handler, cleanup := createTestTaskHandler(t) 763 defer cleanup() 764 765 cmd := NewTaskCommand(handler).Create() 766 cmd.SetArgs([]string{"add", "test task"}) 767 err := cmd.Execute() 768 if err != nil { 769 t.Errorf("task add command failed: %v", err) 770 } 771 }) 772 773 t.Run("projects command - static", func(t *testing.T) { 774 handler, cleanup := createTestTaskHandler(t) 775 defer cleanup() 776 777 cmd := NewTaskCommand(handler).Create() 778 cmd.SetArgs([]string{"projects", "--static"}) 779 err := cmd.Execute() 780 if err != nil { 781 t.Errorf("task projects command failed: %v", err) 782 } 783 }) 784 785 t.Run("tags command - static", func(t *testing.T) { 786 handler, cleanup := createTestTaskHandler(t) 787 defer cleanup() 788 789 cmd := NewTaskCommand(handler).Create() 790 cmd.SetArgs([]string{"tags", "--static"}) 791 err := cmd.Execute() 792 if err != nil { 793 t.Errorf("task tags command failed: %v", err) 794 } 795 }) 796 797 t.Run("contexts command - static", func(t *testing.T) { 798 handler, cleanup := createTestTaskHandler(t) 799 defer cleanup() 800 801 cmd := NewTaskCommand(handler).Create() 802 cmd.SetArgs([]string{"contexts", "--static"}) 803 err := cmd.Execute() 804 if err != nil { 805 t.Errorf("task contexts command failed: %v", err) 806 } 807 }) 808 809 t.Run("timesheet command", func(t *testing.T) { 810 handler, cleanup := createTestTaskHandler(t) 811 defer cleanup() 812 813 cmd := NewTaskCommand(handler).Create() 814 cmd.SetArgs([]string{"timesheet"}) 815 err := cmd.Execute() 816 if err != nil { 817 t.Errorf("task timesheet command failed: %v", err) 818 } 819 }) 820 }) 821}