package config import ( "os" "path/filepath" "strconv" "strings" "testing" ) func TestResolveExplicitPathWinsOverEnvironmentAndDiscovery(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) first := writeDiscoverableInstallation(t, root, filepath.Join(root, "first")) second := writeDiscoverableInstallation(t, root, filepath.Join(root, "second")) got, err := Resolve(first, func(string) string { return second }, root) if err != nil { t.Fatal(err) } if got != first { t.Fatalf("Resolve() = %q, want explicit %q", got, first) } } func TestResolveUsesEnvironmentBeforeAutomaticDiscovery(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "one")) environmentPath := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "two")) got, err := Resolve("", func(name string) string { if name == "THOTHII_INSTALLATION" { return environmentPath } return "" }, root) if err != nil { t.Fatal(err) } if got != environmentPath { t.Fatalf("Resolve() = %q, want environment %q", got, environmentPath) } } func TestResolveFindsDeployDescriptorFromNestedDirectory(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) want := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "psd")) nested := filepath.Join(root, "tools", "nested") if err := os.MkdirAll(nested, 0o755); err != nil { t.Fatal(err) } got, err := Resolve("", func(string) string { return "" }, nested) if err != nil { t.Fatal(err) } canonicalWant, err := filepath.EvalSymlinks(want) if err != nil { t.Fatal(err) } if got != canonicalWant { t.Fatalf("Resolve() = %q, want canonical %q", got, canonicalWant) } } func TestResolveUsesLocalCandidateBeforeAncestorCandidate(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) ancestor := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "ancestor")) localDirectory := filepath.Join(root, "frontend", "feature") local := writeDiscoverableInstallation(t, root, filepath.Join(localDirectory, "deploy", "local")) got, err := Resolve("", func(string) string { return "" }, localDirectory) if err != nil { t.Fatal(err) } want, err := filepath.EvalSymlinks(local) if err != nil { t.Fatal(err) } if got != want { t.Fatalf("Resolve() = %q, want local %q before ancestor %q", got, want, ancestor) } } func TestResolveDiscoversDescriptorFromLinkedWorktree(t *testing.T) { root := t.TempDir() writeDiscoverableLinkedWorktree(t, root) want := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "worktree")) got, err := Resolve("", func(string) string { return "" }, filepath.Join(root, "frontend")) if err != nil { t.Fatal(err) } canonicalWant, err := filepath.EvalSymlinks(want) if err != nil { t.Fatal(err) } if got != canonicalWant { t.Fatalf("Resolve() = %q, want %q from linked worktree", got, canonicalWant) } } func TestResolveIgnoresArtifactsAndRejectsAmbiguousValidCandidates(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) artifacts := writeDiscoverableInstallation(t, root, filepath.Join(root, ".artifacts", "run")) _ = artifacts first := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "one")) second := writeDiscoverableInstallation(t, root, filepath.Join(root, "deploy", "two")) _, err := Resolve("", func(string) string { return "" }, root) if err == nil || !strings.Contains(err.Error(), "multiple") || !strings.Contains(err.Error(), "one") || !strings.Contains(err.Error(), "two") || !strings.Contains(err.Error(), first) || !strings.Contains(err.Error(), second) { t.Fatalf("Resolve() error = %v, want ambiguity naming valid candidates", err) } } func TestResolveDoesNotSelectAnArtifactsDescriptor(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) writeDiscoverableInstallation(t, root, filepath.Join(root, ".artifacts", "run")) _, err := Resolve("", func(string) string { return "" }, root) if err == nil || !strings.Contains(err.Error(), "descriptor not found") { t.Fatalf("Resolve() error = %v, want artifacts candidate excluded", err) } } func TestResolveReportsNoCandidateWithOverrideGuidance(t *testing.T) { root := t.TempDir() writeDiscoverableProject(t, root) _, err := Resolve("", func(string) string { return "" }, root) if err == nil || !strings.Contains(err.Error(), "tht setup") || !strings.Contains(err.Error(), "--installation") { t.Fatalf("Resolve() error = %v, want setup and override guidance", err) } } func TestResolveDoesNotSearchAboveTheDiscoveredProjectRoot(t *testing.T) { container := t.TempDir() root := filepath.Join(container, "thothii") writeDiscoverableProject(t, root) outside := writeDiscoverableInstallation(t, root, container) _, err := Resolve("", func(string) string { return "" }, filepath.Join(root, "frontend")) if err == nil || !strings.Contains(err.Error(), "tht setup") || strings.Contains(err.Error(), outside) { t.Fatalf("Resolve() error = %v, want project-bounded setup guidance", err) } } func writeDiscoverableProject(t *testing.T, root string) { writeDiscoverableProjectWithGitMarker(t, root, false) } func writeDiscoverableLinkedWorktree(t *testing.T, root string) { writeDiscoverableProjectWithGitMarker(t, root, true) } func writeDiscoverableProjectWithGitMarker(t *testing.T, root string, linkedWorktree bool) { t.Helper() for _, path := range []string{"backend", "frontend", "harness", "tools", "deploy"} { if err := os.MkdirAll(filepath.Join(root, path), 0o755); err != nil { t.Fatal(err) } } gitPath := filepath.Join(root, ".git") if linkedWorktree { if err := os.WriteFile(gitPath, []byte("gitdir: /tmp/thothii-worktree.git\n"), 0o600); err != nil { t.Fatal(err) } } else if err := os.MkdirAll(gitPath, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "compose.yaml"), []byte("services: {}\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "deploy", "compose.local.yaml"), []byte("services: {}\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "operator.env"), nil, 0o600); err != nil { t.Fatal(err) } } func writeDiscoverableInstallation(t *testing.T, projectRoot, directory string) string { t.Helper() if err := os.MkdirAll(directory, 0o755); err != nil { t.Fatal(err) } physicalDirectory, err := filepath.EvalSymlinks(directory) if err != nil { t.Fatal(err) } envFile := filepath.Join(physicalDirectory, "operator.env") authDirectory := filepath.Join(physicalDirectory, "auth") if err := os.WriteFile(envFile, []byte("SAFE_VALUE=1\nTHT_AUTH_CONFIG_ROOT="+strconv.Quote(authDirectory)+"\n"), 0o600); err != nil { t.Fatal(err) } installationPath := filepath.Join(directory, "thothii-installation.yaml") contents := "profile: local\nprojectDirectory: " + projectRoot + "\nenvFile: " + envFile + "\nauthentication:\n configDirectory: " + authDirectory + "\n" if err := os.WriteFile(installationPath, []byte(contents), 0o600); err != nil { t.Fatal(err) } return installationPath }