Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
556 lines
17 KiB
Go
556 lines
17 KiB
Go
package workbenchservice
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsTooLongNodeID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(tooLongNodeIDWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "id is too long") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want id length error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsUnknownDisplayMode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(invalidDisplayModeWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "display mode is invalid") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want display mode error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsDuplicateNodeID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(duplicateNodeIDWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "id is duplicated") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want duplicate id error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsInvalidFrame(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(invalidFrameWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "width must be at least") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want frame width error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsInvalidMinimizedTimestamp(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(invalidMinimizedTimestampWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "minimized timestamp is invalid") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want minimized timestamp error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsInvalidLayoutBasis(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
snapshot := workbenchSnapshotWithSpacesFixture()
|
|
snapshot.LayoutBasis.SurfaceSize.Width = 0
|
|
_, _, err := normalizeWorkbenchSnapshot(snapshot)
|
|
if err == nil || !strings.Contains(err.Error(), "surface size") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want layout basis surface size error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotPreservesLockedLayout(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
snapshot := WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{ID: "a", Kind: "agent", Title: "A", Frame: validWorkbenchSnapshotFrame()},
|
|
{ID: "b", Kind: "agent", Title: "B", Frame: validWorkbenchSnapshotFrame()},
|
|
},
|
|
LockedLayout: &WorkbenchSnapshotLockedLayout{
|
|
Preset: WorkbenchSnapshotLayoutPreset{
|
|
Kind: WorkbenchSnapshotLayoutPresetKindRow,
|
|
},
|
|
NodeIDs: []string{"a", "b"},
|
|
NormalizedFrames: map[string]WorkbenchSnapshotNormalizedFrame{
|
|
"a": {X: 0, Y: 0, Width: 0.4, Height: 1},
|
|
"b": {X: 0.42, Y: 0, Width: 0.58, Height: 1},
|
|
},
|
|
},
|
|
}
|
|
|
|
normalizedJSON, _, err := normalizeWorkbenchSnapshot(snapshot)
|
|
if err != nil {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v", err)
|
|
}
|
|
|
|
var decoded WorkbenchSnapshot
|
|
if err := json.Unmarshal(normalizedJSON, &decoded); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
if decoded.LockedLayout == nil || decoded.LockedLayout.Preset.Kind != WorkbenchSnapshotLayoutPresetKindRow {
|
|
t.Fatalf("LockedLayout = %#v, want row layout", decoded.LockedLayout)
|
|
}
|
|
if decoded.LockedLayout.NormalizedFrames["b"].Width != 0.58 {
|
|
t.Fatalf("LockedLayout frames = %#v, want b width 0.58", decoded.LockedLayout.NormalizedFrames)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotCanonicalizesLockedLayoutFramesAtUnitRectEdge(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
float32X := float64(float32(0.2))
|
|
float32Width := float64(float32(0.8))
|
|
if float32X+float32Width <= 1 {
|
|
t.Fatal("float32 layout edge must exceed the unit rect after widening")
|
|
}
|
|
|
|
snapshot := WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{ID: "a", Kind: "agent", Title: "A", Frame: validWorkbenchSnapshotFrame()},
|
|
{ID: "b", Kind: "agent", Title: "B", Frame: validWorkbenchSnapshotFrame()},
|
|
},
|
|
LockedLayout: &WorkbenchSnapshotLockedLayout{
|
|
Preset: WorkbenchSnapshotLayoutPreset{
|
|
Kind: WorkbenchSnapshotLayoutPresetKindRow,
|
|
},
|
|
NodeIDs: []string{"a", "b"},
|
|
NormalizedFrames: map[string]WorkbenchSnapshotNormalizedFrame{
|
|
"a": {X: 0.0625, Y: 0, Width: 0.9375, Height: 1},
|
|
"b": {X: float32X, Y: 0, Width: float32Width, Height: 1},
|
|
},
|
|
},
|
|
}
|
|
|
|
normalizedJSON, _, err := normalizeWorkbenchSnapshot(snapshot)
|
|
if err != nil {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v", err)
|
|
}
|
|
|
|
var decoded WorkbenchSnapshot
|
|
if err := json.Unmarshal(normalizedJSON, &decoded); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
if got := decoded.LockedLayout.NormalizedFrames["a"]; got.X != 0.063 || got.Width != 0.937 {
|
|
t.Fatalf("rounded edge frame = %#v, want x=0.063 width=0.937", got)
|
|
}
|
|
if got := decoded.LockedLayout.NormalizedFrames["b"]; got.X != 0.2 || got.Width != 0.8 {
|
|
t.Fatalf("float32 edge frame = %#v, want x=0.2 width=0.8", got)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsLockedLayoutFrameBeyondTransportTolerance(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
snapshot := WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{ID: "a", Kind: "agent", Title: "A", Frame: validWorkbenchSnapshotFrame()},
|
|
{ID: "b", Kind: "agent", Title: "B", Frame: validWorkbenchSnapshotFrame()},
|
|
},
|
|
LockedLayout: &WorkbenchSnapshotLockedLayout{
|
|
Preset: WorkbenchSnapshotLayoutPreset{
|
|
Kind: WorkbenchSnapshotLayoutPresetKindRow,
|
|
},
|
|
NodeIDs: []string{"a", "b"},
|
|
NormalizedFrames: map[string]WorkbenchSnapshotNormalizedFrame{
|
|
"a": {X: 0.2, Y: 0, Width: 0.801, Height: 1},
|
|
"b": {X: 0, Y: 0, Width: 1, Height: 1},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(snapshot)
|
|
if err == nil || !strings.Contains(err.Error(), "unit layout rect") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want unit rect error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotRejectsOversizedPayload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := normalizeWorkbenchSnapshot(oversizedWorkbenchSnapshotFixture())
|
|
if err == nil || !strings.Contains(err.Error(), "exceeds") {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v, want oversized snapshot error", err)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotEncodesCanonicalFields(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
normalizedJSON, schemaVersion, err := normalizeWorkbenchSnapshot(
|
|
workbenchSnapshotWithSpacesFixture(),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v", err)
|
|
}
|
|
if schemaVersion != workbenchSnapshotContractSchemaVersion {
|
|
t.Fatalf("schemaVersion = %d, want %d", schemaVersion, workbenchSnapshotContractSchemaVersion)
|
|
}
|
|
|
|
var decoded WorkbenchSnapshot
|
|
if err := json.Unmarshal(normalizedJSON, &decoded); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
if decoded.ActiveSpaceID == nil || *decoded.ActiveSpaceID != "space-1" {
|
|
t.Fatalf("ActiveSpaceID = %#v, want space-1", decoded.ActiveSpaceID)
|
|
}
|
|
if len(decoded.Nodes) != 1 {
|
|
t.Fatalf("nodes len = %d, want 1", len(decoded.Nodes))
|
|
}
|
|
if decoded.Nodes[0].RestoreFrame == nil || decoded.Nodes[0].RestoreFrame.Width != 420 {
|
|
t.Fatalf("RestoreFrame = %#v, want width 420", decoded.Nodes[0].RestoreFrame)
|
|
}
|
|
if decoded.Nodes[0].MinimizedAtUnixMs == nil || *decoded.Nodes[0].MinimizedAtUnixMs != 1720000000000 {
|
|
t.Fatalf("MinimizedAtUnixMs = %#v, want 1720000000000", decoded.Nodes[0].MinimizedAtUnixMs)
|
|
}
|
|
if decoded.Spaces == nil || len(*decoded.Spaces) != 1 {
|
|
t.Fatalf("Spaces = %#v, want 1 space", decoded.Spaces)
|
|
}
|
|
if (*decoded.Spaces)[0].Frame == nil || (*decoded.Spaces)[0].Frame.Width != 640 {
|
|
t.Fatalf("Space frame = %#v, want width 640", (*decoded.Spaces)[0].Frame)
|
|
}
|
|
if decoded.LayoutBasis == nil || decoded.LayoutBasis.SurfaceSize.Width != 1440 {
|
|
t.Fatalf("LayoutBasis = %#v, want surface width 1440", decoded.LayoutBasis)
|
|
}
|
|
if decoded.Metadata["initialized"] != true {
|
|
t.Fatalf("Metadata = %#v, want initialized=true", decoded.Metadata)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeWorkbenchSnapshotCanonicalizesTrimmedOrderingDefaultsAndNulls(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
normalizedJSON, _, err := normalizeWorkbenchSnapshot(
|
|
canonicalizationWorkbenchSnapshotFixture(),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("normalizeWorkbenchSnapshot() error = %v", err)
|
|
}
|
|
|
|
var decoded map[string]interface{}
|
|
if err := json.Unmarshal(normalizedJSON, &decoded); err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
|
|
nodes, ok := decoded["nodes"].([]interface{})
|
|
if !ok || len(nodes) != 2 {
|
|
t.Fatalf("nodes = %#v, want 2 canonical nodes", decoded["nodes"])
|
|
}
|
|
firstNode, ok := nodes[0].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("first node = %#v, want object", nodes[0])
|
|
}
|
|
secondNode, ok := nodes[1].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("second node = %#v, want object", nodes[1])
|
|
}
|
|
if firstNode["id"] != "a" || secondNode["id"] != "b" {
|
|
t.Fatalf("node ids = %#v / %#v, want a then b", firstNode["id"], secondNode["id"])
|
|
}
|
|
if firstNode["kind"] != "agent" {
|
|
t.Fatalf("first node kind = %#v, want trimmed agent", firstNode["kind"])
|
|
}
|
|
frame, ok := secondNode["frame"].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("second node frame = %#v, want object", secondNode["frame"])
|
|
}
|
|
if frame["x"] != float64(0) || frame["y"] != float64(3.142) {
|
|
t.Fatalf("frame coordinates = %#v, want x=0 y=3.142", frame)
|
|
}
|
|
if secondNode["displayMode"] != "floating" {
|
|
t.Fatalf("second node displayMode = %#v, want floating default", secondNode["displayMode"])
|
|
}
|
|
if secondNode["isMinimized"] != false {
|
|
t.Fatalf("second node isMinimized = %#v, want false default", secondNode["isMinimized"])
|
|
}
|
|
if restoreFrame, exists := secondNode["restoreFrame"]; !exists || restoreFrame != nil {
|
|
t.Fatalf("second node restoreFrame = %#v (exists=%t), want explicit null", restoreFrame, exists)
|
|
}
|
|
|
|
nodeStack, ok := decoded["nodeStack"].([]interface{})
|
|
if !ok || len(nodeStack) != 2 || nodeStack[0] != "b" || nodeStack[1] != "a" {
|
|
t.Fatalf("nodeStack = %#v, want [b a]", decoded["nodeStack"])
|
|
}
|
|
if decoded["activeNodeId"] != "a" {
|
|
t.Fatalf("activeNodeId = %#v, want fallback a", decoded["activeNodeId"])
|
|
}
|
|
|
|
spaces, ok := decoded["spaces"].([]interface{})
|
|
if !ok || len(spaces) != 2 {
|
|
t.Fatalf("spaces = %#v, want 2 canonical spaces", decoded["spaces"])
|
|
}
|
|
firstSpace, ok := spaces[0].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("first space = %#v, want object", spaces[0])
|
|
}
|
|
secondSpace, ok := spaces[1].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("second space = %#v, want object", spaces[1])
|
|
}
|
|
if firstSpace["id"] != "space-a" || secondSpace["id"] != "space-z" {
|
|
t.Fatalf("space ids = %#v / %#v, want space-a then space-z", firstSpace["id"], secondSpace["id"])
|
|
}
|
|
firstSpaceNodeIDs, ok := firstSpace["nodeIds"].([]interface{})
|
|
if !ok || len(firstSpaceNodeIDs) != 1 || firstSpaceNodeIDs[0] != "a" {
|
|
t.Fatalf("first space nodeIds = %#v, want trimmed unique [a]", firstSpace["nodeIds"])
|
|
}
|
|
if frameValue, exists := firstSpace["frame"]; !exists || frameValue != nil {
|
|
t.Fatalf("first space frame = %#v (exists=%t), want explicit null", frameValue, exists)
|
|
}
|
|
if decoded["activeSpaceId"] != "space-a" {
|
|
t.Fatalf("activeSpaceId = %#v, want fallback space-a", decoded["activeSpaceId"])
|
|
}
|
|
}
|
|
|
|
func workbenchSnapshotWithSpacesFixture() WorkbenchSnapshot {
|
|
displayMode := WorkbenchSnapshotDisplayModeFullscreen
|
|
isMinimized := true
|
|
minimizedAtUnixMs := int64(1720000000000)
|
|
nodeStack := []string{"workspace-files"}
|
|
activeNodeID := "workspace-files"
|
|
activeSpaceID := "space-1"
|
|
spaces := []WorkbenchSnapshotSpace{
|
|
{
|
|
ID: "space-1",
|
|
Name: "Primary",
|
|
NodeIDs: []string{"workspace-files"},
|
|
Frame: &WorkbenchSnapshotFrame{
|
|
X: 40,
|
|
Y: 48,
|
|
Width: 640,
|
|
Height: 480,
|
|
},
|
|
Data: map[string]interface{}{"layout": "single"},
|
|
},
|
|
}
|
|
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: "workspace-files",
|
|
Kind: "workspaceFiles",
|
|
Title: "Files",
|
|
Frame: WorkbenchSnapshotFrame{
|
|
X: 12,
|
|
Y: 18,
|
|
Width: 400,
|
|
Height: 320,
|
|
},
|
|
DisplayMode: &displayMode,
|
|
RestoreFrame: &WorkbenchSnapshotFrame{
|
|
X: 24,
|
|
Y: 30,
|
|
Width: 420,
|
|
Height: 340,
|
|
},
|
|
IsMinimized: &isMinimized,
|
|
MinimizedAtUnixMs: &minimizedAtUnixMs,
|
|
Data: map[string]interface{}{"workspaceID": "workspace-1"},
|
|
AdapterState: map[string]interface{}{
|
|
"reactFlow": map[string]interface{}{
|
|
"type": "workspaceFilesNode",
|
|
"measured": map[string]interface{}{
|
|
"width": 400,
|
|
"height": 320,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NodeStack: &nodeStack,
|
|
ActiveNodeID: &activeNodeID,
|
|
Spaces: &spaces,
|
|
ActiveSpaceID: &activeSpaceID,
|
|
LayoutBasis: &WorkbenchSnapshotLayoutBasis{
|
|
SurfaceSize: WorkbenchSnapshotSize{
|
|
Width: 1440,
|
|
Height: 900,
|
|
},
|
|
LayoutConstraints: WorkbenchSnapshotLayoutConstraints{
|
|
MinWidth: 280,
|
|
MinHeight: 160,
|
|
SurfacePadding: 0,
|
|
SafeArea: WorkbenchSnapshotSafeArea{
|
|
Top: 52,
|
|
Right: 0,
|
|
Bottom: 88,
|
|
Left: 0,
|
|
},
|
|
},
|
|
},
|
|
Metadata: map[string]interface{}{"initialized": true},
|
|
}
|
|
}
|
|
|
|
func duplicateNodeIDWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: "duplicate-node",
|
|
Kind: "terminal",
|
|
Title: "First",
|
|
Frame: validWorkbenchSnapshotFrame(),
|
|
},
|
|
{
|
|
ID: "duplicate-node",
|
|
Kind: "workspaceOverview",
|
|
Title: "Second",
|
|
Frame: validWorkbenchSnapshotFrame(),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func invalidDisplayModeWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
displayMode := WorkbenchSnapshotDisplayMode("tabbed")
|
|
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: "node-1",
|
|
Kind: "terminal",
|
|
Title: "Terminal",
|
|
Frame: validWorkbenchSnapshotFrame(),
|
|
DisplayMode: &displayMode,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func invalidFrameWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: "node-1",
|
|
Kind: "terminal",
|
|
Title: "Terminal",
|
|
Frame: WorkbenchSnapshotFrame{
|
|
X: 0,
|
|
Y: 0,
|
|
Width: workbenchSnapshotContractMinFrameWidth - 1,
|
|
Height: workbenchSnapshotContractMinFrameHeight - 1,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func invalidMinimizedTimestampWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
minimizedAtUnixMs := int64(-1)
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: "node-1",
|
|
Kind: "terminal",
|
|
Title: "Terminal",
|
|
Frame: validWorkbenchSnapshotFrame(),
|
|
MinimizedAtUnixMs: &minimizedAtUnixMs,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func oversizedWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{},
|
|
Metadata: map[string]interface{}{
|
|
"payload": strings.Repeat("x", workbenchSnapshotContractMaxSerializedBytes),
|
|
},
|
|
}
|
|
}
|
|
|
|
func tooLongNodeIDWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: strings.Repeat("a", workbenchSnapshotContractMaxNodeIDLength+1),
|
|
Kind: "workspaceFiles",
|
|
Title: "Files",
|
|
Frame: validWorkbenchSnapshotFrame(),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func validWorkbenchSnapshotFrame() WorkbenchSnapshotFrame {
|
|
return WorkbenchSnapshotFrame{
|
|
X: 0,
|
|
Y: 0,
|
|
Width: workbenchSnapshotContractMinFrameWidth,
|
|
Height: workbenchSnapshotContractMinFrameHeight,
|
|
}
|
|
}
|
|
|
|
func canonicalizationWorkbenchSnapshotFixture() WorkbenchSnapshot {
|
|
nodeStack := []string{" b ", "missing", "a", "a"}
|
|
activeNodeID := " missing "
|
|
activeSpaceID := " missing "
|
|
spaces := []WorkbenchSnapshotSpace{
|
|
{
|
|
ID: " space-z ",
|
|
Name: "Later",
|
|
NodeIDs: []string{" b ", "b"},
|
|
Frame: &WorkbenchSnapshotFrame{
|
|
X: 10,
|
|
Y: 11,
|
|
Width: 320,
|
|
Height: 240,
|
|
},
|
|
},
|
|
{
|
|
ID: " space-a ",
|
|
Name: "Earlier",
|
|
NodeIDs: []string{" a ", "a"},
|
|
Frame: nil,
|
|
},
|
|
}
|
|
|
|
return WorkbenchSnapshot{
|
|
SchemaVersion: workbenchSnapshotContractSchemaVersion,
|
|
Nodes: []WorkbenchSnapshotNode{
|
|
{
|
|
ID: " b ",
|
|
Kind: " terminal ",
|
|
Title: "Terminal",
|
|
Frame: WorkbenchSnapshotFrame{
|
|
X: math.Copysign(0, -1),
|
|
Y: 3.14159,
|
|
Width: 200,
|
|
Height: 150,
|
|
},
|
|
DisplayMode: nil,
|
|
Data: map[string]interface{}{"workspaceID": "workspace-1"},
|
|
},
|
|
{
|
|
ID: " a ",
|
|
Kind: " agent ",
|
|
Title: "Agent",
|
|
Frame: WorkbenchSnapshotFrame{
|
|
X: 10,
|
|
Y: 10,
|
|
Width: 180,
|
|
Height: 140,
|
|
},
|
|
},
|
|
},
|
|
NodeStack: &nodeStack,
|
|
ActiveNodeID: &activeNodeID,
|
|
Spaces: &spaces,
|
|
ActiveSpaceID: &activeSpaceID,
|
|
}
|
|
}
|