diff --git a/internal/adapters/promptkit/adapter_test.go b/internal/adapters/promptkit/adapter_test.go index 50ab792..76211c3 100644 --- a/internal/adapters/promptkit/adapter_test.go +++ b/internal/adapters/promptkit/adapter_test.go @@ -508,6 +508,7 @@ func TestNewValidatesConfiguration(t *testing.T) { } func TestLocalBackendAndMissingCredentialBehavior(t *testing.T) { + t.Setenv("WEATHERREPORTER_TEST_MISSING_KEY", "") profiles := testProfileDirectory(t, `id: local-profile backend: local model: local-model diff --git a/internal/app/generation_test.go b/internal/app/generation_test.go index 284f8af..6097ca7 100644 --- a/internal/app/generation_test.go +++ b/internal/app/generation_test.go @@ -510,9 +510,7 @@ func TestGenerateDetailedDoesNotReplaceSymbolicLinkOutput(t *testing.T) { t.Fatal(err) } outputPath := filepath.Join(dir, "daily.md") - if err := os.Symlink(backing, outputPath); err != nil { - t.Fatal(err) - } + requireSymlink(t, backing, outputPath) bundle := generationBundle(t) collector := &generationCollector{bundle: &bundle} executor := &generationExecutor{} diff --git a/internal/app/output_test.go b/internal/app/output_test.go index aedacbc..2d655fa 100644 --- a/internal/app/output_test.go +++ b/internal/app/output_test.go @@ -46,9 +46,7 @@ func TestResolveComparisonOutputDirectory(t *testing.T) { func TestResolveOutputDirRejectsDanglingSymlinkComponents(t *testing.T) { workingDir := t.TempDir() dangling := filepath.Join(workingDir, "dangling") - if err := os.Symlink(filepath.Join(workingDir, "missing"), dangling); err != nil { - t.Fatal(err) - } + requireSymlink(t, filepath.Join(workingDir, "missing"), dangling) for _, directory := range []string{dangling, filepath.Join(dangling, "reports")} { t.Run(filepath.Base(directory), func(t *testing.T) { @@ -63,9 +61,7 @@ func TestResolveOutputDirAllowsMissingDirectoryBelowValidSymlink(t *testing.T) { workingDir := t.TempDir() target := t.TempDir() link := filepath.Join(workingDir, "linked") - if err := os.Symlink(target, link); err != nil { - t.Fatal(err) - } + requireSymlink(t, target, link) directory := filepath.Join(link, "reports") got, err := resolveOutputDir(workingDir, directory) @@ -73,3 +69,10 @@ func TestResolveOutputDirAllowsMissingDirectoryBelowValidSymlink(t *testing.T) { t.Fatalf("resolveOutputDir() = %q, %v, want %q, nil", got, err, directory) } } + +func requireSymlink(t *testing.T, target string, link string) { + t.Helper() + if err := os.Symlink(target, link); err != nil { + t.Skipf("symlink support is unavailable: %v", err) + } +} diff --git a/internal/comparison/publish_test.go b/internal/comparison/publish_test.go index 511776a..88d8d78 100644 --- a/internal/comparison/publish_test.go +++ b/internal/comparison/publish_test.go @@ -47,18 +47,16 @@ func TestPlanDestination(t *testing.T) { assertDestinationErrorKind(t, workingDirectory, string(os.PathSeparator), false, DestinationFilesystemRoot) assertDestinationErrorKind(t, workingDirectory, "relative", false, DestinationInvalidPath) - link := filepath.Join(workingDirectory, "link") - if err := os.Symlink(empty, link); err != nil { - t.Fatal(err) - } - assertDestinationErrorKind(t, workingDirectory, link, false, DestinationSymlink) + t.Run("symbolic links", func(t *testing.T) { + link := filepath.Join(workingDirectory, "link") + requireSymlink(t, empty, link) + assertDestinationErrorKind(t, workingDirectory, link, false, DestinationSymlink) - dangling := filepath.Join(workingDirectory, "dangling") - if err := os.Symlink(filepath.Join(workingDirectory, "missing"), dangling); err != nil { - t.Fatal(err) - } - assertDestinationErrorKind(t, workingDirectory, dangling, false, DestinationSymlink) - assertDestinationErrorKind(t, workingDirectory, filepath.Join(dangling, "child"), false, DestinationInspection) + dangling := filepath.Join(workingDirectory, "dangling") + requireSymlink(t, filepath.Join(workingDirectory, "missing"), dangling) + assertDestinationErrorKind(t, workingDirectory, dangling, false, DestinationSymlink) + assertDestinationErrorKind(t, workingDirectory, filepath.Join(dangling, "child"), false, DestinationInspection) + }) nonempty := filepath.Join(workingDirectory, "nonempty") if err := os.Mkdir(nonempty, 0o755); err != nil { @@ -116,9 +114,7 @@ func TestRecognizeBundleRejectsUnsafeAndMalformedContents(t *testing.T) { if err := os.Remove(path); err != nil { t.Fatal(err) } - if err := os.Symlink(filepath.Join(directory, DataPackageFilename), path); err != nil { - t.Fatal(err) - } + requireSymlink(t, filepath.Join(directory, DataPackageFilename), path) }}, {name: "digest mismatch", mutate: func(t *testing.T, directory string) { t.Helper() @@ -298,9 +294,7 @@ func TestPublishReauthorizesMovedDestination(t *testing.T) { }, mutate: func(t *testing.T, target string) { t.Helper() - if err := os.Symlink("unrelated-target", target); err != nil { - t.Fatal(err) - } + requireSymlink(t, "unrelated-target", target) }, verify: func(t *testing.T, target string) { t.Helper() @@ -365,6 +359,13 @@ func TestPublishReauthorizesMovedDestination(t *testing.T) { } } +func requireSymlink(t *testing.T, target string, link string) { + t.Helper() + if err := os.Symlink(target, link); err != nil { + t.Skipf("symlink support is unavailable: %v", err) + } +} + func TestPublishRetainsUnauthorizedMovedDestinationWhenRestoreFails(t *testing.T) { workingDirectory := t.TempDir() target := filepath.Join(workingDirectory, "comparison-daily") diff --git a/internal/promptdebug/debug_writer_test.go b/internal/promptdebug/debug_writer_test.go index 4fe15e1..a450015 100644 --- a/internal/promptdebug/debug_writer_test.go +++ b/internal/promptdebug/debug_writer_test.go @@ -253,9 +253,7 @@ func TestPromptDebugWriterKeepsWritesAnchoredToOpenedRoot(t *testing.T) { if err := os.Rename(root, anchoredRoot); err != nil { t.Fatalf("replace opened root: %v", err) } - if err := os.Symlink(outside, root); err != nil { - t.Skipf("symlink creation is unavailable: %v", err) - } + requireSymlink(t, outside, root) ref := promptDebugRef() ref.RunID = "run-anchored" @@ -307,9 +305,7 @@ func TestPromptDebugWriterRejectsUnsafeRootsAndReferences(t *testing.T) { if err := os.Mkdir(target, debugDirectoryMode); err != nil { t.Fatalf("create root symlink target: %v", err) } - if err := os.Symlink(target, link); err != nil { - t.Fatalf("create root symlink: %v", err) - } + requireSymlink(t, target, link) if _, err := NewPromptDebugWriter(link); err == nil { t.Fatal("NewPromptDebugWriter(symlink) error = nil") } @@ -334,15 +330,20 @@ func TestPromptDebugWriterRejectsUnsafeRootsAndReferences(t *testing.T) { if err := os.Mkdir(outside, debugDirectoryMode); err != nil { t.Fatalf("create symlink component target: %v", err) } - if err := os.Symlink(outside, filepath.Join(root, "debug", "daily")); err != nil { - t.Fatalf("create symlink component: %v", err) - } + requireSymlink(t, outside, filepath.Join(root, "debug", "daily")) if _, err := writer.WritePreparation(promptDebugRef(), promptDebugPreparationFixture(), nil); err == nil { t.Fatal("WritePreparation(symlink component) error = nil") } } } +func requireSymlink(t *testing.T, target string, link string) { + t.Helper() + if err := os.Symlink(target, link); err != nil { + t.Skipf("symlink support is unavailable: %v", err) + } +} + func promptDebugRef() PromptDebugRef { return PromptDebugRef{ReportID: report.Daily, ValidDate: "2026-05-29", RunID: "run-123"} }