store_test.go
⎇
Raw
1package store
2
3import (
4 "context"
5 "errors"
6 "path/filepath"
7 "testing"
8
9 "forge.gpl-nas.de/physiobase/internal/database"
10)
11
12func newStore(t *testing.T) *Store {
13 t.Helper()
14 db, err := database.Open(filepath.Join(t.TempDir(), "test.db"))
15 if err != nil {
16 t.Fatal(err)
17 }
18 t.Cleanup(func() { database.Close(db) })
19 return New(db)
20}
21
22func TestFTSQuery(t *testing.T) {
23 cases := map[string]string{
24 "": "",
25 "knie": `"knie"*`,
26 `knie "OR" sehne*`: `"knie"* "OR"* "sehne"*`,
27 "Lachman-Test": `"Lachman"* "Test"*`,
28 `"); DROP`: `"DROP"*`,
29 }
30 for in, want := range cases {
31 if got := FTSQuery(in); got != want {
32 t.Errorf("FTSQuery(%q) = %q, want %q", in, got, want)
33 }
34 }
35}
36
37func TestSeedSearchLinks(t *testing.T) {
38 ctx := context.Background()
39 s := newStore(t)
40 seeded, err := s.Seed(ctx)
41 if err != nil || !seeded {
42 t.Fatalf("seed: %v %v", seeded, err)
43 }
44 // zweites Mal: nichts passiert
45 if again, _ := s.Seed(ctx); again {
46 t.Fatal("seed lief zweimal")
47 }
48 // Präfix + Umlaut-unabhängig
49 for _, q := range []string{"patella", "Ubung", "kniebeuge schräg", "jumper"} {
50 res, err := s.Search(ctx, q, "", "")
51 if err != nil {
52 t.Fatal(err)
53 }
54 if len(res) == 0 {
55 t.Errorf("Suche %q: keine Treffer", q)
56 }
57 }
58 res, _ := s.Search(ctx, "", "uebung", "Knie")
59 if len(res) != 3 {
60 t.Errorf("Filter Übung+Knie: %d Treffer, erwartet 3", len(res))
61 }
62
63 all, _ := s.Search(ctx, "Patellatendinopathie", "krankheitsbild", "")
64 if len(all) != 1 {
65 t.Fatalf("Krankheitsbild nicht gefunden")
66 }
67 rel, err := s.Related(ctx, all[0].ID)
68 if err != nil || len(rel) != 5 {
69 t.Fatalf("Related: %d %v", len(rel), err)
70 }
71 // Update hält den Suchindex aktuell
72 e := all[0]
73 e.Title = "Springerknie"
74 if err := s.UpdateEntry(ctx, e); err != nil {
75 t.Fatal(err)
76 }
77 if r, _ := s.Search(ctx, "springerknie", "", ""); len(r) != 1 {
78 t.Error("geänderter Titel nicht im Index")
79 }
80 if r, _ := s.Search(ctx, "Patellatendinopathie", "krankheitsbild", ""); len(r) != 0 {
81 t.Error("alter Titel noch im Index")
82 }
83 // Löschen entfernt Verknüpfungen (Fremdschlüssel aktiv)
84 if _, err := s.DeleteEntry(ctx, e.ID); err != nil {
85 t.Fatal(err)
86 }
87 var n int
88 s.db.QueryRow(`SELECT count(*) FROM entry_links WHERE a = ? OR b = ?`, e.ID, e.ID).Scan(&n)
89 if n != 0 {
90 t.Errorf("%d Verknüpfungen übrig", n)
91 }
92 if _, err := s.Entry(ctx, e.ID); !errors.Is(err, ErrNotFound) {
93 t.Errorf("gelöschter Eintrag: %v", err)
94 }
95}
96
97func TestHandoutOrderAndCopy(t *testing.T) {
98 ctx := context.Background()
99 s := newStore(t)
100 var ids []int64
101 for _, title := range []string{"A", "B", "C"} {
102 id, _ := s.CreateEntry(ctx, Entry{Kind: "uebung", Title: title, Dosage: "3x10"})
103 ids = append(ids, id)
104 }
105 notEx, _ := s.CreateEntry(ctx, Entry{Kind: "test", Title: "kein Übung"})
106 hid, _ := s.CreateHandout(ctx, "H", "")
107 for _, id := range append(ids, notEx) {
108 if err := s.AddHandoutItem(ctx, hid, id); err != nil {
109 t.Fatal(err)
110 }
111 }
112 items, _ := s.HandoutItems(ctx, hid)
113 if len(items) != 3 {
114 t.Fatalf("%d Items, erwartet 3 (Tests dürfen nicht rein)", len(items))
115 }
116 if items[0].Dosage != "3x10" {
117 t.Error("Standard-Dosierung nicht übernommen")
118 }
119 if err := s.MoveHandoutItemUp(ctx, hid, ids[2]); err != nil {
120 t.Fatal(err)
121 }
122 items, _ = s.HandoutItems(ctx, hid)
123 got := items[0].Entry.Title + items[1].Entry.Title + items[2].Entry.Title
124 if got != "ACB" {
125 t.Errorf("Reihenfolge %s, erwartet ACB", got)
126 }
127 nid, err := s.CopyHandout(ctx, hid)
128 if err != nil {
129 t.Fatal(err)
130 }
131 cp, _ := s.HandoutItems(ctx, nid)
132 if len(cp) != 3 || cp[1].Entry.Title != "C" {
133 t.Error("Kopie unvollständig")
134 }
135}
136