Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1package db_test
2
3import (
4 "os"
5 "testing"
6
7 "github.com/limeleaf/diffdown/internal/db"
8)
9
10func openTestDB(t *testing.T) *db.DB {
11 t.Helper()
12 f, err := os.CreateTemp("", "diffdown-test-*.db")
13 if err != nil {
14 t.Fatal(err)
15 }
16 t.Cleanup(func() { os.Remove(f.Name()) })
17 f.Close()
18
19 database, err := db.Open(f.Name())
20 if err != nil {
21 t.Fatal(err)
22 }
23 db.SetMigrationsDir("../../migrations")
24 if err := database.Migrate(); err != nil {
25 t.Fatal(err)
26 }
27 return database
28}
29
30func TestGetDocVersion_Empty(t *testing.T) {
31 d := openTestDB(t)
32 v, err := d.GetDocVersion("rkey1")
33 if err != nil {
34 t.Fatal(err)
35 }
36 if v != 0 {
37 t.Errorf("expected version 0 for new doc, got %d", v)
38 }
39}
40
41func TestAppendSteps_IncreasesVersion(t *testing.T) {
42 d := openTestDB(t)
43 steps := []string{`{"stepType":"replace"}`, `{"stepType":"replace"}`}
44 newVersion, err := d.AppendSteps("rkey1", 0, steps, "client-a")
45 if err != nil {
46 t.Fatal(err)
47 }
48 if newVersion != 2 {
49 t.Errorf("expected version 2, got %d", newVersion)
50 }
51}
52
53func TestAppendSteps_VersionConflict(t *testing.T) {
54 d := openTestDB(t)
55 _, err := d.AppendSteps("rkey1", 0, []string{`{}`}, "client-a")
56 if err != nil {
57 t.Fatal(err)
58 }
59 // Submit again from clientVersion=0 (stale) — must fail.
60 _, err = d.AppendSteps("rkey1", 0, []string{`{}`}, "client-b")
61 if err == nil {
62 t.Fatal("expected conflict error, got nil")
63 }
64}
65
66func TestGetStepsSince(t *testing.T) {
67 d := openTestDB(t)
68 steps := []string{`{"a":1}`, `{"a":2}`, `{"a":3}`}
69 d.AppendSteps("rkey1", 0, steps, "client-a")
70
71 rows, err := d.GetStepsSince("rkey1", 1)
72 if err != nil {
73 t.Fatal(err)
74 }
75 if len(rows) != 2 {
76 t.Errorf("expected 2 steps since v1, got %d", len(rows))
77 }
78 if rows[0].JSON != `{"a":2}` {
79 t.Errorf("unexpected step: %s", rows[0].JSON)
80 }
81}
82
83func TestCollaborations(t *testing.T) {
84 d := openTestDB(t)
85 const collabDID = "did:plc:collab"
86 const ownerDID = "did:plc:owner"
87 const rkey = "abc123"
88
89 if err := d.AddCollaboration(collabDID, ownerDID, rkey); err != nil {
90 t.Fatalf("AddCollaboration: %v", err)
91 }
92 // idempotent — should not error on duplicate
93 if err := d.AddCollaboration(collabDID, ownerDID, rkey); err != nil {
94 t.Fatalf("AddCollaboration (dup): %v", err)
95 }
96
97 rows, err := d.GetCollaborations(collabDID)
98 if err != nil {
99 t.Fatalf("GetCollaborations: %v", err)
100 }
101 if len(rows) != 1 {
102 t.Fatalf("want 1 row, got %d", len(rows))
103 }
104 if rows[0].OwnerDID != ownerDID || rows[0].DocumentRKey != rkey {
105 t.Errorf("unexpected row: %+v", rows[0])
106 }
107}