Add conflict resolution diff UI and app branding
This commit is contained in:
@@ -1,8 +1,18 @@
|
||||
package docs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/tim/cairnquire/apps/server/internal/database"
|
||||
"github.com/tim/cairnquire/apps/server/internal/markdown"
|
||||
"github.com/tim/cairnquire/apps/server/internal/store"
|
||||
)
|
||||
|
||||
func TestNormalizeRequestPathCandidatesSupportsIndexFiles(t *testing.T) {
|
||||
@@ -37,3 +47,95 @@ func TestNormalizeRequestPathCandidatesSupportsIndexFiles(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveSourcePageWithBaseHashRejectsStaleEditor(t *testing.T) {
|
||||
service, sourceDir := setupDocsTestService(t)
|
||||
ctx := context.Background()
|
||||
|
||||
page, err := service.LoadSourcePage(ctx, "hello")
|
||||
if err != nil {
|
||||
t.Fatalf("LoadSourcePage() error = %v", err)
|
||||
}
|
||||
|
||||
serverContent := "# Hello\n\nServer edit"
|
||||
if err := os.WriteFile(filepath.Join(sourceDir, "hello.md"), []byte(serverContent), 0o644); err != nil {
|
||||
t.Fatalf("write server edit: %v", err)
|
||||
}
|
||||
|
||||
_, err = service.SaveSourcePageWithBaseHash(ctx, "hello", "# Hello\n\nClient edit", page.Hash)
|
||||
var conflict *DocumentConflictError
|
||||
if !errors.As(err, &conflict) {
|
||||
t.Fatalf("SaveSourcePageWithBaseHash() error = %v, want DocumentConflictError", err)
|
||||
}
|
||||
if conflict.BaseHash != page.Hash {
|
||||
t.Fatalf("conflict base hash = %q, want %q", conflict.BaseHash, page.Hash)
|
||||
}
|
||||
if conflict.CurrentContent != serverContent {
|
||||
t.Fatalf("conflict current content = %q, want %q", conflict.CurrentContent, serverContent)
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(filepath.Join(sourceDir, "hello.md"))
|
||||
if err != nil {
|
||||
t.Fatalf("read hello.md: %v", err)
|
||||
}
|
||||
if string(content) != serverContent {
|
||||
t.Fatalf("stale save overwrote content: %q", string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveSourcePageWithBaseHashAcceptsMatchingHash(t *testing.T) {
|
||||
service, sourceDir := setupDocsTestService(t)
|
||||
ctx := context.Background()
|
||||
|
||||
page, err := service.LoadSourcePage(ctx, "hello")
|
||||
if err != nil {
|
||||
t.Fatalf("LoadSourcePage() error = %v", err)
|
||||
}
|
||||
|
||||
nextContent := "# Hello\n\nClient edit"
|
||||
updated, err := service.SaveSourcePageWithBaseHash(ctx, "hello", nextContent, page.Hash)
|
||||
if err != nil {
|
||||
t.Fatalf("SaveSourcePageWithBaseHash() error = %v", err)
|
||||
}
|
||||
if updated.Hash == page.Hash {
|
||||
t.Fatal("expected hash to change after save")
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(filepath.Join(sourceDir, "hello.md"))
|
||||
if err != nil {
|
||||
t.Fatalf("read hello.md: %v", err)
|
||||
}
|
||||
if string(content) != nextContent {
|
||||
t.Fatalf("saved content = %q, want %q", string(content), nextContent)
|
||||
}
|
||||
}
|
||||
|
||||
func setupDocsTestService(t *testing.T) (*Service, string) {
|
||||
t.Helper()
|
||||
|
||||
sourceDir := t.TempDir()
|
||||
storeDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(sourceDir, "hello.md"), []byte("# Hello\n\nOriginal"), 0o644); err != nil {
|
||||
t.Fatalf("create hello.md: %v", err)
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(t.TempDir(), "test.db")
|
||||
db, err := sql.Open("libsql", "file:"+dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("open database: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { db.Close() })
|
||||
|
||||
ctx := context.Background()
|
||||
if err := database.ApplyMigrations(ctx, db); err != nil {
|
||||
t.Fatalf("apply migrations: %v", err)
|
||||
}
|
||||
|
||||
contentStore, err := store.New(storeDir)
|
||||
if err != nil {
|
||||
t.Fatalf("create content store: %v", err)
|
||||
}
|
||||
|
||||
repo := NewRepository(db)
|
||||
return NewService(sourceDir, contentStore, markdown.NewRenderer(), repo, slog.Default()), sourceDir
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user