- wrap existing errors with context + file:line, newline-separated for readable error chains - dual mode philosophy: panics + if err != nil - unify Expect for goexit and panic cases
38 lines
1.5 KiB
Go
38 lines
1.5 KiB
Go
//go:build !result_goexit
|
||
|
||
// Default error-exit implementation: Expect and Expectf signal failure via
|
||
// panic, which is caught by the enclosing result.Go / result.Run goroutine.
|
||
//
|
||
// Performance: error path ≈ 1.4 µs / ~352 B per failure (goroutine spawn +
|
||
// panic + recover). The runtime.Goexit build is about 4× slower (~5.5 µs).
|
||
//
|
||
// Trade-off: a deferred recover() inside a Go/Run closure that does not
|
||
// re-panic unrecognized values will silently swallow a result failure and let
|
||
// execution continue as if nothing happened. This follows standard Go practice
|
||
// for recover() — always check the type and re-panic anything unrecognized:
|
||
//
|
||
// defer func() {
|
||
// if r := recover(); r != nil {
|
||
// if _, ok := r.(MyExpectedType); !ok {
|
||
// panic(r) // not ours — let it propagate
|
||
// }
|
||
// // handle MyExpectedType ...
|
||
// }
|
||
// }()
|
||
//
|
||
// If your codebase uses bare recover() inside Go/Run closures, or integrates
|
||
// with frameworks that do, opt into the safer runtime.Goexit implementation:
|
||
//
|
||
// go test -tags result_goexit ./...
|
||
// go build -tags result_goexit ./...
|
||
|
||
package result
|
||
|
||
// exitGoroutine signals a result failure by panicking with se.
|
||
// The panic is caught by the enclosing Async goroutine via recover().
|
||
func exitGoroutine(se *stackError) { panic(se) }
|
||
|
||
// collectGoexitFailure is a no-op in the panic build — failures travel via
|
||
// panic/recover, not via the gErrors map.
|
||
func collectGoexitFailure() error { return nil }
|