From 25a5b7ecf9ddd31da54e91f87988b77aea857571 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 3 Feb 2026 15:16:35 -1000 Subject: Add comprehensive test coverage across packages New test files: - api/http_test.go: HTTP client and error handling tests - config/config_test.go: Configuration loading and validation tests - middleware/security_test.go: Security middleware tests - models/atom_test.go: Atom model and conversion tests Expanded test coverage: - api/todoist_test.go: Todoist API client tests - api/trello_test.go: Trello API client tests - auth/auth_test.go: Authentication and CSRF tests - handlers/timeline_logic_test.go: Timeline building logic tests - store/sqlite_test.go: SQLite store operations tests Co-Authored-By: Claude Opus 4.5 --- internal/api/trello_test.go | 164 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) (limited to 'internal/api/trello_test.go') diff --git a/internal/api/trello_test.go b/internal/api/trello_test.go index d677363..a209d01 100644 --- a/internal/api/trello_test.go +++ b/internal/api/trello_test.go @@ -239,3 +239,167 @@ func parseFormData(data string) (map[string]string, error) { } return result, nil } + +func TestTrelloClient_GetBoards(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + t.Errorf("Expected GET, got %s", r.Method) + } + if r.URL.Path != "/members/me/boards" { + t.Errorf("Expected path /members/me/boards, got %s", r.URL.Path) + } + + response := []trelloBoardResponse{ + {ID: "board-1", Name: "Board 1"}, + {ID: "board-2", Name: "Board 2"}, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + })) + defer server.Close() + + client := newTestTrelloClient(server.URL, "test-key", "test-token") + boards, err := client.GetBoards(context.Background()) + if err != nil { + t.Fatalf("GetBoards failed: %v", err) + } + + if len(boards) != 2 { + t.Errorf("Expected 2 boards, got %d", len(boards)) + } + if boards[0].ID != "board-1" { + t.Errorf("Expected board ID 'board-1', got '%s'", boards[0].ID) + } +} + +func TestTrelloClient_GetCards(t *testing.T) { + dueDate := "2024-01-15T12:00:00Z" + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + t.Errorf("Expected GET, got %s", r.Method) + } + + w.Header().Set("Content-Type", "application/json") + + // GetCards calls getLists internally + if strings.Contains(r.URL.Path, "/lists") { + response := []trelloListResponse{ + {ID: "list-1", Name: "To Do"}, + } + json.NewEncoder(w).Encode(response) + return + } + + if strings.Contains(r.URL.Path, "/cards") { + response := []trelloCardResponse{ + {ID: "card-1", Name: "Card 1", IDList: "list-1", IDBoard: "board-1", Due: &dueDate}, + {ID: "card-2", Name: "Card 2", IDList: "list-1", IDBoard: "board-1"}, + } + json.NewEncoder(w).Encode(response) + return + } + + t.Errorf("Unexpected path: %s", r.URL.Path) + })) + defer server.Close() + + client := newTestTrelloClient(server.URL, "test-key", "test-token") + cards, err := client.GetCards(context.Background(), "board-1") + if err != nil { + t.Fatalf("GetCards failed: %v", err) + } + + if len(cards) != 2 { + t.Errorf("Expected 2 cards, got %d", len(cards)) + } + if cards[0].DueDate == nil { + t.Error("Expected due date for card 1") + } +} + +func TestTrelloClient_GetLists(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + t.Errorf("Expected GET, got %s", r.Method) + } + if !strings.Contains(r.URL.Path, "/boards/board-1/lists") { + t.Errorf("Expected path to contain /boards/board-1/lists, got %s", r.URL.Path) + } + + response := []trelloListResponse{ + {ID: "list-1", Name: "To Do"}, + {ID: "list-2", Name: "Done"}, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + })) + defer server.Close() + + client := newTestTrelloClient(server.URL, "test-key", "test-token") + lists, err := client.GetLists(context.Background(), "board-1") + if err != nil { + t.Fatalf("GetLists failed: %v", err) + } + + if len(lists) != 2 { + t.Errorf("Expected 2 lists, got %d", len(lists)) + } + if lists[0].Name != "To Do" { + t.Errorf("Expected 'To Do', got '%s'", lists[0].Name) + } +} + +func TestTrelloClient_GetBoardsWithCards(t *testing.T) { + requestCount := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestCount++ + + if strings.Contains(r.URL.Path, "/members/me/boards") { + response := []trelloBoardResponse{ + {ID: "board-1", Name: "Board 1"}, + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + return + } + + if strings.Contains(r.URL.Path, "/lists") { + response := []trelloListResponse{ + {ID: "list-1", Name: "To Do"}, + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + return + } + + if strings.Contains(r.URL.Path, "/cards") { + response := []trelloCardResponse{ + {ID: "card-1", Name: "Card 1", IDList: "list-1", IDBoard: "board-1"}, + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + return + } + + t.Errorf("Unexpected path: %s", r.URL.Path) + })) + defer server.Close() + + client := newTestTrelloClient(server.URL, "test-key", "test-token") + boards, err := client.GetBoardsWithCards(context.Background()) + if err != nil { + t.Fatalf("GetBoardsWithCards failed: %v", err) + } + + if len(boards) != 1 { + t.Errorf("Expected 1 board, got %d", len(boards)) + } + if len(boards[0].Cards) != 1 { + t.Errorf("Expected 1 card, got %d", len(boards[0].Cards)) + } + if boards[0].Cards[0].ListName != "To Do" { + t.Errorf("Expected list name 'To Do', got '%s'", boards[0].Cards[0].ListName) + } +} -- cgit v1.2.3