125 lines
3.4 KiB
Go
125 lines
3.4 KiB
Go
package tests
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"testing"
|
||
|
||
"git.gm6.ru/icewind/seadoc/models"
|
||
"git.gm6.ru/icewind/seadoc/service"
|
||
"git.gm6.ru/icewind/seadoc/store"
|
||
"gorm.io/driver/sqlite"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// helper: инициализация базы и сервиса
|
||
func newTestService(t *testing.T) (*gorm.DB, *service.VersionService, *store.GormStorage) {
|
||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||
if err != nil {
|
||
t.Fatalf("failed to open in-memory sqlite: %v", err)
|
||
}
|
||
if err := db.AutoMigrate(&models.Document{}, &models.Version{}); err != nil {
|
||
t.Fatalf("failed to migrate: %v", err)
|
||
}
|
||
|
||
storage := store.NewGormStorage(db)
|
||
service := service.NewVersionService(storage)
|
||
return db, service, storage
|
||
}
|
||
|
||
func TestVersioningLifecycle(t *testing.T) {
|
||
db, service, store := newTestService(t)
|
||
|
||
// 1️⃣ Создаём документ
|
||
docID, err := store.CreateDocument("test.json")
|
||
if err != nil {
|
||
t.Fatalf("create document: %v", err)
|
||
}
|
||
|
||
// 2️⃣ Данные
|
||
v1 := []byte(`{"name": "Alice", "age": 30}`)
|
||
v2 := []byte(`{"name": "Alice", "age": 31, "city": "Paris"}`)
|
||
v3 := []byte(`{"name": "Alice", "age": 32, "city": "Paris", "lang": "fr"}`)
|
||
|
||
// 3️⃣ Сохраняем версии
|
||
ver1, err := service.SaveNewVersion(docID, v1)
|
||
if err != nil {
|
||
t.Fatalf("save v1: %v", err)
|
||
}
|
||
if !ver1.IsSnapshot {
|
||
t.Errorf("v1 должен быть snapshot, но IsSnapshot=%v", ver1.IsSnapshot)
|
||
}
|
||
|
||
ver2, err := service.SaveNewVersion(docID, v2)
|
||
if err != nil {
|
||
t.Fatalf("save v2: %v", err)
|
||
}
|
||
if ver2.IsSnapshot {
|
||
t.Errorf("v2 не должен быть snapshot")
|
||
}
|
||
|
||
ver3, err := service.SaveNewVersion(docID, v3)
|
||
if err != nil {
|
||
t.Fatalf("save v3: %v", err)
|
||
}
|
||
|
||
// 4️⃣ Проверяем восстановление v2
|
||
data2, err := service.ReconstructVersion(ver2.ID)
|
||
if err != nil {
|
||
t.Fatalf("reconstruct v2: %v", err)
|
||
}
|
||
if !jsonEqual(data2, v2) {
|
||
t.Errorf("восстановленный v2 не совпадает:\n got: %s\nwant: %s", data2, v2)
|
||
}
|
||
|
||
// 5️⃣ Проверяем восстановление v3
|
||
data3, err := service.ReconstructVersion(ver3.ID)
|
||
if err != nil {
|
||
t.Fatalf("reconstruct v3: %v", err)
|
||
}
|
||
if !jsonEqual(data3, v3) {
|
||
t.Errorf("восстановленный v3 не совпадает:\n got: %s\nwant: %s", data3, v3)
|
||
}
|
||
|
||
// 6️⃣ Проверим, что версии записались в базу
|
||
var count int64
|
||
if err := db.Model(&models.Version{}).Count(&count).Error; err != nil {
|
||
t.Fatalf("count versions: %v", err)
|
||
}
|
||
if count != 3 {
|
||
t.Errorf("ожидалось 3 версии, а в БД %d", count)
|
||
}
|
||
}
|
||
|
||
// сравнение JSON без учёта порядка полей
|
||
func jsonEqual(a, b []byte) bool {
|
||
var ja, jb interface{}
|
||
_ = json.Unmarshal(a, &ja)
|
||
_ = json.Unmarshal(b, &jb)
|
||
ra, _ := json.Marshal(ja)
|
||
rb, _ := json.Marshal(jb)
|
||
return bytes.Equal(ra, rb)
|
||
}
|
||
|
||
func TestDiffVersions(t *testing.T) {
|
||
_, service, store := newTestService(t)
|
||
|
||
docID, _ := store.CreateDocument("diff.json")
|
||
|
||
v1 := []byte(`{"name":"Alice","age":30}`)
|
||
v2 := []byte(`{"name":"Alice","age":31,"city":"Paris"}`)
|
||
|
||
ver1, _ := service.SaveNewVersion(docID, v1)
|
||
ver2, _ := service.SaveNewVersion(docID, v2)
|
||
|
||
diff, err := service.DiffVersions(ver1.ID, ver2.ID)
|
||
if err != nil {
|
||
t.Fatalf("diff error: %v", err)
|
||
}
|
||
|
||
expected := `{"age":31,"city":"Paris"}`
|
||
if !jsonEqual(diff, []byte(expected)) {
|
||
t.Errorf("unexpected diff:\n got: %s\nwant: %s", diff, expected)
|
||
}
|
||
}
|