Files
pure-note/internal/store/store_test.go
T

123 lines
2.7 KiB
Go

package store
import (
"errors"
"path/filepath"
"testing"
)
// TestMigrationsFromEmpty 空库 → 最新版本;重复打开幂等(§13 迁移组)。
func TestMigrationsFromEmpty(t *testing.T) {
dir := t.TempDir()
dbPath := filepath.Join(dir, "pn.db")
s1, err := Open(dbPath, false)
if err != nil {
t.Fatalf("首次打开失败: %v", err)
}
v1, err := s1.SchemaVersion()
if err != nil {
t.Fatal(err)
}
if v1 != MaxSchemaVersion {
t.Fatalf("期望版本 %d 实际 %d", MaxSchemaVersion, v1)
}
s1.Close()
// 重开:幂等,不再执行迁移
s2, err := Open(dbPath, false)
if err != nil {
t.Fatalf("二次打开失败: %v", err)
}
defer s2.Close()
v2, err := s2.SchemaVersion()
if err != nil {
t.Fatal(err)
}
if v2 != v1 {
t.Fatalf("迁移不幂等: %d → %d", v1, v2)
}
}
// TestMigrationNewerRejected user_version 越界拒绝启动;--allow-newer 放行(§10.4)。
func TestMigrationNewerRejected(t *testing.T) {
dir := t.TempDir()
dbPath := filepath.Join(dir, "pn.db")
s1, err := Open(dbPath, false)
if err != nil {
t.Fatal(err)
}
if _, err := s1.DB().Exec("PRAGMA user_version = 99"); err != nil {
t.Fatal(err)
}
s1.Close()
_, err = Open(dbPath, false)
if !errors.Is(err, ErrSchemaNewer) {
t.Fatalf("期望 ErrSchemaNewer,实际 %v", err)
}
s2, err := Open(dbPath, true) // --allow-newer
if err != nil {
t.Fatalf("allow-newer 应放行: %v", err)
}
defer s2.Close()
}
// TestForeignKeysCascade 外键级联生效(image_refs 依赖 foreign_keys=1)。
func TestForeignKeysCascade(t *testing.T) {
s := openTestStore(t)
nid, err := s.CreateNote(&Note{Slug: "casc", Title: "级联", Status: "public",
Tags: []string{}, CreatedAt: 1, UpdatedAt: 1})
if err != nil {
t.Fatal(err)
}
imgID, err := s.UpsertImage("aa", "image/png", 1, []byte{1}, 1)
if err != nil {
t.Fatal(err)
}
if err := s.RebuildImageRefs(nid, "![x](/api/images/"+itoa64(imgID)+")"); err != nil {
t.Fatal(err)
}
if err := s.DeleteNoteForever(nid); err != nil {
t.Fatal(err)
}
// 级联后图片变孤儿
orphans, err := s.ListOrphanImages()
if err != nil {
t.Fatal(err)
}
found := false
for _, o := range orphans {
if o.ID == imgID {
found = true
}
}
if !found {
t.Fatal("物理删除笔记后其引用关系应被级联删除(图片转为孤儿)")
}
}
func openTestStore(t *testing.T) *Store {
t.Helper()
s, err := Open(filepath.Join(t.TempDir(), "test.db"), false)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { s.Close() })
return s
}
func itoa64(v int64) string {
if v == 0 {
return "0"
}
var b [20]byte
i := len(b)
for v > 0 {
i--
b[i] = byte('0' + v%10)
v /= 10
}
return string(b[i:])
}