Files
ConfigKit/internal/engine/callback_panic_test.go

74 lines
2.2 KiB
Go

package engine
import (
"errors"
"testing"
)
func capturePanic(call func()) (recovered any) {
defer func() { recovered = recover() }()
call()
return nil
}
func requirePanicValue(t *testing.T, want any, call func()) {
t.Helper()
if got := capturePanic(call); got != want {
t.Fatalf("panic = %#v, want %#v", got, want)
}
}
func TestCallbackContextsCloseWhenCallbacksPanic(t *testing.T) {
type config struct {
Value string `yaml:"value"`
Version string `yaml:"version"`
}
t.Run("resolution", func(t *testing.T) {
sentinel := errors.New("resolution panic sentinel")
var retained *Resolution
got := capturePanic(func() {
_, _ = testLoad[config](NoSource(), Options[config]{Definition: Definition[config]{Resolve: func(_ *config, resolution *Resolution) error {
retained = resolution
panic(sentinel)
}}})
})
if got != sentinel {
t.Fatalf("callback panic = %#v, want original sentinel", got)
}
requirePanicValue(t, closedCallbackContextMessage, func() { retained.IsExplicit(Keys("value")) })
})
t.Run("validation", func(t *testing.T) {
sentinel := errors.New("validation panic sentinel")
var retained *Validation
got := capturePanic(func() {
_, _ = testLoad[config](NoSource(), Options[config]{Definition: Definition[config]{Validate: func(_ *config, validation *Validation) {
retained = validation
panic(sentinel)
}}})
})
if got != sentinel {
t.Fatalf("callback panic = %#v, want original sentinel", got)
}
requirePanicValue(t, closedCallbackContextMessage, func() { retained.Error(Keys("value"), "too late") })
})
t.Run("version", func(t *testing.T) {
sentinel := errors.New("version panic sentinel")
var retained *Validation
got := capturePanic(func() {
_, _ = testLoad[config](Bytes("version.yml", []byte("version: v1\n")), Options[config]{Definition: Definition[config]{
Version: &VersionRule{Path: Keys("version"), Check: func(_ Version, validation *Validation) error {
retained = validation
panic(sentinel)
}},
}})
})
if got != sentinel {
t.Fatalf("callback panic = %#v, want original sentinel", got)
}
requirePanicValue(t, closedCallbackContextMessage, func() { retained.Warning(Keys("version"), "too late") })
})
}