cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package repo
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 _ "github.com/mattn/go-sqlite3"
9 "github.com/stormlightlabs/noteleaf/internal/models"
10 "github.com/stormlightlabs/noteleaf/internal/shared"
11)
12
13func TestNoteRepository(t *testing.T) {
14 t.Run("CRUD Operations", func(t *testing.T) {
15 db := CreateTestDB(t)
16 repo := NewNoteRepository(db)
17 ctx := context.Background()
18
19 t.Run("Create Note", func(t *testing.T) {
20 note := CreateSampleNote()
21
22 id, err := repo.Create(ctx, note)
23 shared.AssertNoError(t, err, "Failed to create note")
24 shared.AssertNotEqual(t, int64(0), id, "Expected non-zero ID")
25 shared.AssertEqual(t, id, note.ID, "Expected note ID to be set correctly")
26 shared.AssertFalse(t, note.Created.IsZero(), "Expected Created timestamp to be set")
27 shared.AssertFalse(t, note.Modified.IsZero(), "Expected Modified timestamp to be set")
28 })
29
30 t.Run("Get Note", func(t *testing.T) {
31 original := CreateSampleNote()
32 id, err := repo.Create(ctx, original)
33 shared.AssertNoError(t, err, "Failed to create note")
34
35 retrieved, err := repo.Get(ctx, id)
36 shared.AssertNoError(t, err, "Failed to get note")
37
38 shared.AssertEqual(t, original.ID, retrieved.ID, "ID mismatch")
39 shared.AssertEqual(t, original.Title, retrieved.Title, "Title mismatch")
40 shared.AssertEqual(t, original.Content, retrieved.Content, "Content mismatch")
41 shared.AssertEqual(t, len(original.Tags), len(retrieved.Tags), "Tags length mismatch")
42 shared.AssertEqual(t, original.Archived, retrieved.Archived, "Archived mismatch")
43 shared.AssertEqual(t, original.FilePath, retrieved.FilePath, "FilePath mismatch")
44 })
45
46 t.Run("Update Note", func(t *testing.T) {
47 note := CreateSampleNote()
48 id, err := repo.Create(ctx, note)
49 shared.AssertNoError(t, err, "Failed to create note")
50
51 originalModified := note.Modified
52
53 note.Title = "Updated Title"
54 note.Content = "Updated content"
55 note.Tags = []string{"updated", "test"}
56 note.Archived = true
57 note.FilePath = "/new/path/note.md"
58
59 err = repo.Update(ctx, note)
60 shared.AssertNoError(t, err, "Failed to update note")
61
62 retrieved, err := repo.Get(ctx, id)
63 shared.AssertNoError(t, err, "Failed to get updated note")
64
65 shared.AssertEqual(t, "Updated Title", retrieved.Title, "Expected updated title")
66 shared.AssertEqual(t, "Updated content", retrieved.Content, "Expected updated content")
67 shared.AssertEqual(t, 2, len(retrieved.Tags), "Expected 2 tags")
68 if len(retrieved.Tags) >= 2 {
69 shared.AssertEqual(t, "updated", retrieved.Tags[0], "Expected first tag to be 'updated'")
70 shared.AssertEqual(t, "test", retrieved.Tags[1], "Expected second tag to be 'test'")
71 }
72 shared.AssertTrue(t, retrieved.Archived, "Expected note to be archived")
73 shared.AssertEqual(t, "/new/path/note.md", retrieved.FilePath, "Expected updated file path")
74 shared.AssertTrue(t, retrieved.Modified.After(originalModified), "Expected Modified timestamp to be updated")
75 })
76
77 t.Run("Delete Note", func(t *testing.T) {
78 note := CreateSampleNote()
79 id, err := repo.Create(ctx, note)
80 shared.AssertNoError(t, err, "Failed to create note")
81
82 err = repo.Delete(ctx, id)
83 shared.AssertNoError(t, err, "Failed to delete note")
84
85 _, err = repo.Get(ctx, id)
86 shared.AssertError(t, err, "Expected error when getting deleted note")
87 })
88 })
89
90 t.Run("List", func(t *testing.T) {
91 db := CreateTestDB(t)
92 repo := NewNoteRepository(db)
93 ctx := context.Background()
94
95 notes := []*models.Note{
96 {Title: "First Note", Content: "Content 1", Tags: []string{"work"}, Archived: false},
97 {Title: "Second Note", Content: "Content 2", Tags: []string{"personal"}, Archived: true},
98 {Title: "Third Note", Content: "Important content", Tags: []string{"work", "important"}, Archived: false},
99 }
100
101 for _, note := range notes {
102 _, err := repo.Create(ctx, note)
103 shared.AssertNoError(t, err, "Failed to create test note")
104 }
105
106 t.Run("List All Notes", func(t *testing.T) {
107 results, err := repo.List(ctx, NoteListOptions{})
108 shared.AssertNoError(t, err, "Failed to list notes")
109 shared.AssertEqual(t, 3, len(results), "Expected 3 notes")
110 })
111
112 t.Run("List Archived Notes Only", func(t *testing.T) {
113 archived := true
114 results, err := repo.List(ctx, NoteListOptions{Archived: &archived})
115 shared.AssertNoError(t, err, "Failed to list archived notes")
116 shared.AssertEqual(t, 1, len(results), "Expected 1 archived note")
117 if len(results) > 0 {
118 shared.AssertTrue(t, results[0].Archived, "Retrieved note should be archived")
119 }
120 })
121
122 t.Run("List Active Notes Only", func(t *testing.T) {
123 archived := false
124 results, err := repo.List(ctx, NoteListOptions{Archived: &archived})
125 shared.AssertNoError(t, err, "Failed to list active notes")
126 shared.AssertEqual(t, 2, len(results), "Expected 2 active notes")
127 for _, note := range results {
128 shared.AssertFalse(t, note.Archived, "Retrieved note should not be archived")
129 }
130 })
131
132 t.Run("Search by Title", func(t *testing.T) {
133 results, err := repo.List(ctx, NoteListOptions{Title: "First"})
134 shared.AssertNoError(t, err, "Failed to search by title")
135 shared.AssertEqual(t, 1, len(results), "Expected 1 note")
136 if len(results) > 0 {
137 shared.AssertEqual(t, "First Note", results[0].Title, "Expected 'First Note'")
138 }
139 })
140
141 t.Run("Search by Content", func(t *testing.T) {
142 results, err := repo.List(ctx, NoteListOptions{Content: "Important"})
143 shared.AssertNoError(t, err, "Failed to search by content")
144 shared.AssertEqual(t, 1, len(results), "Expected 1 note")
145 if len(results) > 0 {
146 shared.AssertEqual(t, "Third Note", results[0].Title, "Expected 'Third Note'")
147 }
148 })
149
150 t.Run("Limit and Offset", func(t *testing.T) {
151 results, err := repo.List(ctx, NoteListOptions{Limit: 2})
152 shared.AssertNoError(t, err, "Failed to list with limit")
153 shared.AssertEqual(t, 2, len(results), "Expected 2 notes")
154
155 results, err = repo.List(ctx, NoteListOptions{Limit: 2, Offset: 1})
156 shared.AssertNoError(t, err, "Failed to list with limit and offset")
157 shared.AssertEqual(t, 2, len(results), "Expected 2 notes with offset")
158 })
159 })
160
161 t.Run("Special Methods", func(t *testing.T) {
162 db := CreateTestDB(t)
163 repo := NewNoteRepository(db)
164 ctx := context.Background()
165
166 notes := []*models.Note{
167 {Title: "Work Note", Content: "Work content", Tags: []string{"work"}, Archived: false},
168 {Title: "Personal Note", Content: "Personal content", Tags: []string{"personal"}, Archived: true},
169 {Title: "Important Note", Content: "Important content", Tags: []string{"work", "important"}, Archived: false},
170 }
171
172 for _, note := range notes {
173 _, err := repo.Create(ctx, note)
174 shared.AssertNoError(t, err, "Failed to create test note")
175 }
176
177 t.Run("GetByTitle", func(t *testing.T) {
178 results, err := repo.GetByTitle(ctx, "Work")
179 shared.AssertNoError(t, err, "Failed to get by title")
180 shared.AssertEqual(t, 1, len(results), "Expected 1 note")
181 if len(results) > 0 {
182 shared.AssertEqual(t, "Work Note", results[0].Title, "Expected 'Work Note'")
183 }
184 })
185
186 t.Run("GetArchived", func(t *testing.T) {
187 results, err := repo.GetArchived(ctx)
188 shared.AssertNoError(t, err, "Failed to get archived notes")
189 shared.AssertEqual(t, 1, len(results), "Expected 1 archived note")
190 if len(results) > 0 {
191 shared.AssertTrue(t, results[0].Archived, "Retrieved note should be archived")
192 }
193 })
194
195 t.Run("GetActive", func(t *testing.T) {
196 results, err := repo.GetActive(ctx)
197 shared.AssertNoError(t, err, "Failed to get active notes")
198 shared.AssertEqual(t, 2, len(results), "Expected 2 active notes")
199 for _, note := range results {
200 shared.AssertFalse(t, note.Archived, "Retrieved note should not be archived")
201 }
202 })
203
204 t.Run("Archive and Unarchive", func(t *testing.T) {
205 note := &models.Note{
206 Title: "Test Archive",
207 Content: "Archive test",
208 Archived: false,
209 }
210 id, err := repo.Create(ctx, note)
211 shared.AssertNoError(t, err, "Failed to create note")
212
213 err = repo.Archive(ctx, id)
214 shared.AssertNoError(t, err, "Failed to archive note")
215
216 retrieved, err := repo.Get(ctx, id)
217 shared.AssertNoError(t, err, "Failed to get note")
218 shared.AssertTrue(t, retrieved.Archived, "Note should be archived")
219
220 err = repo.Unarchive(ctx, id)
221 shared.AssertNoError(t, err, "Failed to unarchive note")
222
223 retrieved, err = repo.Get(ctx, id)
224 shared.AssertNoError(t, err, "Failed to get note")
225 shared.AssertFalse(t, retrieved.Archived, "Note should not be archived")
226 })
227
228 t.Run("SearchContent", func(t *testing.T) {
229 results, err := repo.SearchContent(ctx, "Important")
230 shared.AssertNoError(t, err, "Failed to search content")
231 shared.AssertEqual(t, 1, len(results), "Expected 1 note")
232 if len(results) > 0 {
233 shared.AssertEqual(t, "Important Note", results[0].Title, "Expected 'Important Note'")
234 }
235 })
236
237 t.Run("GetRecent", func(t *testing.T) {
238 results, err := repo.GetRecent(ctx, 2)
239 shared.AssertNoError(t, err, "Failed to get recent notes")
240 shared.AssertEqual(t, 2, len(results), "Expected 2 notes")
241 })
242 })
243
244 t.Run("Tag Methods", func(t *testing.T) {
245 db := CreateTestDB(t)
246 repo := NewNoteRepository(db)
247 ctx := context.Background()
248
249 note := &models.Note{
250 Title: "Tag Test Note",
251 Content: "Testing tags",
252 Tags: []string{"initial"},
253 }
254 id, err := repo.Create(ctx, note)
255 shared.AssertNoError(t, err, "Failed to create note")
256
257 t.Run("AddTag", func(t *testing.T) {
258 err := repo.AddTag(ctx, id, "new-tag")
259 shared.AssertNoError(t, err, "Failed to add tag")
260
261 retrieved, err := repo.Get(ctx, id)
262 shared.AssertNoError(t, err, "Failed to get note")
263
264 shared.AssertEqual(t, 2, len(retrieved.Tags), "Expected 2 tags")
265
266 found := false
267 for _, tag := range retrieved.Tags {
268 if tag == "new-tag" {
269 found = true
270 break
271 }
272 }
273 shared.AssertTrue(t, found, "New tag not found in note")
274 })
275
276 t.Run("AddTag Duplicate", func(t *testing.T) {
277 err := repo.AddTag(ctx, id, "new-tag")
278 shared.AssertNoError(t, err, "Failed to add duplicate tag")
279
280 retrieved, err := repo.Get(ctx, id)
281 shared.AssertNoError(t, err, "Failed to get note")
282
283 shared.AssertEqual(t, 2, len(retrieved.Tags), "Expected 2 tags (no duplicate)")
284 })
285
286 t.Run("RemoveTag", func(t *testing.T) {
287 err := repo.RemoveTag(ctx, id, "initial")
288 shared.AssertNoError(t, err, "Failed to remove tag")
289
290 retrieved, err := repo.Get(ctx, id)
291 shared.AssertNoError(t, err, "Failed to get note")
292
293 shared.AssertEqual(t, 1, len(retrieved.Tags), "Expected 1 tag after removal")
294
295 for _, tag := range retrieved.Tags {
296 shared.AssertNotEqual(t, "initial", tag, "Removed tag still found in note")
297 }
298 })
299
300 t.Run("GetByTags", func(t *testing.T) {
301 note1 := &models.Note{
302 Title: "Note 1",
303 Content: "Content 1",
304 Tags: []string{"work", "urgent"},
305 }
306 note2 := &models.Note{
307 Title: "Note 2",
308 Content: "Content 2",
309 Tags: []string{"personal", "ideas"},
310 }
311 note3 := &models.Note{
312 Title: "Note 3",
313 Content: "Content 3",
314 Tags: []string{"work", "planning"},
315 }
316
317 _, err := repo.Create(ctx, note1)
318 shared.AssertNoError(t, err, "Failed to create note1")
319 _, err = repo.Create(ctx, note2)
320 shared.AssertNoError(t, err, "Failed to create note2")
321 _, err = repo.Create(ctx, note3)
322 shared.AssertNoError(t, err, "Failed to create note3")
323
324 results, err := repo.GetByTags(ctx, []string{"work"})
325 shared.AssertNoError(t, err, "Failed to get notes by tag")
326 shared.AssertTrue(t, len(results) >= 2, "Expected at least 2 notes with 'work' tag")
327
328 results, err = repo.GetByTags(ctx, []string{"nonexistent"})
329 shared.AssertNoError(t, err, "Failed to get notes by nonexistent tag")
330 shared.AssertEqual(t, 0, len(results), "Expected 0 notes with nonexistent tag")
331
332 results, err = repo.GetByTags(ctx, []string{})
333 shared.AssertNoError(t, err, "Failed to get notes with empty tags")
334 shared.AssertEqual(t, 0, len(results), "Expected 0 notes with empty tag list")
335 })
336 })
337
338 t.Run("Context Cancellation Error Paths", func(t *testing.T) {
339 db := CreateTestDB(t)
340 repo := NewNoteRepository(db)
341 ctx := context.Background()
342
343 note := NewNoteBuilder().WithTitle("Test Note").WithContent("Test content").Build()
344 id, err := repo.Create(ctx, note)
345 shared.AssertNoError(t, err, "Failed to create note")
346
347 t.Run("Create with cancelled context", func(t *testing.T) {
348 newNote := NewNoteBuilder().WithTitle("Cancelled").Build()
349 _, err := repo.Create(NewCanceledContext(), newNote)
350 AssertCancelledContext(t, err)
351 })
352
353 t.Run("Get with cancelled context", func(t *testing.T) {
354 _, err := repo.Get(NewCanceledContext(), id)
355 AssertCancelledContext(t, err)
356 })
357
358 t.Run("Update with cancelled context", func(t *testing.T) {
359 note.Title = "Updated"
360 err := repo.Update(NewCanceledContext(), note)
361 AssertCancelledContext(t, err)
362 })
363
364 t.Run("Delete with cancelled context", func(t *testing.T) {
365 err := repo.Delete(NewCanceledContext(), id)
366 AssertCancelledContext(t, err)
367 })
368
369 t.Run("List with cancelled context", func(t *testing.T) {
370 _, err := repo.List(NewCanceledContext(), NoteListOptions{})
371 AssertCancelledContext(t, err)
372 })
373
374 t.Run("GetByTitle with cancelled context", func(t *testing.T) {
375 _, err := repo.GetByTitle(NewCanceledContext(), "Test")
376 AssertCancelledContext(t, err)
377 })
378
379 t.Run("GetArchived with cancelled context", func(t *testing.T) {
380 _, err := repo.GetArchived(NewCanceledContext())
381 AssertCancelledContext(t, err)
382 })
383
384 t.Run("GetActive with cancelled context", func(t *testing.T) {
385 _, err := repo.GetActive(NewCanceledContext())
386 AssertCancelledContext(t, err)
387 })
388
389 t.Run("Archive with cancelled context", func(t *testing.T) {
390 err := repo.Archive(NewCanceledContext(), id)
391 AssertCancelledContext(t, err)
392 })
393
394 t.Run("Unarchive with cancelled context", func(t *testing.T) {
395 err := repo.Unarchive(NewCanceledContext(), id)
396 AssertCancelledContext(t, err)
397 })
398
399 t.Run("SearchContent with cancelled context", func(t *testing.T) {
400 _, err := repo.SearchContent(NewCanceledContext(), "test")
401 AssertCancelledContext(t, err)
402 })
403
404 t.Run("GetRecent with cancelled context", func(t *testing.T) {
405 _, err := repo.GetRecent(NewCanceledContext(), 10)
406 AssertCancelledContext(t, err)
407 })
408
409 t.Run("AddTag with cancelled context", func(t *testing.T) {
410 err := repo.AddTag(NewCanceledContext(), id, "tag")
411 AssertCancelledContext(t, err)
412 })
413
414 t.Run("RemoveTag with cancelled context", func(t *testing.T) {
415 err := repo.RemoveTag(NewCanceledContext(), id, "tag")
416 AssertCancelledContext(t, err)
417 })
418
419 t.Run("GetByTags with cancelled context", func(t *testing.T) {
420 _, err := repo.GetByTags(NewCanceledContext(), []string{"tag"})
421 AssertCancelledContext(t, err)
422 })
423 })
424
425 t.Run("Edge Cases", func(t *testing.T) {
426 db := CreateTestDB(t)
427 repo := NewNoteRepository(db)
428 ctx := context.Background()
429
430 t.Run("Get non-existent note", func(t *testing.T) {
431 _, err := repo.Get(ctx, 99999)
432 shared.AssertError(t, err, "Expected error for non-existent note")
433 })
434
435 t.Run("Update non-existent note", func(t *testing.T) {
436 note := &models.Note{
437 ID: 99999,
438 Title: "Nonexistent",
439 Content: "Should fail",
440 }
441
442 err := repo.Update(ctx, note)
443 shared.AssertError(t, err, "Expected error when updating non-existent note")
444 })
445
446 t.Run("Delete non-existent note", func(t *testing.T) {
447 err := repo.Delete(ctx, 99999)
448 shared.AssertError(t, err, "Expected error when deleting non-existent note")
449 })
450
451 t.Run("Archive non-existent note", func(t *testing.T) {
452 err := repo.Archive(ctx, 99999)
453 shared.AssertError(t, err, "Expected error when archiving non-existent note")
454 })
455
456 t.Run("AddTag to non-existent note", func(t *testing.T) {
457 err := repo.AddTag(ctx, 99999, "tag")
458 shared.AssertError(t, err, "Expected error when adding tag to non-existent note")
459 })
460
461 t.Run("Note with empty tags", func(t *testing.T) {
462 note := &models.Note{
463 Title: "No Tags Note",
464 Content: "This note has no tags",
465 Tags: []string{},
466 }
467
468 id, err := repo.Create(ctx, note)
469 shared.AssertNoError(t, err, "Failed to create note with empty tags")
470
471 retrieved, err := repo.Get(ctx, id)
472 shared.AssertNoError(t, err, "Failed to get note")
473
474 shared.AssertEqual(t, 0, len(retrieved.Tags), "Expected empty tags slice")
475 })
476
477 t.Run("Note with nil tags", func(t *testing.T) {
478 note := &models.Note{
479 Title: "Nil Tags Note",
480 Content: "This note has nil tags",
481 Tags: nil,
482 }
483
484 id, err := repo.Create(ctx, note)
485 shared.AssertNoError(t, err, "Failed to create note with nil tags")
486
487 retrieved, err := repo.Get(ctx, id)
488 shared.AssertNoError(t, err, "Failed to get note")
489
490 shared.AssertEqual(t, 0, len(retrieved.Tags), "Expected empty tags")
491 })
492
493 t.Run("Note with long content", func(t *testing.T) {
494 longContent := ""
495 for i := 0; i < 1000; i++ {
496 longContent += "This is a very long content string. "
497 }
498
499 note := &models.Note{
500 Title: "Long Content Note",
501 Content: longContent,
502 }
503
504 id, err := repo.Create(ctx, note)
505 shared.AssertNoError(t, err, "Failed to create note with long content")
506
507 retrieved, err := repo.Get(ctx, id)
508 shared.AssertNoError(t, err, "Failed to get note")
509
510 shared.AssertEqual(t, longContent, retrieved.Content, "Long content was not stored/retrieved correctly")
511 })
512
513 t.Run("List with no results", func(t *testing.T) {
514 notes, err := repo.List(ctx, NoteListOptions{Title: "NonexistentTitle"})
515 shared.AssertNoError(t, err, "Should not error when no notes found")
516 shared.AssertEqual(t, 0, len(notes), "Expected empty result set")
517 })
518 })
519
520 t.Run("Leaflet Methods", func(t *testing.T) {
521 db := CreateTestDB(t)
522 repo := NewNoteRepository(db)
523 ctx := context.Background()
524
525 rkey1 := "rkey-published-1"
526 rkey2 := "rkey-draft-1"
527 rkey3 := "rkey-published-2"
528 pubTime := time.Now()
529
530 publishedNote1 := &models.Note{
531 Title: "Published Note 1",
532 Content: "Content 1",
533 LeafletRKey: &rkey1,
534 IsDraft: false,
535 PublishedAt: &pubTime,
536 }
537 _, err := repo.Create(ctx, publishedNote1)
538 shared.AssertNoError(t, err, "create published note 1")
539
540 draftNote := &models.Note{
541 Title: "Draft Note",
542 Content: "Draft content",
543 LeafletRKey: &rkey2,
544 IsDraft: true,
545 }
546 _, err = repo.Create(ctx, draftNote)
547 shared.AssertNoError(t, err, "create draft note")
548
549 publishedNote2 := &models.Note{
550 Title: "Published Note 2",
551 Content: "Content 2",
552 LeafletRKey: &rkey3,
553 IsDraft: false,
554 PublishedAt: &pubTime,
555 }
556 _, err = repo.Create(ctx, publishedNote2)
557 shared.AssertNoError(t, err, "create published note 2")
558
559 regularNote := &models.Note{
560 Title: "Regular Note",
561 Content: "No leaflet association",
562 }
563 _, err = repo.Create(ctx, regularNote)
564 shared.AssertNoError(t, err, "create regular note")
565
566 t.Run("GetByLeafletRKey finds note by rkey", func(t *testing.T) {
567 note, err := repo.GetByLeafletRKey(ctx, rkey1)
568 shared.AssertNoError(t, err, "get by leaflet rkey")
569 shared.AssertEqual(t, "Published Note 1", note.Title, "title should match")
570 shared.AssertNotNil(t, note.LeafletRKey, "leaflet rkey should be set")
571 shared.AssertEqual(t, rkey1, *note.LeafletRKey, "rkey should match")
572 })
573
574 t.Run("GetByLeafletRKey returns error for non-existent rkey", func(t *testing.T) {
575 _, err := repo.GetByLeafletRKey(ctx, "non-existent-rkey")
576 shared.AssertError(t, err, "should error for non-existent rkey")
577 })
578
579 t.Run("ListPublished returns only published notes", func(t *testing.T) {
580 notes, err := repo.ListPublished(ctx)
581 shared.AssertNoError(t, err, "list published")
582 shared.AssertEqual(t, 2, len(notes), "should have 2 published notes")
583
584 for _, note := range notes {
585 shared.AssertFalse(t, note.IsDraft, "published notes should not be drafts")
586 shared.AssertNotNil(t, note.LeafletRKey, "should have leaflet rkey")
587 }
588 })
589
590 t.Run("ListDrafts returns only draft notes", func(t *testing.T) {
591 notes, err := repo.ListDrafts(ctx)
592 shared.AssertNoError(t, err, "list drafts")
593 shared.AssertEqual(t, 1, len(notes), "should have 1 draft note")
594
595 shared.AssertTrue(t, notes[0].IsDraft, "should be draft")
596 shared.AssertEqual(t, "Draft Note", notes[0].Title, "title should match")
597 shared.AssertNotNil(t, notes[0].LeafletRKey, "should have leaflet rkey")
598 })
599
600 t.Run("GetLeafletNotes returns all notes with leaflet association", func(t *testing.T) {
601 notes, err := repo.GetLeafletNotes(ctx)
602 shared.AssertNoError(t, err, "get leaflet notes")
603 shared.AssertEqual(t, 3, len(notes), "should have 3 leaflet notes")
604
605 for _, note := range notes {
606 shared.AssertNotNil(t, note.LeafletRKey, "all should have leaflet rkey")
607 }
608 })
609
610 t.Run("GetNewestPublication returns most recent published note", func(t *testing.T) {
611 note, err := repo.GetNewestPublication(ctx)
612 shared.AssertNoError(t, err, "get newest publication")
613 shared.AssertNotNil(t, note, "should return a note")
614 shared.AssertFalse(t, note.IsDraft, "newest should not be draft")
615 shared.AssertNotNil(t, note.PublishedAt, "should have published_at")
616 })
617
618 t.Run("GetNewestPublication returns error when no published notes", func(t *testing.T) {
619 emptyDB := CreateTestDB(t)
620 emptyRepo := NewNoteRepository(emptyDB)
621
622 _, err := emptyRepo.GetNewestPublication(ctx)
623 shared.AssertError(t, err, "should error when no published notes exist")
624 })
625
626 t.Run("DeleteAllLeafletNotes removes all leaflet notes", func(t *testing.T) {
627 beforeLeaflet, err := repo.GetLeafletNotes(ctx)
628 shared.AssertNoError(t, err, "get leaflet notes before delete")
629 shared.AssertEqual(t, 3, len(beforeLeaflet), "should have 3 leaflet notes before delete")
630
631 allNotes, err := repo.List(ctx, NoteListOptions{})
632 shared.AssertNoError(t, err, "get all notes before delete")
633 shared.AssertEqual(t, 4, len(allNotes), "should have 4 total notes before delete")
634
635 err = repo.DeleteAllLeafletNotes(ctx)
636 shared.AssertNoError(t, err, "delete all leaflet notes")
637
638 afterLeaflet, err := repo.GetLeafletNotes(ctx)
639 shared.AssertNoError(t, err, "get leaflet notes after delete")
640 shared.AssertEqual(t, 0, len(afterLeaflet), "should have 0 leaflet notes after delete")
641
642 remainingNotes, err := repo.List(ctx, NoteListOptions{})
643 shared.AssertNoError(t, err, "get remaining notes")
644 shared.AssertEqual(t, 1, len(remainingNotes), "should have 1 regular note remaining")
645 if remainingNotes[0].LeafletRKey != nil {
646 t.Error("remaining note should not have leaflet rkey")
647 }
648 })
649
650 t.Run("Context Cancellation", func(t *testing.T) {
651 t.Run("GetByLeafletRKey with cancelled context", func(t *testing.T) {
652 _, err := repo.GetByLeafletRKey(NewCanceledContext(), rkey1)
653 AssertCancelledContext(t, err)
654 })
655
656 t.Run("ListPublished with cancelled context", func(t *testing.T) {
657 _, err := repo.ListPublished(NewCanceledContext())
658 AssertCancelledContext(t, err)
659 })
660
661 t.Run("ListDrafts with cancelled context", func(t *testing.T) {
662 _, err := repo.ListDrafts(NewCanceledContext())
663 AssertCancelledContext(t, err)
664 })
665
666 t.Run("GetLeafletNotes with cancelled context", func(t *testing.T) {
667 _, err := repo.GetLeafletNotes(NewCanceledContext())
668 AssertCancelledContext(t, err)
669 })
670
671 t.Run("GetNewestPublication with cancelled context", func(t *testing.T) {
672 _, err := repo.GetNewestPublication(NewCanceledContext())
673 AssertCancelledContext(t, err)
674 })
675
676 t.Run("DeleteAllLeafletNotes with cancelled context", func(t *testing.T) {
677 err := repo.DeleteAllLeafletNotes(NewCanceledContext())
678 AssertCancelledContext(t, err)
679 })
680 })
681 })
682}