package result_test import ( "os" "os/exec" "strings" "testing" "gitea.djmil.dev/go/template/pkg/result" ) // TestMustCollected verifies that Must() failures are collected by Run as // normal errors, not left as unhandled panics. By contrast, genuine runtime // panics (nil-deref, index out of bounds, etc.) are NOT collected — they // propagate and crash the program. That behavior cannot be unit-tested // without a subprocess, so it is only documented here. func TestMustCollected(t *testing.T) { err := result.Run(func() { result.Errf[int]("unrecoverable").Must() }) if err == nil { t.Fatal("expected error, got nil") } if !strings.Contains(err.Error(), "unrecoverable") { t.Fatalf("unexpected error: %v", err) } } // TestGenuineRuntimePanicPropagates verifies that genuine runtime panics // (nil-deref, index out of bounds, etc.) are NOT collected by Go/Run — they // crash the program. Tested via subprocess so the crash doesn't kill the suite. func TestGenuineRuntimePanicPropagates(t *testing.T) { if os.Getenv("RESULT_TEST_CRASH") == "1" { _ = result.Run(func() { panic("genuine runtime panic") // not a *stackError, so Run must not collect it }) return } cmd := exec.Command(os.Args[0], "-test.run=TestGenuineRuntimePanicPropagates") cmd.Env = append(os.Environ(), "RESULT_TEST_CRASH=1") if cmd.Run() == nil { t.Fatal("expected subprocess to crash, but it exited cleanly") } } // TestStackTrace verifies that StackTrace returns a non-empty string containing // the call site of the failing Expect call. func TestStackTrace(t *testing.T) { err := result.Run(func() { parsePort("not-a-number").Expect("parse port") }) if err == nil { t.Fatal("expected error, got nil") } trace := result.StackTrace(err) if trace == "" { t.Fatal("expected non-empty stack trace") } if !strings.Contains(trace, "panic_test.go") { t.Fatalf("expected trace to reference panic_test.go, got:\n%s", trace) } }