220 lines
6.0 KiB
Go
220 lines
6.0 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"verstak/internal/core/nodes"
|
|
)
|
|
|
|
func TestListInboxNodesReturnsOnlyCapturedArtifacts(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
manual, err := app.CreateNodeFromTemplate("", "Manual Root", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create manual root: %v", err)
|
|
}
|
|
legacyInbox, err := app.CreateNodeFromTemplate("", "Legacy Inbox Root", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create legacy inbox root: %v", err)
|
|
}
|
|
captured, err := app.CreateNodeFromTemplate("", "Captured Artifact", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create captured artifact: %v", err)
|
|
}
|
|
child, err := app.CreateNodeFromTemplate(captured.ID, "Nested Child", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create child: %v", err)
|
|
}
|
|
if _, err := app.db.Exec(`UPDATE nodes SET section = 'inbox' WHERE id = ?`, legacyInbox.ID); err != nil {
|
|
t.Fatalf("mark legacy inbox: %v", err)
|
|
}
|
|
if err := app.nodes.MetaSet(captured.ID, "capture.inbox", "true"); err != nil {
|
|
t.Fatalf("mark captured: %v", err)
|
|
}
|
|
if err := app.nodes.MetaSet(captured.ID, "capture.kind", "text"); err != nil {
|
|
t.Fatalf("mark capture kind: %v", err)
|
|
}
|
|
if err := app.nodes.MetaSet(captured.ID, "capture.source", "clipboard"); err != nil {
|
|
t.Fatalf("mark capture source: %v", err)
|
|
}
|
|
|
|
list, err := app.ListInboxNodes()
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodes: %v", err)
|
|
}
|
|
|
|
got := map[string]bool{}
|
|
for _, item := range list {
|
|
got[item.ID] = true
|
|
}
|
|
if !got[captured.ID] {
|
|
t.Fatal("captured artifact missing from inbox")
|
|
}
|
|
for _, item := range list {
|
|
if item.ID == captured.ID {
|
|
if item.CaptureKind != "text" {
|
|
t.Fatalf("CaptureKind = %q, want text", item.CaptureKind)
|
|
}
|
|
if item.CaptureSource != "clipboard" {
|
|
t.Fatalf("CaptureSource = %q, want clipboard", item.CaptureSource)
|
|
}
|
|
}
|
|
}
|
|
if got[manual.ID] {
|
|
t.Fatal("manual root should not be in inbox")
|
|
}
|
|
if got[legacyInbox.ID] {
|
|
t.Fatal("section=inbox root without capture metadata should not be in inbox")
|
|
}
|
|
if got[child.ID] {
|
|
t.Fatal("nested child should not be in inbox")
|
|
}
|
|
|
|
workspace, err := app.ListWorkspaceTree()
|
|
if err != nil {
|
|
t.Fatalf("ListWorkspaceTree: %v", err)
|
|
}
|
|
for _, item := range workspace {
|
|
if item.ID == captured.ID {
|
|
t.Fatal("captured artifact should not be shown in workspace tree")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAssignInboxNodeMovesArtifactIntoCase(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
parent, err := app.CreateNodeFromTemplate("", "Target Case", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create parent: %v", err)
|
|
}
|
|
captured, err := app.CaptureText("Captured task material")
|
|
if err != nil {
|
|
t.Fatalf("CaptureText: %v", err)
|
|
}
|
|
|
|
moved, err := app.AssignInboxNode(captured.ID, parent.ID)
|
|
if err != nil {
|
|
t.Fatalf("AssignInboxNode: %v", err)
|
|
}
|
|
if moved.ParentID == nil || *moved.ParentID != parent.ID {
|
|
t.Fatalf("ParentID = %v, want %q", moved.ParentID, parent.ID)
|
|
}
|
|
|
|
inbox, err := app.ListInboxNodes()
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodes: %v", err)
|
|
}
|
|
for _, item := range inbox {
|
|
if item.ID == captured.ID {
|
|
t.Fatal("assigned artifact should leave inbox")
|
|
}
|
|
}
|
|
notes, err := app.ListNotes(parent.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListNotes: %v", err)
|
|
}
|
|
var found bool
|
|
for _, note := range notes {
|
|
if note.ID == captured.ID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("assigned text artifact missing from target case notes")
|
|
}
|
|
}
|
|
|
|
func TestDeleteInboxNodeRemovesArtifactFromInbox(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
captured, err := app.CaptureText("Delete this captured material")
|
|
if err != nil {
|
|
t.Fatalf("CaptureText: %v", err)
|
|
}
|
|
if err := app.DeleteInboxNode(captured.ID); err != nil {
|
|
t.Fatalf("DeleteInboxNode: %v", err)
|
|
}
|
|
|
|
inbox, err := app.ListInboxNodes()
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodes: %v", err)
|
|
}
|
|
for _, item := range inbox {
|
|
if item.ID == captured.ID {
|
|
t.Fatal("deleted artifact should leave inbox")
|
|
}
|
|
}
|
|
if _, err := app.nodes.GetActive(captured.ID); !errors.Is(err, nodes.ErrNotFound) {
|
|
t.Fatalf("GetActive err = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestResolveCapturedURLCreatesLinkForTargetOnly(t *testing.T) {
|
|
app, _ := setupTestApp(t)
|
|
|
|
projectA, err := app.CreateNodeFromTemplate("", "Project A", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create project A: %v", err)
|
|
}
|
|
projectB, err := app.CreateNodeFromTemplate("", "Project B", "folder.default")
|
|
if err != nil {
|
|
t.Fatalf("create project B: %v", err)
|
|
}
|
|
ctx := `{"contextType":"node","nodeId":"` + projectA.ID + `","suggestedTargetNodeId":"` + projectA.ID + `"}`
|
|
captured, err := app.CaptureURLWithContext("https://example.test/article", "Example Article", "drop", ctx)
|
|
if err != nil {
|
|
t.Fatalf("CaptureURLWithContext: %v", err)
|
|
}
|
|
|
|
localBefore, err := app.ListInboxNodesForTarget(projectA.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodesForTarget before: %v", err)
|
|
}
|
|
if len(localBefore) != 1 || localBefore[0].ID != captured.ID {
|
|
t.Fatalf("local inbox before = %+v, want captured URL", localBefore)
|
|
}
|
|
|
|
if _, err := app.ResolveInboxNode(captured.ID, projectA.ID); err != nil {
|
|
t.Fatalf("ResolveInboxNode: %v", err)
|
|
}
|
|
|
|
globalAfter, err := app.ListInboxNodes()
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodes after: %v", err)
|
|
}
|
|
for _, item := range globalAfter {
|
|
if item.ID == captured.ID {
|
|
t.Fatal("resolved URL should leave global inbox")
|
|
}
|
|
}
|
|
|
|
localAfter, err := app.ListInboxNodesForTarget(projectA.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListInboxNodesForTarget after: %v", err)
|
|
}
|
|
if len(localAfter) != 0 {
|
|
t.Fatalf("local inbox after = %+v, want empty", localAfter)
|
|
}
|
|
|
|
linksA, err := app.ListLinks(projectA.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListLinks(A): %v", err)
|
|
}
|
|
if len(linksA) != 1 {
|
|
t.Fatalf("links A = %+v, want one link", linksA)
|
|
}
|
|
if linksA[0].Title != "Example Article" || linksA[0].URL != "https://example.test/article" || linksA[0].Hostname != "example.test" {
|
|
t.Fatalf("link A = %+v, want captured URL data", linksA[0])
|
|
}
|
|
|
|
linksB, err := app.ListLinks(projectB.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListLinks(B): %v", err)
|
|
}
|
|
if len(linksB) != 0 {
|
|
t.Fatalf("links B = %+v, want empty", linksB)
|
|
}
|
|
}
|