Skip to content

Commit

Permalink
Handle Fail calls on the TestingT in the right place
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsheepuk committed Jan 10, 2024
1 parent 1c5335a commit 1d2f5b4
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 29 deletions.
19 changes: 5 additions & 14 deletions suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ func (s *suite) runStep(ctx context.Context, pickle *Scenario, step *Step, scena

earlyReturn := scenarioErr != nil || errors.Is(err, ErrUndefined)

// Check for any calls to Fail on dogT
if err == nil {
err = getDogTestingT(ctx).isFailed()
}

switch {
case errors.Is(err, ErrPending):
sr.Status = StepPending
Expand Down Expand Up @@ -537,18 +542,12 @@ func (s *suite) runPickle(pickle *messages.Pickle) (err error) {
s.testingT.Run(pickle.Name, func(t *testing.T) {
dt.t = t
ctx, err = s.runSteps(ctx, pickle, pickle.Steps)
if err == nil {
err = dt.check()
}
if s.shouldFail(err) {
t.Errorf("%+v", err)
}
})
} else {
ctx, err = s.runSteps(ctx, pickle, pickle.Steps)
if err == nil {
err = dt.check()
}
}

// After scenario handlers are called in context of last evaluated step
Expand All @@ -557,14 +556,6 @@ func (s *suite) runPickle(pickle *messages.Pickle) (err error) {
return err
}

type TestingT interface {
Log(args ...interface{})
Logf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Fail()
FailNow()
}

// Logf will log test output. If called in the context of a test and testing.T has been registered,
// this will log using the step's testing.T, else it will simply log to stdout.
func Logf(ctx context.Context, format string, args ...interface{}) {
Expand Down
50 changes: 35 additions & 15 deletions testingt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,33 @@ package godog
import (
"context"
"fmt"
"strings"
"testing"
)

type TestingT interface {
Log(args ...interface{})
Logf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Fail()
FailNow()
}

// GetTestingT returns a TestingT compatible interface from the current test context. It will return
// nil if called outside the context of a test. This can be used with (for example) testify's assert
// and require packages.
func GetTestingT(ctx context.Context) TestingT {
return getDogTestingT(ctx)
}

// errFailNow should be returned inside a panic within the test to immediately halt execution of that
// test
var errFailNow = fmt.Errorf("FailNow called")

type dogTestingT struct {
t *testing.T
failed bool
t *testing.T
failed bool
failMessages []string
}

// check interface:
Expand All @@ -36,41 +53,44 @@ func (dt *dogTestingT) Logf(format string, args ...interface{}) {

func (dt *dogTestingT) Errorf(format string, args ...interface{}) {
dt.Logf(format, args...)
dt.failed = true
dt.failMessages = append(dt.failMessages, fmt.Sprintf(format, args...))
dt.Fail()
}

func (dt *dogTestingT) Fail() {
dt.failed = true
}

func (dt *dogTestingT) FailNow() {
dt.Fail()
panic(errFailNow)
}

func (dt *dogTestingT) check() error {
if dt.failed {
return fmt.Errorf("one or more checks failed")
// isFailed will return an error representing the calls to Fail made during this test
func (dt *dogTestingT) isFailed() error {
if !dt.failed {
return nil
}
switch len(dt.failMessages) {
case 0:
return fmt.Errorf("fail called on TestingT")
case 1:
return fmt.Errorf(dt.failMessages[0])
default:
return fmt.Errorf("checks failed:\n* %s", strings.Join(dt.failMessages, "\n* "))
}

return nil
}

type testingTCtxVal struct{}

func setContextDogTester(ctx context.Context, dt *dogTestingT) context.Context {
return context.WithValue(ctx, testingTCtxVal{}, dt)
}

func getDogTestingT(ctx context.Context) *dogTestingT {
dt, ok := ctx.Value(testingTCtxVal{}).(*dogTestingT)
if !ok {
return nil
}
return dt
}

// GetTestingT returns a TestingT compatible interface from the current test context. It will return
// nil if called outside the context of a test. This can be used with (for example) testify's assert
// and require packages.
func GetTestingT(ctx context.Context) TestingT {
return getDogTestingT(ctx)
}

0 comments on commit 1d2f5b4

Please sign in to comment.