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
159 lines
4.8 KiB
Go
159 lines
4.8 KiB
Go
package storesqlite
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeAgentSessionRailSectionDerivesKeyFromPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
root := t.TempDir()
|
|
canonical := NormalizeProjectPath(root)
|
|
aliased := root
|
|
if runtime.GOOS == "darwin" {
|
|
// On macOS TempDir is often under /var which is a symlink to /private/var.
|
|
if evaluated, err := filepath.EvalSymlinks(root); err == nil && evaluated != root {
|
|
aliased = root
|
|
canonical = evaluated
|
|
}
|
|
}
|
|
|
|
section := normalizeAgentSessionRailSection(RailSection{
|
|
Kind: RailSectionKindProject,
|
|
ProjectPath: aliased,
|
|
Key: "project:" + aliased,
|
|
})
|
|
if section.ProjectPath != canonical {
|
|
t.Fatalf("ProjectPath = %q, want %q", section.ProjectPath, canonical)
|
|
}
|
|
wantKey := RailSectionKeyForProject(canonical)
|
|
if section.Key != wantKey {
|
|
t.Fatalf("Key = %q, want %q", section.Key, wantKey)
|
|
}
|
|
if !isValidAgentSessionRailSection(section) {
|
|
t.Fatalf("normalized section should be valid: %#v", section)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeAgentSessionRailSectionRepairsMismatchedKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
root := t.TempDir()
|
|
canonical := NormalizeProjectPath(root)
|
|
section := normalizeAgentSessionRailSection(RailSection{
|
|
Kind: RailSectionKindProject,
|
|
ProjectPath: canonical,
|
|
Key: "project:/unrelated/path",
|
|
})
|
|
if section.Key != RailSectionKeyForProject(canonical) {
|
|
t.Fatalf("Key = %q, want derived from path", section.Key)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeRailSectionKeyAliasesCompareEqual(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
root := t.TempDir()
|
|
canonical := NormalizeProjectPath(root)
|
|
if canonical == root {
|
|
t.Skip("temp dir path is already canonical; no symlink alias to assert")
|
|
}
|
|
if NormalizeRailSectionKey("project:"+root) != NormalizeRailSectionKey("project:"+canonical) {
|
|
t.Fatalf(
|
|
"NormalizeRailSectionKey(%q) != NormalizeRailSectionKey(%q)",
|
|
root,
|
|
canonical,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeAgentSessionRailSectionClearsConversationProjectBinding(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
section := normalizeAgentSessionRailSection(RailSection{
|
|
Kind: RailSectionKindConversations,
|
|
ProjectPath: t.TempDir(),
|
|
Key: "project:/tmp/x",
|
|
})
|
|
if section.ProjectPath != "" || section.Key != RailSectionKeyConversations {
|
|
t.Fatalf("conversations section = %#v", section)
|
|
}
|
|
}
|
|
|
|
func TestClassifyRailSectionUsesCanonicalProjectKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
root := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(root, "pkg"), 0o755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
section := ClassifyRailSection(filepath.Join(root, "pkg"), nil, []string{root})
|
|
want := RailSectionKeyForProject(root)
|
|
if section.Key != want {
|
|
t.Fatalf("ClassifyRailSection key = %q, want %q", section.Key, want)
|
|
}
|
|
}
|
|
|
|
func TestRailSectionKeyForProjectUsesWindowsCaseInsensitiveIdentity(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("Windows filesystem identity is platform-specific")
|
|
}
|
|
left := `C:\Users\Demo\Repo`
|
|
right := `c:\users\demo\repo`
|
|
if RailSectionKeyForProject(left) != RailSectionKeyForProject(right) {
|
|
t.Fatalf("Windows project keys differ: %q vs %q", RailSectionKeyForProject(left), RailSectionKeyForProject(right))
|
|
}
|
|
}
|
|
|
|
func TestWindowsRailPreservesPOSIXProjectNamespace(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const projectPath = "/workspace/Snake"
|
|
if got := normalizeProjectPathForPlatform(projectPath, "windows"); got != projectPath {
|
|
t.Fatalf("NormalizeProjectPath = %q, want %q", got, projectPath)
|
|
}
|
|
if got := railIdentityPathForPlatform(projectPath, "windows"); got != projectPath {
|
|
t.Fatalf("rail identity = %q, want case-sensitive %q", got, projectPath)
|
|
}
|
|
if !isProjectPathWithinForPlatform(projectPath, projectPath+"/src", "windows") {
|
|
t.Fatalf("POSIX child should remain within %q on Windows", projectPath)
|
|
}
|
|
if isProjectPathWithinForPlatform(projectPath, "/workspace/snake/src", "windows") {
|
|
t.Fatalf("POSIX project identity should remain case-sensitive on Windows")
|
|
}
|
|
}
|
|
|
|
func TestRailSectionKeyForProjectPreservesPOSIXIdentityOnWindows(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("Windows path normalization is platform-specific")
|
|
}
|
|
const projectPath = "/workspace/Snake"
|
|
if got, want := RailSectionKeyForProject(projectPath), "project:"+projectPath; got != want {
|
|
t.Fatalf("RailSectionKeyForProject = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestIsProjectPathWithinUsesWindowsCaseInsensitiveIdentity(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("Windows filesystem identity is platform-specific")
|
|
}
|
|
root := filepath.Join(t.TempDir(), "Project")
|
|
child := filepath.Join(root, "Packages", "App")
|
|
if err := os.MkdirAll(child, 0o755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
if !IsProjectPathWithin(strings.ToUpper(root), strings.ToLower(child)) {
|
|
t.Fatalf("Windows path identity should recognize %q as within %q", child, root)
|
|
}
|
|
}
|