103 lines
4.6 KiB
Go
103 lines
4.6 KiB
Go
package platform
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
const legacyMigrationFixture = `{"schema_version":1,"nodes":[
|
|
{"id":"f","type":"frame","position":{"x":100,"y":200},"width":640,"height":400,"data":{"kind":"frame","title":"Frame","text":"","labelMode":"fixed"}},
|
|
{"id":"empty","type":"frame","position":{"x":0,"y":0},"width":400,"height":300,"data":{"kind":"frame","title":"Empty","text":""}},
|
|
{"id":"a","type":"material","position":{"x":150,"y":260},"data":{"kind":"text","title":"A","text":"preserved","frameId":"f","fontSize":24}},
|
|
{"id":"b","type":"material","position":{"x":250,"y":300},"data":{"kind":"script","title":"B","text":"","frameId":"f"}},
|
|
{"id":"outside","type":"material","position":{"x":160,"y":270},"data":{"kind":"text","title":"Not a member","text":"overlaps frame"}}
|
|
],"edges":[{"id":"internal","source":"a","target":"b","sourceHandle":"right","targetHandle":"left"},{"id":"boundary","source":"b","target":"outside","sourceHandle":"right","targetHandle":"left"},{"id":"boundary-2","source":"b","target":"outside","sourceHandle":"right","targetHandle":"top"}],"viewport":{"x":2000,"y":3000,"zoom":2}}`
|
|
|
|
func TestLegacyMigrationOwnershipAndBoundary(t *testing.T) {
|
|
parent := canvasSnapshot{BoardID: "parent", Version: 5, Document: json.RawMessage(legacyMigrationFixture)}
|
|
plan := legacyPlan("p", "w", parent)
|
|
if plan.ChildCount != 2 || len(plan.Frames) != 2 {
|
|
t.Fatal("empty frame omitted")
|
|
}
|
|
if !reflect.DeepEqual(plan.Frames[1].NodeIDs, []string{"a", "b"}) {
|
|
t.Fatalf("non-explicit member included: %+v", plan.Frames)
|
|
}
|
|
children := map[string]string{"f": "11111111-1111-4111-8111-111111111111", "empty": "22222222-2222-4222-8222-222222222222"}
|
|
migrated, docs, err := migrateLegacyDocument(parent.Document, children)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
data := canvasNodeData(migrated)
|
|
if data["a"] != nil || data["b"] != nil || data["outside"] == nil {
|
|
t.Fatal("ownership duplicated or overlapping node absorbed")
|
|
}
|
|
ports := data["f"]["ports"].([]any)
|
|
if len(ports) != 1 {
|
|
t.Fatalf("ports not deduplicated: %+v", ports)
|
|
}
|
|
if ports[0].(map[string]any)["nodeId"] != "b" {
|
|
t.Fatal("boundary port targets wrong child node")
|
|
}
|
|
var child map[string]any
|
|
_ = json.Unmarshal(docs["f"], &child)
|
|
nodes := child["nodes"].([]any)
|
|
if len(nodes) != 2 {
|
|
t.Fatal("child membership")
|
|
}
|
|
a := nodes[0].(map[string]any)
|
|
position := a["position"].(map[string]any)
|
|
if position["x"] != float64(26) || position["y"] != float64(24) {
|
|
t.Fatalf("inverse projection used viewport: %v", position)
|
|
}
|
|
if a["data"].(map[string]any)["text"] != "preserved" || a["data"].(map[string]any)["frameId"] != nil {
|
|
t.Fatal("member data changed")
|
|
}
|
|
if len(child["edges"].([]any)) != 1 {
|
|
t.Fatal("internal edge lost")
|
|
}
|
|
var p map[string]any
|
|
_ = json.Unmarshal(migrated, &p)
|
|
if len(p["edges"].([]any)) != 2 {
|
|
t.Fatal("boundary edges lost")
|
|
}
|
|
for _, v := range p["edges"].([]any) {
|
|
e := v.(map[string]any)
|
|
if e["source"] != "f" {
|
|
t.Fatal("boundary edge not remapped")
|
|
}
|
|
}
|
|
// A second plan skips linked frames and does not create more children.
|
|
if legacyPlan("p", "w", canvasSnapshot{BoardID: "parent", Version: 6, Document: migrated}).ChildCount != 0 {
|
|
t.Fatal("migration not repeatable")
|
|
}
|
|
changed := parent
|
|
changed.Version++
|
|
if legacyPlan("p", "w", changed).PlanID == plan.PlanID {
|
|
t.Fatal("plan not bound to version")
|
|
}
|
|
}
|
|
|
|
func TestMigrationPreservesBezierGeometry(t *testing.T) {
|
|
var doc map[string]any
|
|
_ = json.Unmarshal([]byte(legacyMigrationFixture), &doc)
|
|
doc["schema_version"] = 2
|
|
e := doc["edges"].([]any)[0].(map[string]any)
|
|
e["data"] = map[string]any{"path": map[string]any{"type": "bezier-chain", "startControl": map[string]any{"x": 90, "y": 0}, "knots": []any{map[string]any{"id": "k", "position": map[string]any{"x": 200, "y": 280}, "in": map[string]any{"x": -20, "y": 0}, "out": map[string]any{"x": 20, "y": 0}, "mode": "symmetric"}}}}
|
|
raw, _ := json.Marshal(doc)
|
|
_, children, err := migrateLegacyDocument(raw, map[string]string{"f": "11111111-1111-4111-8111-111111111111", "empty": "22222222-2222-4222-8222-222222222222"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var child map[string]any
|
|
_ = json.Unmarshal(children["f"], &child)
|
|
path := child["edges"].([]any)[0].(map[string]any)["data"].(map[string]any)["path"].(map[string]any)
|
|
knot := path["knots"].([]any)[0].(map[string]any)
|
|
if knot["position"].(map[string]any)["x"] != float64(76) || knot["position"].(map[string]any)["y"] != float64(44) {
|
|
t.Fatal("knot position not translated")
|
|
}
|
|
if knot["in"].(map[string]any)["x"] != float64(-20) || path["startControl"].(map[string]any)["x"] != float64(90) {
|
|
t.Fatal("control vector translated")
|
|
}
|
|
}
|