container/stub: remove function call in handleExit
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m21s
Test / Hpkg (push) Successful in 4m21s
Test / Sandbox (race detector) (push) Successful in 4m44s
Test / Hakurei (race detector) (push) Successful in 5m24s
Test / Hakurei (push) Successful in 2m26s
Test / Flake checks (push) Successful in 1m36s

This gets inlined and does not cause problems usually but turns out -coverpkg uninlines it and breaks the recovery.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-09-04 19:39:12 +09:00
parent 19630a9593
commit 3920acf8c2
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
6 changed files with 57 additions and 35 deletions

View File

@ -149,7 +149,7 @@ func checkSimple(t *testing.T, fname string, testCases []simpleTestCase) {
t.Helper()
k := &kstub{stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} }, tc.want)}
defer k.HandleExit()
defer stub.HandleExit(t)
if err := tc.f(k); !reflect.DeepEqual(err, tc.wantErr) {
t.Errorf("%s: error = %v, want %v", fname, err, tc.wantErr)
}
@ -189,7 +189,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} },
stub.Expect{Calls: slices.Concat(tc.early, []stub.Call{{Name: stub.CallSeparator}}, tc.apply)},
)}
defer k.HandleExit()
defer stub.HandleExit(t)
errEarly := tc.op.early(state, k)
k.Expects(stub.CallSeparator)
if !reflect.DeepEqual(errEarly, tc.wantErrEarly) {

View File

@ -12,20 +12,13 @@ const (
)
// HandleExit must be deferred before calling with the stub.
func (s *Stub[K]) HandleExit() { handleExit(s.TB, true) }
func handleExit(t testing.TB, root bool) {
func HandleExit(t testing.TB) {
switch r := recover(); r {
case PanicExit:
break
case panicFailNow:
if root {
t.FailNow()
} else {
t.Fail()
}
break
t.FailNow()
case panicFatal, panicFatalf, nil:
break
@ -34,3 +27,18 @@ func handleExit(t testing.TB, root bool) {
panic(r)
}
}
// handleExitNew handles exits from goroutines created by [Stub.New].
func handleExitNew(t testing.TB) {
switch r := recover(); r {
case PanicExit, panicFatal, panicFatalf, nil:
break
case panicFailNow:
t.Fail()
break
default:
panic(r)
}
}

View File

@ -7,8 +7,8 @@ import (
"hakurei.app/container/stub"
)
//go:linkname handleExit hakurei.app/container/stub.handleExit
func handleExit(_ testing.TB, _ bool)
//go:linkname handleExitNew hakurei.app/container/stub.handleExitNew
func handleExitNew(_ testing.TB)
// overrideTFailNow overrides the Fail and FailNow method.
type overrideTFailNow struct {
@ -33,7 +33,7 @@ func (o *overrideTFailNow) Fail() {
func TestHandleExit(t *testing.T) {
t.Run("exit", func(t *testing.T) {
defer handleExit(t, true)
defer stub.HandleExit(t)
panic(stub.PanicExit)
})
@ -45,7 +45,7 @@ func TestHandleExit(t *testing.T) {
t.Errorf("FailNow was never called")
}
}()
defer handleExit(ot, true)
defer stub.HandleExit(ot)
panic(0xcafe0000)
})
@ -56,24 +56,38 @@ func TestHandleExit(t *testing.T) {
t.Errorf("Fail was never called")
}
}()
defer handleExit(ot, false)
defer handleExitNew(ot)
panic(0xcafe0000)
})
})
t.Run("nil", func(t *testing.T) {
defer handleExit(t, true)
defer stub.HandleExit(t)
})
t.Run("passthrough", func(t *testing.T) {
defer func() {
want := 0xcafebabe
if r := recover(); r != want {
t.Errorf("recover: %v, want %v", r, want)
}
t.Run("toplevel", func(t *testing.T) {
defer func() {
want := 0xcafebabe
if r := recover(); r != want {
t.Errorf("recover: %v, want %v", r, want)
}
}()
defer handleExit(t, true)
panic(0xcafebabe)
}()
defer stub.HandleExit(t)
panic(0xcafebabe)
})
t.Run("new", func(t *testing.T) {
defer func() {
want := 0xcafe
if r := recover(); r != want {
t.Errorf("recover: %v, want %v", r, want)
}
}()
defer handleExitNew(t)
panic(0xcafe)
})
})
}

View File

@ -68,7 +68,7 @@ func (s *Stub[K]) New(f func(k K)) {
s.Helper()
defer s.wg.Done()
defer handleExit(s.TB, false)
defer handleExitNew(s.TB)
f(s.makeK(ds))
}()
}

View File

@ -118,7 +118,7 @@ func TestStub(t *testing.T) {
{"New", ExpectArgs{}, nil, nil},
{"panic", ExpectArgs{"unreachable"}, nil, nil},
}})
func() { defer s.HandleExit(); s.New(func(k stubHolder) { panic("unreachable") }) }()
func() { defer HandleExit(t); s.New(func(k stubHolder) { panic("unreachable") }) }()
var visit int
s.VisitIncomplete(func(s *Stub[stubHolder]) {
@ -139,7 +139,7 @@ func TestStub(t *testing.T) {
ot := &overrideT{T: t}
ot.error.Store(checkError(t, "Expects: advancing beyond expected calls"))
s := New(ot, func(s *Stub[stubHolder]) stubHolder { return stubHolder{s} }, Expect{})
func() { defer s.HandleExit(); s.Expects("unreachable") }()
func() { defer HandleExit(t); s.Expects("unreachable") }()
})
t.Run("separator", func(t *testing.T) {
@ -149,7 +149,7 @@ func TestStub(t *testing.T) {
s := New(ot, func(s *Stub[stubHolder]) stubHolder { return stubHolder{s} }, Expect{Calls: []Call{
{CallSeparator, ExpectArgs{}, nil, nil},
}})
func() { defer s.HandleExit(); s.Expects("meow") }()
func() { defer HandleExit(t); s.Expects("meow") }()
})
t.Run("mismatch", func(t *testing.T) {
@ -158,7 +158,7 @@ func TestStub(t *testing.T) {
s := New(ot, func(s *Stub[stubHolder]) stubHolder { return stubHolder{s} }, Expect{Calls: []Call{
{"panic", ExpectArgs{}, nil, nil},
}})
func() { defer s.HandleExit(); s.Expects(CallSeparator) }()
func() { defer HandleExit(t); s.Expects(CallSeparator) }()
})
})
@ -168,7 +168,7 @@ func TestStub(t *testing.T) {
s := New(ot, func(s *Stub[stubHolder]) stubHolder { return stubHolder{s} }, Expect{Calls: []Call{
{"nya", ExpectArgs{}, nil, nil},
}})
func() { defer s.HandleExit(); s.Expects("meow") }()
func() { defer HandleExit(t); s.Expects("meow") }()
})
})
})
@ -198,7 +198,7 @@ func TestCheckArg(t *testing.T) {
}
})
t.Run("mismatch", func(t *testing.T) {
defer s.HandleExit()
defer HandleExit(t)
s.Expects("meow")
ot.errorf.Store(checkErrorf(t, "%s: %s = %#v, want %#v (%d)", "meow", "time", 0, -1, 1))
if CheckArg(s, "time", 0, 0) {
@ -241,7 +241,7 @@ func TestCheckArgReflect(t *testing.T) {
}
})
t.Run("mismatch", func(t *testing.T) {
defer s.HandleExit()
defer HandleExit(t)
s.Expects("meow")
ot.errorf.Store(checkErrorf(t, "%s: %s = %#v, want %#v (%d)", "meow", "time", 0, -1, 1))
if CheckArgReflect(s, "time", 0, 0) {

View File

@ -44,7 +44,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
}
sys, s := InternalNew(t, stub.Expect{Calls: slices.Concat(tc.apply, []stub.Call{{Name: stub.CallSeparator}}, tc.revert)}, tc.uid)
defer s.HandleExit()
defer stub.HandleExit(t)
errApply := tc.op.apply(sys)
s.Expects(stub.CallSeparator)
if !reflect.DeepEqual(errApply, tc.wantErrApply) {
@ -91,7 +91,7 @@ func checkOpsBuilder(t *testing.T, fname string, testCases []opsBuilderTestCase)
t.Helper()
sys, s := InternalNew(t, tc.exp, tc.uid)
defer s.HandleExit()
defer stub.HandleExit(t)
tc.f(sys)
s.VisitIncomplete(func(s *stub.Stub[syscallDispatcher]) {
t.Helper()