From 281b8991d9c3c78f33c4e696037e9d4fe463f4a8 Mon Sep 17 00:00:00 2001 From: Adam Luzsi Date: Mon, 1 Jul 2024 21:44:40 +0200 Subject: [PATCH] fix panics due to doc with spec suite mode --- Spec.go | 28 ++++++++++++++++++++++------ Spec_test.go | 25 +++++++++++++++++++++++++ internal/suite.go | 38 +++++++++++++++++++------------------- ordering.go | 9 +++------ ordering_test.go | 2 +- seed.go | 12 ++++++++++-- 6 files changed, 80 insertions(+), 34 deletions(-) diff --git a/Spec.go b/Spec.go index b3758e1..18ee2fa 100644 --- a/Spec.go +++ b/Spec.go @@ -18,8 +18,8 @@ import ( // NewSpec create new Spec struct that is ready for usage. func NewSpec(tb testing.TB, opts ...SpecOption) *Spec { + h(tb).Helper() tb, opts = checkSuite(tb, opts) - tb.Helper() var s *Spec switch tb := tb.(type) { case *T: @@ -27,21 +27,24 @@ func NewSpec(tb testing.TB, opts ...SpecOption) *Spec { default: s = newSpec(tb, opts...) s.seed = seedForSpec(tb) - s.orderer = newOrderer(tb, s.seed) + s.orderer = newOrderer(s.seed) s.sync = true } applyGlobal(s) - tb.Cleanup(s.documentResults) + if isValidTestingTB(tb) { + tb.Cleanup(s.documentResults) + } return s } func newSpec(tb testing.TB, opts ...SpecOption) *Spec { - tb.Helper() + h(tb).Helper() s := &Spec{ testingTB: tb, opts: opts, vars: newVariables(), immutable: false, + isSuite: tb == nil, } s.doc.maker = doc.DocumentFormat{} for _, to := range opts { @@ -596,10 +599,16 @@ func (spec *Spec) Finish() { } func (spec *Spec) documentResults() { - spec.testingTB.Helper() + if spec.testingTB == nil { + return + } if spec.parent != nil { return } + if spec.isSuite || spec.isBenchmark { + return + } + spec.testingTB.Helper() spec.doc.once.Do(func() { var collect func(*Spec) []doc.TestingCase collect = func(spec *Spec) []doc.TestingCase { @@ -783,7 +792,7 @@ func (spec *Spec) hasTestRan() bool { func checkSuite(tb testing.TB, opts []SpecOption) (testing.TB, []SpecOption) { if tb == nil { - return internal.SuiteNullTB{}, append(opts, specOptionFunc(func(s *Spec) { + return internal.NullTB{}, append(opts, specOptionFunc(func(s *Spec) { s.isSuite = true })) } @@ -810,3 +819,10 @@ func (suite SpecSuite) run(tb testing.TB) { defer s.Finish() s.Context(suite.N, suite.Spec, Group(suite.N)) } + +func h(tb helper) helper { + if tb == nil { + return internal.NullTB{} + } + return tb +} diff --git a/Spec_test.go b/Spec_test.go index 2146f69..8471adb 100644 --- a/Spec_test.go +++ b/Spec_test.go @@ -1688,3 +1688,28 @@ func BenchmarkTestSpec_Benchmark(b *testing.B) { b.Skip("done") }) } + +func TestSpecSuite(t *testing.T) { + var ran int + spec := testcase.NewSpec(nil) + spec.Describe("#Foo", func(spec *testcase.Spec) { + spec.Test("x", func(t *testcase.T) { ran++ }) + }) + suite := spec.AsSuite("the-suite") + + t.Run("#Test", func(t *testing.T) { + ir := ran + suite.Test(t) + assert.Equal(t, ran, ir+1) + }) + + t.Run("#Spec", func(t *testing.T) { + ir := ran + + s := testcase.NewSpec(t) + s.Describe("", suite.Spec) + s.Finish() + + assert.Equal(t, ran, ir+1) + }) +} diff --git a/internal/suite.go b/internal/suite.go index bdc5db5..fdef5ee 100644 --- a/internal/suite.go +++ b/internal/suite.go @@ -4,91 +4,91 @@ import ( "testing" ) -type SuiteNullTB struct{ testing.TB } +type NullTB struct{ testing.TB } -func (n SuiteNullTB) Helper() {} +func (n NullTB) Helper() {} -func (n SuiteNullTB) Cleanup(f func()) { +func (n NullTB) Cleanup(f func()) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Error(args ...any) { +func (n NullTB) Error(args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Errorf(format string, args ...any) { +func (n NullTB) Errorf(format string, args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Fail() { +func (n NullTB) Fail() { //TODO implement me panic("implement me") } -func (n SuiteNullTB) FailNow() { +func (n NullTB) FailNow() { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Failed() bool { +func (n NullTB) Failed() bool { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Fatal(args ...any) { +func (n NullTB) Fatal(args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Fatalf(format string, args ...any) { +func (n NullTB) Fatalf(format string, args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Log(args ...any) { +func (n NullTB) Log(args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Logf(format string, args ...any) { +func (n NullTB) Logf(format string, args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Name() string { +func (n NullTB) Name() string { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Setenv(key, value string) { +func (n NullTB) Setenv(key, value string) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Skip(args ...any) { +func (n NullTB) Skip(args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) SkipNow() { +func (n NullTB) SkipNow() { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Skipf(format string, args ...any) { +func (n NullTB) Skipf(format string, args ...any) { //TODO implement me panic("implement me") } -func (n SuiteNullTB) Skipped() bool { +func (n NullTB) Skipped() bool { //TODO implement me panic("implement me") } -func (n SuiteNullTB) TempDir() string { +func (n NullTB) TempDir() string { //TODO implement me panic("implement me") } diff --git a/ordering.go b/ordering.go index 02661e5..8b71a45 100644 --- a/ordering.go +++ b/ordering.go @@ -5,15 +5,13 @@ import ( "math/rand" "os" "sync" - "testing" "go.llib.dev/testcase/internal" "go.llib.dev/testcase/internal/environ" ) -func newOrderer(tb testing.TB, seed int64) orderer { - tb.Helper() - switch mod := getGlobalOrderMod(tb); mod { +func newOrderer(seed int64) orderer { + switch mod := getGlobalOrderMod(); mod { case OrderingAsDefined: return nullOrderer{} case OrderingAsRandom, undefinedOrdering: @@ -71,8 +69,7 @@ var ( }) ) -func getGlobalOrderMod(tb testing.TB) testOrderingMod { - tb.Helper() +func getGlobalOrderMod() testOrderingMod { globalOrderModInit.Do(func() { globalOrderMod = getOrderingModFromENV() }) return globalOrderMod } diff --git a/ordering_test.go b/ordering_test.go index 168b64e..31bd604 100644 --- a/ordering_test.go +++ b/ordering_test.go @@ -172,7 +172,7 @@ func TestNewOrderer(t *testing.T) { return int64(t.Random.Int()) }) subject := func(t *T) orderer { - return newOrderer(t, seed.Get(t)) + return newOrderer(seed.Get(t)) } s.Before(func(t *T) { diff --git a/seed.go b/seed.go index 85857b1..2f5ee88 100644 --- a/seed.go +++ b/seed.go @@ -29,8 +29,8 @@ func makeSeed() (int64, error) { } func seedForSpec(tb testing.TB) (_seed int64) { - tb.Helper() - if tb != (internal.SuiteNullTB{}) { + h(tb).Helper() + if isValidTestingTB(tb) { tb.Cleanup(func() { tb.Helper() if tb.Failed() { @@ -45,3 +45,11 @@ func seedForSpec(tb testing.TB) (_seed int64) { } return seed } + +func isValidTestingTB(tb testing.TB) bool { + if tb == nil { + return false + } + _, ok := tb.(internal.NullTB) + return !ok +}