mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
```bash for file in `cat diffys`; do printf '%s\n%s\n' "// Copyright 2021 Molecula Corp. All rights reserved." "$(cat $file)" >$file; done ```
318 lines
7.8 KiB
Go
318 lines
7.8 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package testhook_test
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/molecula/featurebase/v2/testhook"
|
|
)
|
|
|
|
func TestAuditor_CatchError(t *testing.T) {
|
|
auditor := testhook.NewVerifyCloseAuditor(nil)
|
|
var x, y int
|
|
reg, err := auditor.Registry(&x)
|
|
if err != nil {
|
|
t.Fatalf("requesting registry: %v", err)
|
|
}
|
|
err = reg.Created(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating x: %v", err)
|
|
}
|
|
err = reg.Opened(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening x: %v", err)
|
|
}
|
|
err = reg.Seen(&y, nil)
|
|
if err == nil {
|
|
t.Fatalf("seeing unopened y: expected error, didn't get one")
|
|
}
|
|
err = reg.Seen(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("seeing opened x: unexpected error %v", err)
|
|
}
|
|
err = reg.Created(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating y: %v", err)
|
|
}
|
|
err = reg.Opened(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening y: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("closing x: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err == nil {
|
|
t.Fatalf("double-closing x: expected error, didn't get one")
|
|
}
|
|
err = reg.Destroyed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("destroying x: got unexpected error %v", err)
|
|
}
|
|
err, errs := auditor.FinalCheck()
|
|
if err == nil {
|
|
t.Fatalf("unclosed y not detected")
|
|
}
|
|
_ = errs
|
|
}
|
|
|
|
type ignoreLiveness struct {
|
|
skippable *int
|
|
}
|
|
|
|
func (ign *ignoreLiveness) Live(o interface{}, _ *testhook.RegistryEntry) error {
|
|
if ptr, ok := o.(*int); ok {
|
|
if ptr == ign.skippable {
|
|
return nil
|
|
}
|
|
}
|
|
return errors.New("unexpected live object")
|
|
}
|
|
|
|
var _ testhook.RegistryHookLive = &ignoreLiveness{}
|
|
|
|
func TestAuditor_DiscardError(t *testing.T) {
|
|
var x, y int
|
|
iptr := reflect.TypeOf(&x)
|
|
auditor := testhook.NewVerifyCloseAuditor(testhook.RegistryHooks{iptr: &ignoreLiveness{skippable: &y}})
|
|
reg, err := auditor.Registry(&x)
|
|
if err != nil {
|
|
t.Fatalf("requesting registry: %v", err)
|
|
}
|
|
err = reg.Created(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating x: %v", err)
|
|
}
|
|
err = reg.Opened(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening x: %v", err)
|
|
}
|
|
err = reg.Seen(&y, nil)
|
|
if err == nil {
|
|
t.Fatalf("seeing unopened y: expected error, didn't get one")
|
|
}
|
|
err = reg.Seen(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("seeing opened x: unexpected error %v", err)
|
|
}
|
|
err = reg.Created(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating y: %v", err)
|
|
}
|
|
err = reg.Opened(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening y: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("closing x: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err == nil {
|
|
t.Fatalf("double-closing x: expected error, didn't get one")
|
|
}
|
|
err = reg.Destroyed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("destroying x: got unexpected error %v", err)
|
|
}
|
|
err, errs := auditor.FinalCheck()
|
|
if err != nil {
|
|
t.Fatalf("expected to skip y, instead got err %v, error list %v", err, errs)
|
|
}
|
|
}
|
|
|
|
func TestAuditor_KeepError(t *testing.T) {
|
|
var x, y, z int
|
|
iptr := reflect.TypeOf(&x)
|
|
auditor := testhook.NewVerifyCloseAuditor(testhook.RegistryHooks{iptr: &ignoreLiveness{skippable: &z}})
|
|
reg, err := auditor.Registry(&x)
|
|
if err != nil {
|
|
t.Fatalf("requesting registry: %v", err)
|
|
}
|
|
err = reg.Created(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating x: %v", err)
|
|
}
|
|
err = reg.Opened(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening x: %v", err)
|
|
}
|
|
err = reg.Seen(&y, nil)
|
|
if err == nil {
|
|
t.Fatalf("seeing unopened y: expected error, didn't get one")
|
|
}
|
|
err = reg.Seen(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("seeing opened x: unexpected error %v", err)
|
|
}
|
|
err = reg.Created(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("creating y: %v", err)
|
|
}
|
|
err = reg.Opened(&y, nil)
|
|
if err != nil {
|
|
t.Fatalf("opening y: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("closing x: %v", err)
|
|
}
|
|
err = reg.Closed(&x, nil)
|
|
if err == nil {
|
|
t.Fatalf("double-closing x: expected error, didn't get one")
|
|
}
|
|
err = reg.Destroyed(&x, nil)
|
|
if err != nil {
|
|
t.Fatalf("destroying x: %v", err)
|
|
}
|
|
err, errs := auditor.FinalCheck()
|
|
if err == nil {
|
|
t.Fatalf("undestroyed y not detected")
|
|
}
|
|
_ = errs
|
|
}
|
|
|
|
type failHook struct {
|
|
calls int
|
|
}
|
|
|
|
func (f *failHook) Opened(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
func (f *failHook) WasOpened(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry, err error) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
// Implement WasSeen but not Seen, so we can verify that the only-one
|
|
// case works in both directions.
|
|
func (f *failHook) WasSeen(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry, err error) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
func (f *failHook) Closed(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
func (f *failHook) WasClosed(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry, err error) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
func (f *failHook) Live(i interface{}, ent *testhook.RegistryEntry) error {
|
|
f.calls++
|
|
return errors.New("failHook always fails")
|
|
}
|
|
|
|
type successHook struct {
|
|
calls int
|
|
}
|
|
|
|
func (s *successHook) Opened(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry) error {
|
|
s.calls++
|
|
return nil
|
|
}
|
|
|
|
func (s *successHook) WasOpened(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry, err error) error {
|
|
s.calls++
|
|
return nil
|
|
}
|
|
|
|
func (s *successHook) Closed(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry) error {
|
|
s.calls++
|
|
return nil
|
|
}
|
|
|
|
func (s *successHook) Seen(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry) error {
|
|
s.calls++
|
|
return nil
|
|
}
|
|
|
|
// successHook allows an error to leak from WasClosed.
|
|
func (s *successHook) WasClosed(i interface{}, kv testhook.KV, _ *testhook.RegistryEntry, err error) error {
|
|
s.calls++
|
|
return err
|
|
}
|
|
|
|
func (s *successHook) Live(i interface{}, ent *testhook.RegistryEntry) error {
|
|
s.calls++
|
|
return errors.New("even successHook can fail sometimes")
|
|
}
|
|
|
|
func TestComposedHooks(t *testing.T) {
|
|
s := &successHook{}
|
|
f := &failHook{}
|
|
sExp, fExp := 0, 0
|
|
var err error
|
|
checkExp := func(when string) {
|
|
if s.calls != sExp {
|
|
t.Fatalf("after %s, expected %d calls to successHook, got %d", when, sExp, s.calls)
|
|
}
|
|
if f.calls != fExp {
|
|
t.Fatalf("after %s, expected %d calls to failHook, got %d", when, fExp, f.calls)
|
|
}
|
|
}
|
|
combined := testhook.Compose(s, f)
|
|
// Opened: we expect both opened calls to be hit, and the error from
|
|
// the second to come back.
|
|
err = combined.Opened(nil, nil, nil)
|
|
sExp++
|
|
fExp++
|
|
checkExp("opened")
|
|
if err == nil {
|
|
t.Fatalf("composed hook, opened: didn't error")
|
|
}
|
|
if err.Error() != "failHook always fails" {
|
|
t.Fatalf("composed hook, opened: expected failHook always fails, got %v", err)
|
|
}
|
|
|
|
// WasOpened: we expect the error from failHook to be overridden.
|
|
err = combined.WasOpened(nil, nil, nil, nil)
|
|
sExp++
|
|
fExp++
|
|
checkExp("wasOpened")
|
|
if err != nil {
|
|
t.Fatalf("composed hook, wasOpened: expected no error, got %v", err)
|
|
}
|
|
|
|
// Seen: nothing to call for failHook
|
|
err = combined.Seen(nil, nil, nil)
|
|
sExp++
|
|
checkExp("seen")
|
|
if err != nil {
|
|
t.Fatalf("composed hook, seen: expected no error, got %v", err)
|
|
}
|
|
|
|
// WasSeen: nothing to call for successHook
|
|
err = combined.WasSeen(nil, nil, nil, nil)
|
|
fExp++
|
|
checkExp("wasSeen")
|
|
if err == nil {
|
|
t.Fatalf("composed hook, wasSeen: expected error, didn't get it")
|
|
}
|
|
|
|
// WasClosed: expect both to get called, but successHook to leak the error up
|
|
err = combined.WasClosed(nil, nil, nil, nil)
|
|
sExp++
|
|
fExp++
|
|
checkExp("wasClosed")
|
|
if err == nil {
|
|
t.Fatalf("composed hook, wasClosed: expected error, didn't get it")
|
|
}
|
|
|
|
// Live: the failure from successHook (oops) should prevent failHook from
|
|
// being called.
|
|
err = combined.Live(nil, nil)
|
|
sExp++
|
|
checkExp("live")
|
|
if err == nil {
|
|
t.Fatalf("composed hook, live: expected error, didn't get it")
|
|
}
|
|
}
|