源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
package agentruntime
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCanonicalFileChangesNormalizeProviderShapes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
payload map[string]any
|
||||
path string
|
||||
change string
|
||||
}{
|
||||
{
|
||||
name: "cursor delete kind",
|
||||
payload: map[string]any{
|
||||
"kind": "delete",
|
||||
"content": []any{map[string]any{
|
||||
"type": "diff", "path": "/workspace/obsolete.txt", "oldText": "obsolete", "newText": "",
|
||||
}},
|
||||
},
|
||||
path: "/workspace/obsolete.txt",
|
||||
change: "deleted",
|
||||
},
|
||||
{
|
||||
name: "codex nested change kind",
|
||||
payload: map[string]any{
|
||||
"kind": "edit",
|
||||
"input": map[string]any{"changes": []any{map[string]any{
|
||||
"path": "/workspace/new.go", "kind": map[string]any{"type": "add"}, "diff": "@@ -0,0 +1 @@\n+package new",
|
||||
}}},
|
||||
},
|
||||
path: "/workspace/new.go",
|
||||
change: "added",
|
||||
},
|
||||
{
|
||||
name: "claude structured patch change",
|
||||
payload: map[string]any{
|
||||
"output": map[string]any{"changes": []any{map[string]any{
|
||||
"path": "/workspace/app.ts", "type": "update", "diff": "@@ -1 +1 @@\n-old\n+new",
|
||||
}}},
|
||||
},
|
||||
path: "/workspace/app.ts",
|
||||
change: "modified",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
files := payloadArray(canonicalFileChangesFromToolPayload(test.payload)["files"])
|
||||
if len(files) != 1 || files[0]["path"] != test.path || files[0]["change"] != test.change {
|
||||
t.Fatalf("canonical files = %#v, want %s %s", files, test.change, test.path)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalFileChangesMovesRawCreatedBodyOutOfUnifiedDiff(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
content := "# Liying\n\n- 自我介绍\n- 欢迎来到我的 README\n"
|
||||
got := canonicalFileChangesFromToolPayload(map[string]any{
|
||||
"fileChanges": map[string]any{
|
||||
"files": []any{map[string]any{
|
||||
"path": "/workspace/README.md",
|
||||
"change": "created",
|
||||
"unifiedDiff": content,
|
||||
}},
|
||||
},
|
||||
})
|
||||
files := payloadArray(got["files"])
|
||||
if len(files) != 1 {
|
||||
t.Fatalf("canonical files = %#v, want one file", files)
|
||||
}
|
||||
file := files[0]
|
||||
if file["change"] != "added" || file["newString"] != content {
|
||||
t.Fatalf("canonical file = %#v, want added file with its body in newString", file)
|
||||
}
|
||||
if _, exists := file["diff"]; exists {
|
||||
t.Fatalf("canonical file retained invalid diff: %#v", file)
|
||||
}
|
||||
if _, exists := file["unifiedDiff"]; exists {
|
||||
t.Fatalf("canonical file retained invalid unifiedDiff: %#v", file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalFileChangesKeepsValidUnifiedDiff(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
diff := "@@ -1 +1 @@\n-old\n+new"
|
||||
got := canonicalFileChangesFromToolPayload(map[string]any{
|
||||
"fileChanges": map[string]any{
|
||||
"files": []any{map[string]any{
|
||||
"path": "/workspace/app.ts",
|
||||
"change": "modified",
|
||||
"unifiedDiff": diff,
|
||||
}},
|
||||
},
|
||||
})
|
||||
file := payloadArray(got["files"])[0]
|
||||
if file["unifiedDiff"] != diff || file["diff"] != diff {
|
||||
t.Fatalf("canonical file = %#v, want valid unified diff preserved", file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalFileChangesChoosesFirstValidDiffAlias(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
valid := "@@ -1 +1 @@\n-old\n+new"
|
||||
rawBody := "README\n- bullet\n"
|
||||
got := canonicalFileChangesFromToolPayload(map[string]any{
|
||||
"fileChanges": map[string]any{
|
||||
"files": []any{map[string]any{
|
||||
"path": "/workspace/app.ts",
|
||||
"change": "modified",
|
||||
"diff": rawBody,
|
||||
"unifiedDiff": valid,
|
||||
}},
|
||||
},
|
||||
})
|
||||
file := payloadArray(got["files"])[0]
|
||||
if file["diff"] != valid || file["unifiedDiff"] != valid {
|
||||
t.Fatalf("canonical file = %#v, want the valid later alias", file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalFileChangesPreservesInvalidModifiedBodyWithoutDiff(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
body := "README\n- bullet\n"
|
||||
got := canonicalFileChangesFromToolPayload(map[string]any{
|
||||
"fileChanges": map[string]any{
|
||||
"files": []any{map[string]any{
|
||||
"path": "/workspace/README.md",
|
||||
"change": "modified",
|
||||
"diff": body,
|
||||
}},
|
||||
},
|
||||
})
|
||||
file := payloadArray(got["files"])[0]
|
||||
if file["newString"] != body || file["change"] != "modified" {
|
||||
t.Fatalf("canonical file = %#v, want modified body preserved as newString", file)
|
||||
}
|
||||
if _, exists := file["diff"]; exists {
|
||||
t.Fatalf("canonical file retained invalid diff: %#v", file)
|
||||
}
|
||||
if _, exists := file["content"]; exists {
|
||||
t.Fatalf("canonical file retained obsolete content field: %#v", file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLooksLikeUnifiedDiffRejectsPseudoHunks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if looksLikeUnifiedDiff("@@ notes\n- bullet") {
|
||||
t.Fatal("pseudo hunk was accepted as a unified diff")
|
||||
}
|
||||
if !looksLikeUnifiedDiff("@@ -1 +1 @@\n-old\n+new") {
|
||||
t.Fatal("valid unified diff was rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeCanonicalFileChangesKeepsTurnLevelSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
current := map[string]any{"files": []any{
|
||||
map[string]any{"path": "/workspace/new.ts", "change": "added", "oldString": "", "newString": "first"},
|
||||
map[string]any{"path": "/workspace/old.ts", "change": "modified", "oldString": "before", "newString": "after"},
|
||||
}}
|
||||
incoming := map[string]any{"files": []any{
|
||||
map[string]any{"path": "/workspace/new.ts", "change": "modified", "oldString": "first", "newString": "final"},
|
||||
map[string]any{"path": "/workspace/old.ts", "change": "deleted", "oldString": "after", "newString": ""},
|
||||
}}
|
||||
|
||||
files := payloadArray(mergeCanonicalFileChanges(current, incoming)["files"])
|
||||
if len(files) != 2 {
|
||||
t.Fatalf("merged files = %#v, want two files", files)
|
||||
}
|
||||
if files[0]["change"] != "added" || files[0]["oldString"] != "" || files[0]["newString"] != "final" {
|
||||
t.Fatalf("created-then-edited file = %#v, want added with final content", files[0])
|
||||
}
|
||||
if files[1]["change"] != "deleted" || files[1]["oldString"] != "before" || files[1]["newString"] != "" {
|
||||
t.Fatalf("edited-then-deleted file = %#v, want deleted with original content", files[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeCanonicalFileChangesDeduplicatesAndCancelsCreatedFiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
current := map[string]any{"files": []any{
|
||||
map[string]any{"path": "/workspace/a.txt", "change": "added", "newString": "first"},
|
||||
map[string]any{"path": "/workspace/a.txt", "change": "modified", "newString": "final"},
|
||||
}}
|
||||
incoming := map[string]any{"files": []any{
|
||||
map[string]any{"path": "/workspace/a.txt", "change": "deleted"},
|
||||
map[string]any{"path": "/workspace/b.txt", "change": "added", "newString": "b"},
|
||||
}}
|
||||
|
||||
files := payloadArray(mergeCanonicalFileChanges(current, incoming)["files"])
|
||||
if len(files) != 1 || files[0]["path"] != "/workspace/b.txt" {
|
||||
t.Fatalf("merged files = %#v, want only the surviving file", files)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user