cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package handlers
2
3import (
4 "context"
5 "os"
6 "runtime"
7 "strings"
8 "testing"
9
10 "github.com/stormlightlabs/noteleaf/internal/store"
11)
12
13func countRecords(t *testing.T, db *store.Database, table string) int {
14 t.Helper()
15
16 var count int
17 query := "SELECT COUNT(*) FROM " + table
18 err := db.QueryRow(query).Scan(&count)
19 if err != nil {
20 t.Fatalf("Failed to count records in %s: %v", table, err)
21 }
22 return count
23}
24
25func getTaskRecord(t *testing.T, db *store.Database, id int) (description, project, priority, status string) {
26 t.Helper()
27
28 query := "SELECT description, project, priority, status FROM tasks WHERE id = ?"
29 err := db.QueryRow(query, id).Scan(&description, &project, &priority, &status)
30 if err != nil {
31 t.Fatalf("Failed to get task record: %v", err)
32 }
33 return description, project, priority, status
34}
35
36func getBookRecord(t *testing.T, db *store.Database, id int) (title, author, status string, progress int) {
37 t.Helper()
38
39 query := "SELECT title, author, status, progress FROM books WHERE id = ?"
40 err := db.QueryRow(query, id).Scan(&title, &author, &status, &progress)
41 if err != nil {
42 t.Fatalf("Failed to get book record: %v", err)
43 }
44 return title, author, status, progress
45}
46
47func TestSeedHandler(t *testing.T) {
48 _ = NewHandlerTestSuite(t)
49
50 handler, err := NewSeedHandler()
51 if err != nil {
52 t.Fatalf("Failed to create seed handler: %v", err)
53 }
54 defer handler.Close()
55
56 ctx := context.Background()
57
58 t.Run("New", func(t *testing.T) {
59 t.Run("creates handler successfully", func(t *testing.T) {
60 testHandler, err := NewSeedHandler()
61 if err != nil {
62 t.Fatalf("NewSeedHandler failed: %v", err)
63 }
64 if testHandler == nil {
65 t.Fatal("Handler should not be nil")
66 }
67 defer testHandler.Close()
68
69 if testHandler.db == nil {
70 t.Error("Handler database should not be nil")
71 }
72 if testHandler.config == nil {
73 t.Error("Handler config should not be nil")
74 }
75 if testHandler.repos == nil {
76 t.Error("Handler repos should not be nil")
77 }
78 })
79
80 t.Run("handles database initialization error", func(t *testing.T) {
81 originalXDG := os.Getenv("XDG_CONFIG_HOME")
82 originalHome := os.Getenv("HOME")
83 originalNoteleafConfig := os.Getenv("NOTELEAF_CONFIG")
84 originalNoteleafDataDir := os.Getenv("NOTELEAF_DATA_DIR")
85
86 if runtime.GOOS == "windows" {
87 originalAppData := os.Getenv("APPDATA")
88 os.Unsetenv("APPDATA")
89 defer os.Setenv("APPDATA", originalAppData)
90 } else {
91 os.Unsetenv("XDG_CONFIG_HOME")
92 os.Unsetenv("HOME")
93 }
94 os.Unsetenv("NOTELEAF_CONFIG")
95 os.Unsetenv("NOTELEAF_DATA_DIR")
96
97 defer func() {
98 os.Setenv("XDG_CONFIG_HOME", originalXDG)
99 os.Setenv("HOME", originalHome)
100 os.Setenv("NOTELEAF_CONFIG", originalNoteleafConfig)
101 os.Setenv("NOTELEAF_DATA_DIR", originalNoteleafDataDir)
102 }()
103
104 _, err := NewSeedHandler()
105 if err == nil {
106 t.Error("NewSeedHandler should fail when database initialization fails")
107 }
108 if !strings.Contains(err.Error(), "failed to initialize database") {
109 t.Errorf("Expected database error, got: %v", err)
110 }
111 })
112 })
113
114 t.Run("Seed", func(t *testing.T) {
115 t.Run("seeds database with test data", func(t *testing.T) {
116 err := handler.Seed(ctx, false)
117 if err != nil {
118 t.Fatalf("Seed failed: %v", err)
119 }
120
121 taskCount := countRecords(t, handler.db, "tasks")
122 if taskCount != 5 {
123 t.Errorf("Expected 5 tasks, got %d", taskCount)
124 }
125
126 bookCount := countRecords(t, handler.db, "books")
127 if bookCount != 5 {
128 t.Errorf("Expected 5 books, got %d", bookCount)
129 }
130
131 desc, proj, prio, status := getTaskRecord(t, handler.db, 1)
132 if desc != "Review quarterly report" {
133 t.Errorf("Expected 'Review quarterly report', got '%s'", desc)
134 }
135 if proj != "work" {
136 t.Errorf("Expected 'work' project, got '%s'", proj)
137 }
138 if prio != "high" {
139 t.Errorf("Expected 'high' priority, got '%s'", prio)
140 }
141 if status != "pending" {
142 t.Errorf("Expected 'pending' status, got '%s'", status)
143 }
144
145 title, author, bookStatus, progress := getBookRecord(t, handler.db, 1)
146 if title != "The Go Programming Language" {
147 t.Errorf("Expected 'The Go Programming Language', got '%s'", title)
148 }
149 if author != "Alan Donovan" {
150 t.Errorf("Expected 'Alan Donovan', got '%s'", author)
151 }
152 if bookStatus != "reading" {
153 t.Errorf("Expected 'reading' status, got '%s'", bookStatus)
154 }
155 if progress != 45 {
156 t.Errorf("Expected 45%% progress, got %d", progress)
157 }
158 })
159
160 t.Run("seeds without force flag preserves existing data", func(t *testing.T) {
161 err := handler.Seed(ctx, false)
162 if err != nil {
163 t.Fatalf("First seed failed: %v", err)
164 }
165
166 initialTaskCount := countRecords(t, handler.db, "tasks")
167 initialBookCount := countRecords(t, handler.db, "books")
168
169 err = handler.Seed(ctx, false)
170 if err != nil {
171 t.Fatalf("Second seed failed: %v", err)
172 }
173
174 finalTaskCount := countRecords(t, handler.db, "tasks")
175 finalBookCount := countRecords(t, handler.db, "books")
176
177 expectedTasks := initialTaskCount + 5
178 expectedBooks := initialBookCount + 5
179
180 if finalTaskCount != expectedTasks {
181 t.Errorf("Expected %d tasks after second seed, got %d", expectedTasks, finalTaskCount)
182 }
183 if finalBookCount != expectedBooks {
184 t.Errorf("Expected %d books after second seed, got %d", expectedBooks, finalBookCount)
185 }
186 })
187
188 t.Run("force flag clears existing data before seeding", func(t *testing.T) {
189 err := handler.Seed(ctx, false)
190 if err != nil {
191 t.Fatalf("Initial seed failed: %v", err)
192 }
193
194 if countRecords(t, handler.db, "tasks") == 0 {
195 t.Fatal("No tasks found after initial seed")
196 }
197 if countRecords(t, handler.db, "books") == 0 {
198 t.Fatal("No books found after initial seed")
199 }
200
201 err = handler.Seed(ctx, true)
202 if err != nil {
203 t.Fatalf("Force seed failed: %v", err)
204 }
205
206 taskCount := countRecords(t, handler.db, "tasks")
207 bookCount := countRecords(t, handler.db, "books")
208
209 if taskCount != 5 {
210 t.Errorf("Expected exactly 5 tasks after force seed, got %d", taskCount)
211 }
212 if bookCount != 5 {
213 t.Errorf("Expected exactly 5 books after force seed, got %d", bookCount)
214 }
215
216 _, _, _, _ = getTaskRecord(t, handler.db, 1) // Should not error
217 _, _, _, _ = getBookRecord(t, handler.db, 1) // Should not error
218 })
219 })
220
221 t.Run("Close", func(t *testing.T) {
222 testHandler, err := NewSeedHandler()
223 if err != nil {
224 t.Fatalf("Failed to create test handler: %v", err)
225 }
226
227 if err = testHandler.Close(); err != nil {
228 t.Errorf("Close should succeed: %v", err)
229 }
230 })
231}