hsa-app/internal/storage/ai_notes_test.go
Jean-Michel Tremblay c715c8e0c0
All checks were successful
Build and Test / build-and-test (push) Successful in 37s
AI classifier correction notes + misread review (AI tab)
Add a global, temporal ai_notes list appended to the classifier prompt
(seeded once from no-PII defaults, documented in README), managed inline
on a new AI tab with a read-only view of the assembled prompt. Every
AI-run upload records the browser-round-tripped suggestion blob + model;
misreads are derived (final field != AI guess) and reviewed one by one
(image + per-field guess-vs-entered + notes-since), attributing which
note fixed each or closing unresolved. Update SPEC (new section 10),
DESIGN item 15, README, and changelog (0.0.3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:04:30 -04:00

106 lines
2.3 KiB
Go

package storage
import (
"path/filepath"
"testing"
"time"
)
func notesTestStore(t *testing.T) *Store {
t.Helper()
s, err := Open(filepath.Join(t.TempDir(), "notes.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { s.Close() })
return s
}
func TestNotes_SeededOnFirstOpen(t *testing.T) {
s := notesTestStore(t)
notes, err := s.ListActiveNotes()
if err != nil {
t.Fatal(err)
}
if len(notes) != len(defaultNotes) {
t.Fatalf("seeded %d notes, want %d", len(notes), len(defaultNotes))
}
}
func TestNotes_DeletedDefaultDoesNotResurrect(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "n.db")
s, err := Open(path)
if err != nil {
t.Fatal(err)
}
all, _ := s.ListActiveNotes()
if err := s.DeleteNote(all[0].ID); err != nil {
t.Fatal(err)
}
s.Close()
// Reopen: seeding must NOT run again (table is non-empty thanks to history).
s2, err := Open(path)
if err != nil {
t.Fatal(err)
}
defer s2.Close()
notes, _ := s2.ListActiveNotes()
if len(notes) != len(defaultNotes)-1 {
t.Errorf("after delete+reopen got %d active notes, want %d", len(notes), len(defaultNotes)-1)
}
}
func TestNotes_EditKeepsHistory(t *testing.T) {
s := notesTestStore(t)
id, err := s.AddNote("original")
if err != nil {
t.Fatal(err)
}
newID, err := s.EditNote(id, "revised")
if err != nil {
t.Fatal(err)
}
if newID == id {
t.Error("edit should create a new row id")
}
active, _ := s.ListActiveNotes()
var texts []string
for _, n := range active {
texts = append(texts, n.Text)
}
if contains(texts, "original") {
t.Error("old text should no longer be active")
}
if !contains(texts, "revised") {
t.Error("revised text should be active")
}
}
func TestNotes_CreatedAfter(t *testing.T) {
s := notesTestStore(t)
cutoff := time.Now().UTC()
// created_at has second resolution (RFC3339); make sure the new note sorts after.
time.Sleep(1100 * time.Millisecond)
if _, err := s.AddNote("late note"); err != nil {
t.Fatal(err)
}
after, err := s.NotesCreatedAfter(cutoff)
if err != nil {
t.Fatal(err)
}
if len(after) != 1 || after[0].Text != "late note" {
t.Fatalf("NotesCreatedAfter = %v, want just the late note", after)
}
}
func contains(ss []string, want string) bool {
for _, s := range ss {
if s == want {
return true
}
}
return false
}