Files
agent-radar 2ed3415fb7
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
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

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,
}
}