Files
donniemarko/internal/storage/sqlite_test.go
adminoo b571588b15 feat(release): v0.2.0
commit 78d6c27c8940da32a6de8e64327c86f74fdaa2eb
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 12:59:22 2026 +0100

    feat: freebsd log rotation config thingie

commit 55af4e6c70122e679272ed247c26e04b1247f694
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 12:58:43 2026 +0100

    feat: embed templates, static resolution

commit 29c917f929a7378ec29c54315ee2e9f420747787
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 10:44:34 2026 +0100

    feat: set log file path

commit 294fd3d1549979eab63587ceec6ff5d0978e9afc
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 10:23:53 2026 +0100

    feat: logging HTTP request

commit c9ae80b240d58e1abed7ae3b7b2c3b283a31f1a1
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 09:54:05 2026 +0100

    feat: freebsd-specific compile target and scripts

commit 86ca154dedd19aa1fe5f571c445dcf17a8396bfa
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 09:25:16 2026 +0100

    feat: mobile friendly CSS

commit 199f4319e0b08a4b6d595d7eb3effb6db6c7beec
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 09:25:03 2026 +0100

    feat: persisting rendered note

commit 865e258237e45d7c542685a4653bcad3c5af259d
Author: adminoo <git@kadath.corp>
Date:   Wed Feb 4 08:06:38 2026 +0100

    fix: grouping notes by folder

commit 242d1d074c92461f38212b033c7a9e383f9dc550
Author: adminoo <git@kadath.corp>
Date:   Tue Feb 3 16:52:50 2026 +0100

    feat: storage layer logic

    - Prune notes from db not matching current folder structure at start
    - Detect file system deletion on start by comparing in-db notes
    - Prevent updating of in-db notes at start if modification time is not
      newer
    - Delete by path

commit d75d46bc1ab22bd990d0fdc307e571fe52f0dd99
Author: adminoo <git@kadath.corp>
Date:   Tue Feb 3 15:27:07 2026 +0100

    feat: group notes by root folders

commit e1e25a938e717599332f7b40a449d9bb854b673a
Author: adminoo <git@kadath.corp>
Date:   Tue Feb 3 14:24:37 2026 +0100

    feat: size in kilobytes

commit 61220272a2df2b66c2b8e356ba359ed01de3bd12
Author: adminoo <git@kadath.corp>
Date:   Tue Feb 3 14:19:40 2026 +0100

    feat: styling inputs
2026-02-04 13:17:16 +01:00

279 lines
6.8 KiB
Go

package storage
import (
"path/filepath"
"testing"
"time"
"donniemarko/internal/note"
)
func newSQLiteStorage(t *testing.T) *SQLiteStorage {
t.Helper()
dbPath := filepath.Join(t.TempDir(), "notes.db")
st, err := NewSQLiteStorage(dbPath)
if err != nil {
t.Fatalf("new sqlite storage: %v", err)
}
t.Cleanup(func() {
_ = st.Close()
})
return st
}
func sampleNote(id, path, title, content string, tstamp time.Time) *note.Note {
return &note.Note{
ID: id,
Path: path,
Title: title,
Content: content,
UpdatedAt: tstamp.Add(2 * time.Hour),
Size: int64(len(content)),
Published: true,
}
}
func TestSQLiteStorage_CreateGet(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
n := sampleNote("n1", "notes/alpha.md", "Alpha", "# Alpha", ts)
if err := st.Create(n); err != nil {
t.Fatalf("create note: %v", err)
}
got, err := st.Get("n1")
if err != nil {
t.Fatalf("get note: %v", err)
}
if got.Title != n.Title || got.Path != n.Path || got.Content != n.Content {
t.Fatalf("unexpected note fields: %+v", got)
}
if !got.UpdatedAt.Equal(n.UpdatedAt) || got.Size != n.Size {
t.Fatalf("unexpected time fields: %+v", got)
}
if !got.Published {
t.Fatalf("expected published to be true")
}
}
func TestSQLiteStorage_GetAll(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.Create(sampleNote("n2", "notes/beta.md", "Beta", "two", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
all := st.GetAll()
if len(all) != 2 {
t.Fatalf("expected 2 notes, got %d", len(all))
}
}
func TestSQLiteStorage_Update(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
n := sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)
if err := st.Create(n); err != nil {
t.Fatalf("create note: %v", err)
}
updated := sampleNote("n1", "notes/alpha.md", "Alpha Updated", "two", ts.Add(24*time.Hour))
st.Update("n1", updated)
got, err := st.Get("n1")
if err != nil {
t.Fatalf("get note: %v", err)
}
if got.Title != "Alpha Updated" || got.Content != "two" {
t.Fatalf("update did not persist: %+v", got)
}
}
func TestSQLiteStorage_Delete(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
st.Delete("n1")
if st.Count() != 0 {
t.Fatalf("expected count 0 after delete")
}
if _, err := st.Get("n1"); err == nil {
t.Fatalf("expected error for missing note")
}
}
func TestSQLiteStorage_DeleteByPath(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
n := sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)
if err := st.Create(n); err != nil {
t.Fatalf("create note: %v", err)
}
st.DeleteByPath("notes/alpha.md")
if st.Count() != 0 {
t.Fatalf("expected count 0 after delete by path")
}
}
func TestSQLiteStorage_Search(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "Rust tips", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.Create(sampleNote("n2", "notes/beta.md", "Beta", "Golang tutorial", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
results := st.Search("rust")
if len(results) != 1 {
t.Fatalf("expected 1 result, got %d", len(results))
}
if results[0].ID != "n1" {
t.Fatalf("expected rust match to be n1")
}
}
func TestSQLiteStorage_Count(t *testing.T) {
st := newSQLiteStorage(t)
if st.Count() != 0 {
t.Fatalf("expected empty count to be 0")
}
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.Create(sampleNote("n2", "notes/beta.md", "Beta", "two", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if st.Count() != 2 {
t.Fatalf("expected count 2")
}
}
func TestSQLiteStorage_Tags(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.AddTag("n1", "go"); err != nil {
t.Fatalf("add tag: %v", err)
}
if err := st.AddTag("n1", "rust"); err != nil {
t.Fatalf("add tag: %v", err)
}
tags := st.GetTags("n1")
if len(tags) != 2 {
t.Fatalf("expected 2 tags, got %d", len(tags))
}
if err := st.RemoveTag("n1", "go"); err != nil {
t.Fatalf("remove tag: %v", err)
}
tags = st.GetTags("n1")
if len(tags) != 1 || tags[0] != "rust" {
t.Fatalf("expected remaining tag rust, got %+v", tags)
}
}
func TestSQLiteStorage_SearchByTag(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "no match", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.Create(sampleNote("n2", "notes/beta.md", "Beta", "content", ts)); err != nil {
t.Fatalf("create note: %v", err)
}
if err := st.AddTag("n2", "Go"); err != nil {
t.Fatalf("add tag: %v", err)
}
results := st.Search("go")
if len(results) != 1 {
t.Fatalf("expected 1 result, got %d", len(results))
}
if results[0].ID != "n2" {
t.Fatalf("expected tag match to be n2")
}
}
func TestSQLiteStorage_Create_Upsert(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
n := sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)
if err := st.Create(n); err != nil {
t.Fatalf("create note: %v", err)
}
n.Content = "updated"
n.Title = "Alpha Updated"
n.UpdatedAt = ts.Add(4 * time.Hour)
if err := st.Create(n); err != nil {
t.Fatalf("upsert note: %v", err)
}
got, err := st.Get("n1")
if err != nil {
t.Fatalf("get note: %v", err)
}
if got.Title != "Alpha Updated" || got.Content != "updated" {
t.Fatalf("expected note to be updated, got %+v", got)
}
}
func TestSQLiteStorage_Create_UpsertSkipsOlder(t *testing.T) {
st := newSQLiteStorage(t)
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
n := sampleNote("n1", "notes/alpha.md", "Alpha", "one", ts)
if err := st.Create(n); err != nil {
t.Fatalf("create note: %v", err)
}
n.Content = "older"
n.UpdatedAt = ts.Add(-2 * time.Hour)
if err := st.Create(n); err != nil {
t.Fatalf("upsert note: %v", err)
}
got, err := st.Get("n1")
if err != nil {
t.Fatalf("get note: %v", err)
}
if got.Content != "one" {
t.Fatalf("expected existing content to remain, got %q", got.Content)
}
}