266 lines
7.6 KiB
Go
266 lines
7.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCaptureTextCreatesInboxArtifact(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
dto, err := app.CaptureText("Нужно разобрать этот текст")
|
|
if err != nil {
|
|
t.Fatalf("CaptureText: %v", err)
|
|
}
|
|
if dto.ID == "" {
|
|
t.Fatal("empty captured node id")
|
|
}
|
|
if dto.CaptureKind != "text" {
|
|
t.Fatalf("CaptureKind = %q, want text", dto.CaptureKind)
|
|
}
|
|
if dto.CaptureSource != "clipboard" {
|
|
t.Fatalf("CaptureSource = %q, want clipboard", dto.CaptureSource)
|
|
}
|
|
|
|
content, err := app.ReadNote(dto.ID)
|
|
if err != nil {
|
|
t.Fatalf("ReadNote: %v", err)
|
|
}
|
|
if !strings.Contains(content, "Нужно разобрать этот текст") {
|
|
t.Fatalf("captured content missing: %q", content)
|
|
}
|
|
var path string
|
|
if err := app.db.QueryRow(`SELECT f.path FROM notes n JOIN files f ON f.id = n.file_id WHERE n.node_id = ?`, dto.ID).Scan(&path); err != nil {
|
|
t.Fatalf("query note file path: %v", err)
|
|
}
|
|
if !strings.HasPrefix(path, ".verstak/inbox/") {
|
|
t.Fatalf("path = %q, want .verstak/inbox prefix", path)
|
|
}
|
|
|
|
inbox, err := app.ListInboxNodes()
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodes: %v", err)
|
|
}
|
|
var found bool
|
|
for _, item := range inbox {
|
|
if item.ID == dto.ID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("captured text missing from inbox")
|
|
}
|
|
}
|
|
|
|
func TestCaptureURLCreatesInboxArtifact(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
dto, err := app.CaptureURL("https://example.test/page", "Example Page")
|
|
if err != nil {
|
|
t.Fatalf("CaptureURL: %v", err)
|
|
}
|
|
if dto.CaptureKind != "url" {
|
|
t.Fatalf("CaptureKind = %q, want url", dto.CaptureKind)
|
|
}
|
|
if dto.Title != "Example Page" {
|
|
t.Fatalf("Title = %q, want Example Page", dto.Title)
|
|
}
|
|
if dto.Type != "link" {
|
|
t.Fatalf("Type = %q, want link", dto.Type)
|
|
}
|
|
if dto.SourceKind != "url" {
|
|
t.Fatalf("SourceKind = %q, want url", dto.SourceKind)
|
|
}
|
|
if dto.URL != "https://example.test/page" {
|
|
t.Fatalf("URL = %q, want captured URL", dto.URL)
|
|
}
|
|
if dto.Hostname != "example.test" {
|
|
t.Fatalf("Hostname = %q, want example.test", dto.Hostname)
|
|
}
|
|
}
|
|
|
|
func TestCapturePathCopiesFileIntoInbox(t *testing.T) {
|
|
app, vaultRoot := setupTestApp(t)
|
|
sourceDir := t.TempDir()
|
|
source := filepath.Join(sourceDir, "brief.pdf")
|
|
if err := os.WriteFile(source, []byte("pdf content"), 0o640); err != nil {
|
|
t.Fatalf("write source: %v", err)
|
|
}
|
|
|
|
dto, err := app.CapturePath(source)
|
|
if err != nil {
|
|
t.Fatalf("CapturePath: %v", err)
|
|
}
|
|
if dto.CaptureKind != "file" {
|
|
t.Fatalf("CaptureKind = %q, want file", dto.CaptureKind)
|
|
}
|
|
|
|
records, err := app.files.ListByNode(dto.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListByNode: %v", err)
|
|
}
|
|
if len(records) != 1 {
|
|
t.Fatalf("records = %d, want 1", len(records))
|
|
}
|
|
if !strings.HasPrefix(records[0].Path, ".verstak/inbox/") {
|
|
t.Fatalf("path = %q, want .verstak/inbox prefix", records[0].Path)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(vaultRoot, records[0].Path)); err != nil {
|
|
t.Fatalf("captured file missing in vault: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCapturePathCopiesDirectoryIntoInbox(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
source := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(source, "nested"), 0o750); err != nil {
|
|
t.Fatalf("mkdir nested: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(source, "nested", "note.txt"), []byte("nested"), 0o640); err != nil {
|
|
t.Fatalf("write nested file: %v", err)
|
|
}
|
|
|
|
dto, err := app.CapturePath(source)
|
|
if err != nil {
|
|
t.Fatalf("CapturePath: %v", err)
|
|
}
|
|
if dto.CaptureKind != "folder" {
|
|
t.Fatalf("CaptureKind = %q, want folder", dto.CaptureKind)
|
|
}
|
|
|
|
items, err := app.ListItems(dto.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListItems: %v", err)
|
|
}
|
|
var foundNested bool
|
|
for _, item := range items {
|
|
if item.Name == "nested" && item.Type == "folder" {
|
|
foundNested = true
|
|
}
|
|
}
|
|
if !foundNested {
|
|
t.Fatalf("captured folder children missing: %+v", items)
|
|
}
|
|
}
|
|
|
|
func TestCaptureFileDataCreatesImageInboxArtifact(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
data := base64.StdEncoding.EncodeToString([]byte("fake image bytes"))
|
|
|
|
dto, err := app.CaptureFileData("pasted.png", data)
|
|
if err != nil {
|
|
t.Fatalf("CaptureFileData: %v", err)
|
|
}
|
|
if dto.CaptureKind != "image" {
|
|
t.Fatalf("CaptureKind = %q, want image", dto.CaptureKind)
|
|
}
|
|
records, err := app.files.ListByNode(dto.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListByNode: %v", err)
|
|
}
|
|
if len(records) != 1 || records[0].MIME != "image/png" {
|
|
t.Fatalf("records = %+v, want one png image", records)
|
|
}
|
|
}
|
|
|
|
func TestCaptureTextWithSectionContextCreatesUnresolvedArtifact(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
dto, err := app.CaptureTextWithContext("Dropped on today", "paste", `{"contextType":"section","section":"today"}`)
|
|
if err != nil {
|
|
t.Fatalf("CaptureTextWithContext: %v", err)
|
|
}
|
|
|
|
if dto.CaptureStatus != "unresolved" {
|
|
t.Fatalf("CaptureStatus = %q, want unresolved", dto.CaptureStatus)
|
|
}
|
|
if dto.SourceKind != "text" {
|
|
t.Fatalf("SourceKind = %q, want text", dto.SourceKind)
|
|
}
|
|
if dto.CaptureSource != "paste" {
|
|
t.Fatalf("CaptureSource = %q, want paste", dto.CaptureSource)
|
|
}
|
|
if dto.CaptureContextType != "section" {
|
|
t.Fatalf("CaptureContextType = %q, want section", dto.CaptureContextType)
|
|
}
|
|
if dto.CaptureContextSection != "today" {
|
|
t.Fatalf("CaptureContextSection = %q, want today", dto.CaptureContextSection)
|
|
}
|
|
if dto.CaptureContextNodeID != "" {
|
|
t.Fatalf("CaptureContextNodeID = %q, want empty", dto.CaptureContextNodeID)
|
|
}
|
|
if dto.SuggestedTargetNodeID != "" {
|
|
t.Fatalf("SuggestedTargetNodeID = %q, want empty", dto.SuggestedTargetNodeID)
|
|
}
|
|
}
|
|
|
|
func TestCapturePathWithNodeContextUsesNodeIDForLocalInbox(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
sourceDir := t.TempDir()
|
|
source := filepath.Join(sourceDir, "brief.pdf")
|
|
if err := os.WriteFile(source, []byte("pdf"), 0o640); err != nil {
|
|
t.Fatalf("write source: %v", err)
|
|
}
|
|
projectA, err := app.CreateNodeFromTemplate("", "DuckLM", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create project A: %v", err)
|
|
}
|
|
projectB, err := app.CreateNodeFromTemplate("", "DuckLM", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create project B: %v", err)
|
|
}
|
|
|
|
ctx := `{"contextType":"node","nodeId":"` + projectA.ID + `","suggestedTargetNodeId":"` + projectA.ID + `"}`
|
|
dto, err := app.CapturePathWithContext(source, "drop", ctx)
|
|
if err != nil {
|
|
t.Fatalf("CapturePathWithContext: %v", err)
|
|
}
|
|
|
|
if dto.CaptureContextType != "node" {
|
|
t.Fatalf("CaptureContextType = %q, want node", dto.CaptureContextType)
|
|
}
|
|
if dto.CaptureContextNodeID != projectA.ID {
|
|
t.Fatalf("CaptureContextNodeID = %q, want %q", dto.CaptureContextNodeID, projectA.ID)
|
|
}
|
|
if dto.SuggestedTargetNodeID != projectA.ID {
|
|
t.Fatalf("SuggestedTargetNodeID = %q, want %q", dto.SuggestedTargetNodeID, projectA.ID)
|
|
}
|
|
|
|
localA, err := app.ListInboxNodesForTarget(projectA.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodesForTarget(A): %v", err)
|
|
}
|
|
if len(localA) != 1 || localA[0].ID != dto.ID {
|
|
t.Fatalf("local inbox A = %+v, want captured artifact", localA)
|
|
}
|
|
|
|
localB, err := app.ListInboxNodesForTarget(projectB.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodesForTarget(B): %v", err)
|
|
}
|
|
if len(localB) != 0 {
|
|
t.Fatalf("local inbox B = %+v, want empty for same title different node", localB)
|
|
}
|
|
}
|
|
|
|
func TestClassifyClipboardTextRoutesURLBeforePlainText(t *testing.T) {
|
|
kind, value := classifyClipboardText(" https://example.test/page ")
|
|
if kind != "url" {
|
|
t.Fatalf("kind = %q, want url", kind)
|
|
}
|
|
if value != "https://example.test/page" {
|
|
t.Fatalf("value = %q, want trimmed URL", value)
|
|
}
|
|
|
|
kind, value = classifyClipboardText("not a url\nwith more text")
|
|
if kind != "text" {
|
|
t.Fatalf("kind = %q, want text", kind)
|
|
}
|
|
if value != "not a url\nwith more text" {
|
|
t.Fatalf("value = %q, want trimmed text", value)
|
|
}
|
|
}
|