summaryrefslogtreecommitdiff
path: root/internal/api/todoist_test.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-02-03 15:16:35 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-02-03 15:16:35 -1000
commit25a5b7ecf9ddd31da54e91f87988b77aea857571 (patch)
tree30654edbdd966cea316a5f54a99474aad337cf58 /internal/api/todoist_test.go
parent9f35f7149d8fb790bbe8e4f0ee74f895aea1fc58 (diff)
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 <noreply@anthropic.com>
Diffstat (limited to 'internal/api/todoist_test.go')
-rw-r--r--internal/api/todoist_test.go183
1 files changed, 183 insertions, 0 deletions
diff --git a/internal/api/todoist_test.go b/internal/api/todoist_test.go
index 7bbcc1e..f7ca719 100644
--- a/internal/api/todoist_test.go
+++ b/internal/api/todoist_test.go
@@ -246,3 +246,186 @@ func TestTodoistClient_GetProjects(t *testing.T) {
t.Errorf("Project 2 mismatch: got ID=%s Name=%s", projects[1].ID, projects[1].Name)
}
}
+
+func TestTodoistClient_GetTasks(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)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+
+ // GetTasks also calls GetProjects internally
+ if r.URL.Path == "/projects" {
+ response := []todoistProjectResponse{
+ {ID: "proj-1", Name: "Project 1"},
+ }
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ if r.URL.Path == "/tasks" {
+ response := []todoistTaskResponse{
+ {ID: "task-1", Content: "Task 1", ProjectID: "proj-1", CreatedAt: time.Now().Format(time.RFC3339)},
+ {ID: "task-2", Content: "Task 2", ProjectID: "proj-1", CreatedAt: time.Now().Format(time.RFC3339)},
+ }
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ t.Errorf("Unexpected path: %s", r.URL.Path)
+ }))
+ defer server.Close()
+
+ client := newTestTodoistClient(server.URL, "test-key")
+ tasks, err := client.GetTasks(context.Background())
+ if err != nil {
+ t.Fatalf("GetTasks failed: %v", err)
+ }
+
+ if len(tasks) != 2 {
+ t.Errorf("Expected 2 tasks, got %d", len(tasks))
+ }
+}
+
+func TestTodoistClient_ReopenTask(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ t.Errorf("Expected POST, got %s", r.Method)
+ }
+ expectedPath := "/tasks/task-123/reopen"
+ if r.URL.Path != expectedPath {
+ t.Errorf("Expected path %s, got %s", expectedPath, r.URL.Path)
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+ }))
+ defer server.Close()
+
+ client := newTestTodoistClient(server.URL, "test-key")
+ err := client.ReopenTask(context.Background(), "task-123")
+ if err != nil {
+ t.Fatalf("ReopenTask failed: %v", err)
+ }
+}
+
+func TestTodoistClient_UpdateTask(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ t.Errorf("Expected POST, got %s", r.Method)
+ }
+ expectedPath := "/tasks/task-123"
+ if r.URL.Path != expectedPath {
+ t.Errorf("Expected path %s, got %s", expectedPath, r.URL.Path)
+ }
+
+ var payload map[string]interface{}
+ json.NewDecoder(r.Body).Decode(&payload)
+ if payload["content"] != "Updated Content" {
+ t.Errorf("Expected content 'Updated Content', got %v", payload["content"])
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(map[string]string{"id": "task-123"})
+ }))
+ defer server.Close()
+
+ client := newTestTodoistClient(server.URL, "test-key")
+ err := client.UpdateTask(context.Background(), "task-123", map[string]interface{}{"content": "Updated Content"})
+ if err != nil {
+ t.Fatalf("UpdateTask failed: %v", err)
+ }
+}
+
+func TestTodoistClient_Sync(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ t.Errorf("Expected POST, got %s", r.Method)
+ }
+ if r.URL.Path != "/sync" {
+ t.Errorf("Expected path /sync, got %s", r.URL.Path)
+ }
+
+ response := TodoistSyncResponse{
+ SyncToken: "new-sync-token",
+ FullSync: true,
+ Items: []SyncItemResponse{
+ {ID: "item-1", Content: "Item 1", ProjectID: "proj-1"},
+ },
+ Projects: []SyncProjectResponse{
+ {ID: "proj-1", Name: "Project 1"},
+ },
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ }))
+ defer server.Close()
+
+ client := newTestTodoistClient(server.URL, "test-key")
+ resp, err := client.Sync(context.Background(), "*")
+ if err != nil {
+ t.Fatalf("Sync failed: %v", err)
+ }
+
+ if resp.SyncToken != "new-sync-token" {
+ t.Errorf("Expected sync token 'new-sync-token', got '%s'", resp.SyncToken)
+ }
+ if len(resp.Items) != 1 {
+ t.Errorf("Expected 1 item, got %d", len(resp.Items))
+ }
+}
+
+func TestConvertSyncItemsToTasks(t *testing.T) {
+ projects := map[string]string{
+ "proj-1": "Project 1",
+ }
+
+ items := []SyncItemResponse{
+ {
+ ID: "item-1",
+ Content: "Task 1",
+ Description: "Description 1",
+ ProjectID: "proj-1",
+ Priority: 3,
+ Labels: []string{"label1"},
+ },
+ {
+ ID: "item-2",
+ Content: "Completed Task",
+ ProjectID: "proj-1",
+ IsCompleted: true,
+ },
+ }
+
+ tasks := ConvertSyncItemsToTasks(items, projects)
+
+ // Should skip completed task
+ if len(tasks) != 1 {
+ t.Errorf("Expected 1 task (excluding completed), got %d", len(tasks))
+ }
+
+ if tasks[0].ID != "item-1" {
+ t.Errorf("Expected task ID 'item-1', got '%s'", tasks[0].ID)
+ }
+ if tasks[0].ProjectName != "Project 1" {
+ t.Errorf("Expected project name 'Project 1', got '%s'", tasks[0].ProjectName)
+ }
+}
+
+func TestBuildProjectMapFromSync(t *testing.T) {
+ projects := []SyncProjectResponse{
+ {ID: "proj-1", Name: "Project 1"},
+ {ID: "proj-2", Name: "Project 2"},
+ }
+
+ projectMap := BuildProjectMapFromSync(projects)
+
+ if len(projectMap) != 2 {
+ t.Errorf("Expected 2 projects in map, got %d", len(projectMap))
+ }
+
+ if projectMap["proj-1"] != "Project 1" {
+ t.Errorf("Expected 'Project 1', got '%s'", projectMap["proj-1"])
+ }
+}