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

153 lines
4.7 KiB
Go

package workspacefiles
import (
"errors"
"path/filepath"
"testing"
)
func TestNormalizeLogicalPathWithinRoot(t *testing.T) {
tests := []struct {
name string
input string
want LogicalPath
wantErr error
}{
{name: "empty defaults to root", input: "", want: "/"},
{name: "relative path stays under root", input: "src/App.tsx", want: "/src/App.tsx"},
{name: "collapses duplicate separators", input: "/Users/test/project//src///", want: "/Users/test/project/src"},
{name: "cleans dot segments", input: "/Users/test/project/src/../docs", want: "/Users/test/project/docs"},
{name: "normalizes backslashes", input: "src\\App.tsx", want: "/src/App.tsx"},
{name: "normalizes Windows drive absolute path", input: `C:\\Users\\test\\project`, want: "/C:/Users/test/project"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NormalizeLogicalPath(tt.input)
if tt.wantErr != nil {
if !errors.Is(err, tt.wantErr) {
t.Fatalf("error = %v, want %v", err, tt.wantErr)
}
return
}
if err != nil {
t.Fatalf("NormalizeLogicalPath() error = %v", err)
}
if got != tt.want {
t.Fatalf("NormalizeLogicalPath() = %q, want %q", got, tt.want)
}
})
}
}
func TestNormalizeLogicalPathWithinWindowsRootAcceptsDriveAbsolutePath(t *testing.T) {
for _, input := range []string{
`C:\\Users\\test\\project`,
`c:/Users/test/project`,
`/c/Users/test/project`,
} {
t.Run(input, func(t *testing.T) {
got, err := NormalizeLogicalPathWithinRoot(
input,
`C:\\Users\\test\\project`,
)
if err != nil {
t.Fatalf("NormalizeLogicalPathWithinRoot() error = %v", err)
}
if got != "/C:/Users/test/project" {
t.Fatalf("NormalizeLogicalPathWithinRoot() = %q, want /C:/Users/test/project", got)
}
})
}
}
func TestNormalizeLogicalPathWithinWindowsRootKeepsPosixDriveLikePathPosix(t *testing.T) {
got, err := NormalizeLogicalPathWithinRoot("/c/Users/test/project", "/")
if err != nil {
t.Fatalf("NormalizeLogicalPathWithinRoot() error = %v", err)
}
if got != "/c/Users/test/project" {
t.Fatalf("NormalizeLogicalPathWithinRoot() = %q, want /c/Users/test/project", got)
}
}
func TestLogicalRelativePathMatchesWindowsDrivePathsCaseInsensitively(t *testing.T) {
got, err := LogicalRelativePath(
"/c:/users/test/project/src/App.tsx",
`C:\\Users\\test\\project`,
)
if err != nil {
t.Fatalf("LogicalRelativePath() error = %v", err)
}
if got != "src/App.tsx" {
t.Fatalf("LogicalRelativePath() = %q, want src/App.tsx", got)
}
}
func TestNormalizeLogicalPathWithinExplicitRootRejectsEscapes(t *testing.T) {
root := "/Users/test/project"
tests := []struct {
name string
input string
want LogicalPath
wantErr error
}{
{name: "empty defaults to explicit root", input: "", want: "/Users/test/project"},
{name: "relative path stays under explicit root", input: "src/App.tsx", want: "/Users/test/project/src/App.tsx"},
{name: "rejects absolute escape", input: "/etc/passwd", wantErr: ErrPathEscapesRoot},
{name: "rejects parent escape", input: "/Users/test/project/../../etc", wantErr: ErrPathEscapesRoot},
{name: "rejects relative parent escape", input: "../etc", wantErr: ErrPathEscapesRoot},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NormalizeLogicalPathWithinRoot(tt.input, root)
if tt.wantErr != nil {
if !errors.Is(err, tt.wantErr) {
t.Fatalf("error = %v, want %v", err, tt.wantErr)
}
return
}
if err != nil {
t.Fatalf("NormalizeLogicalPathWithinRoot() error = %v", err)
}
if got != tt.want {
t.Fatalf("NormalizeLogicalPathWithinRoot() = %q, want %q", got, tt.want)
}
})
}
}
func TestJoinPhysicalPathRejectsEscape(t *testing.T) {
root := WorkspaceRoot{
LogicalRoot: "/workspace",
PhysicalRoot: filepath.Join(t.TempDir(), "workspace"),
}
got, err := JoinPhysicalPath(root, "/workspace/src/App.tsx")
if err != nil {
t.Fatalf("JoinPhysicalPath() error = %v", err)
}
want := filepath.Join(root.PhysicalRoot, "src", "App.tsx")
if got != want {
t.Fatalf("JoinPhysicalPath() = %q, want %q", got, want)
}
_, err = JoinPhysicalPath(root, "/etc/passwd")
if !errors.Is(err, ErrPathEscapesRoot) {
t.Fatalf("JoinPhysicalPath escape error = %v, want %v", err, ErrPathEscapesRoot)
}
}
func TestIsPhysicalPathWithinRoot(t *testing.T) {
root := filepath.Join(t.TempDir(), "workspace")
if !IsPhysicalPathWithinRoot(root, filepath.Join(root, "src", "main.go")) {
t.Fatal("child path should be within root")
}
if !IsPhysicalPathWithinRoot(root, root) {
t.Fatal("root path should be within root")
}
if IsPhysicalPathWithinRoot(root, filepath.Join(root, "..", "outside")) {
t.Fatal("sibling path should not be within root")
}
}