Skip to content

Commit

Permalink
feat: update deps, renaming, small improvements (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkrop committed Jan 18, 2023
1 parent d8a9ae3 commit 6008a3f
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 26 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ jobs:
- name: Build and tests
run: make cdp

# - name: Upload coverage
# run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report --force-coverage-parser go -r build/test-all.cover

- name: Send coverage
uses: shogo82148/actions-goveralls@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<!--[![Security](https://img.shields.io/snyk/vulnerabilities/github/tkrop/go-testing/go.mod)](https://snyk.io/github/tkrop/go-testing)-->
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![FOSSA](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftkrop%2Ftesting.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftkrop%2Ftesting?ref=badge_shield)
[![Report](https://goreportcard.com/badge/github.com/tkrop/go-testing)](https://goreportcard.com/badge/github.com/tkrop/go-testing)
[![Report](https://goreportcard.com/badge/github.com/tkrop/go-testing)](https://goreportcard.com/report/github.com/tkrop/go-testing)
[![Docs](https://pkg.go.dev/badge/github.com/tkrop/go-testing.svg)](https://pkg.go.dev/github.com/tkrop/go-testing)


Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.19
require (
github.com/golang/mock v1.6.0
github.com/stretchr/testify v1.8.1
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30
golang.org/x/exp v0.0.0-20230116083435-1de6713980de
golang.org/x/text v0.3.3
gopkg.in/h2non/gock.v1 v1.1.2
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230116083435-1de6713980de h1:DBWn//IJw30uYCgERoxCg84hWtA97F4wMiKOIh00Uf0=
golang.org/x/exp v0.0.0-20230116083435-1de6713980de/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand Down
4 changes: 2 additions & 2 deletions internal/math/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestMin(t *testing.T) {
test.Map(t, testMinParams).
Run(func(t test.Test, param MinMaxParams) {
// Given
mock.NewMock(t).Expect(param.setup)
mock.NewMocks(t).Expect(param.setup)

// When
result := math.Min(param.values...)
Expand Down Expand Up @@ -79,7 +79,7 @@ func TestMax(t *testing.T) {
test.Map(t, testMaxParams).
Run(func(t test.Test, param MinMaxParams) {
// Given
mock.NewMock(t).Expect(param.setup)
mock.NewMocks(t).Expect(param.setup)

// When
result := math.Max(param.values...)
Expand Down
4 changes: 2 additions & 2 deletions internal/reflect/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func TestValuesIn(t *testing.T) {
test.Map(t, testValuesInParams).
Run(func(t test.Test, param ValuesParams) {
// Given
mock.NewMock(t).Expect(param.setup)
mock.NewMocks(t).Expect(param.setup)
ftype := reflect.TypeOf(param.call)

// When
Expand Down Expand Up @@ -583,7 +583,7 @@ func TestValuesOut(t *testing.T) {
test.Map(t, testValuesOutParams).
Run(func(t test.Test, param ValuesParams) {
// Given
mock.NewMock(t).Expect(param.setup)
mock.NewMocks(t).Expect(param.setup)
ftype := reflect.TypeOf(param.call)

// When
Expand Down
63 changes: 53 additions & 10 deletions mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,29 @@ type Mocks struct {
mocks map[reflect.Type]any
}

// NewMock creates a new mock handler using given test reporter (`*testing.T`).
func NewMock(t gomock.TestReporter) *Mocks {
// NewMocks creates a new mock handler using given test reporter (`*testing.T`).
func NewMocks(t gomock.TestReporter) *Mocks {
return (&Mocks{
ctrl: gomock.NewController(t),
wg: sync.NewLenientWaitGroup(),
mocks: map[reflect.Type]any{},
}).syncWith(t)
}

// Get resolves the singleton mock from the mock handler by providing the
// constructor function generated by `gomock` to create a new mock. The mock
// is only created once and stored in an internal creator to mock map.
func (mocks *Mocks) Get(creator func(*Controller) any) any {
ctype := reflect.TypeOf(creator)
mock, ok := mocks.mocks[ctype]
if ok && mock != nil {
return mock
}
mock = creator(mocks.ctrl)
mocks.mocks[ctype] = mock
return mock
}

// Expect configures the mock handler to expect the given mock function calls.
func (mocks *Mocks) Expect(fncalls SetupFunc) *Mocks {
if fncalls != nil {
Expand Down Expand Up @@ -145,6 +159,7 @@ func (mocks *Mocks) Wait() {
//
// Times is creating the expectation that exactly the given number of mock call
// are consumed. This call is best provided as input for `Times`.
//
// func (mocks *Mocks) Times(num int) int {
// mocks.wg.Add(num - 1)
// return num
Expand Down Expand Up @@ -191,6 +206,30 @@ func (mocks *Mocks) notify(
return notify
}

// TODO: continue or delete!!
// Redirecting this call is destroying the caller information captured by
// controller with a fixed stack hight of 3 calls. Can we do a tail call
// removing the added stack level?
// func (mocks *Mocks) Call(mock any, method string, args ...any) []any {
// mocks.ctrl.T.Helper()
// defer mocks.wg.Done()
// return mocks.ctrl.Call(mock, method, args)
// }

// func (mocks *Mocks) RecordCall(mock any, method string, args ...any) *Call {
// mocks.ctrl.T.Helper()
// defer mocks.wg.Add(1)
// return mocks.ctrl.RecordCall(mock, method, args)
// }

// func (mocks *Mocks) RecordCallWithMethodType(
// mock any, method string, mtype reflect.Type, args ...any,
// ) *Call {
// mocks.ctrl.T.Helper()
// defer mocks.wg.Add(1)
// return mocks.ctrl.RecordCallWithMethodType(mock, method, mtype, args)
// }

// TODO: Reconsider approach - complex signature. Test setup look as follows:
//
// func CallBX(input string, output string) mock.SetupFunc {
Expand Down Expand Up @@ -221,16 +260,20 @@ func (mocks *Mocks) notify(
// Get resolves the actual mock from the mock handler by providing the
// constructor function generated by `gomock` to create a new mock.
func Get[T any](mocks *Mocks, creator func(*Controller) *T) *T {
ctype := reflect.TypeOf(creator)
mock, ok := mocks.mocks[ctype]
if ok && mock != nil {
return mock.(*T)
}
mock = creator(mocks.ctrl)
mocks.mocks[ctype] = mock
return mock.(*T)
return mocks.Get(func(ctrl *Controller) any {
return creator(ctrl)
}).(*T)
}

// TODO: decide on strategy mock strategy.
//
// Expect resolves the mock recorder from the mock handler by providing the
// constructor function generated by `gomock`.
// func Expect[T any](mocks *Mocks, creator func(*Controller) any) T {
// return reflect.ValueOf(mocks.Get(creator)).
// MethodByName("EXPECT").Call(nil)[0].Interface().(T)
// }

// Setup creates only a lazily ordered set of mock calls that is detached from
// the parent setup by returning no calls for chaining. The mock calls created
// by the setup are only validated in so far in relation to each other, that
Expand Down
4 changes: 2 additions & 2 deletions mock/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func NoCall() mock.SetupFunc {
}

func MockSetup(t gomock.TestReporter, mockSetup mock.SetupFunc) *mock.Mocks {
return mock.NewMock(t).Expect(mockSetup)
return mock.NewMocks(t).Expect(mockSetup)
}

func MockValidate(
Expand Down Expand Up @@ -612,7 +612,7 @@ func TestFailures(t *testing.T) {
test.Map(t, testFailureParams).
Run(func(t test.Test, param FailureParam) {
// Given
mocks := mock.NewMock(t).Expect(CallA("a"))
mocks := mock.NewMocks(t).Expect(CallA("a"))
defer func() {
if err := recover(); err != nil && err != "panic" {
// Test thread will not wait on failures.
Expand Down
2 changes: 1 addition & 1 deletion perm/perm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func SetupPermTestABCDEF(mocks *mock.Mocks) *perm.Test {
}

func MockSetup(t gomock.TestReporter, mockSetup mock.SetupFunc) *mock.Mocks {
return mock.NewMock(t).Expect(mockSetup)
return mock.NewMocks(t).Expect(mockSetup)
}

var testPermTestParams = perm.ExpectMap{
Expand Down
2 changes: 1 addition & 1 deletion test/caller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (c *Caller) Panic(arg any) {
// number for the given call.
func getCaller(call func(t test.Reporter)) string {
t := test.NewTester(&testing.T{}, test.Failure)
mocks := mock.NewMock(t)
mocks := mock.NewMocks(t)
caller := mock.Get(mocks,
func(ctrl *gomock.Controller) *Caller {
return &Caller{}
Expand Down
43 changes: 42 additions & 1 deletion test/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"fmt"
"math"
"runtime"
"runtime/debug"
"strings"
gosync "sync"
"sync/atomic"
"testing"
Expand Down Expand Up @@ -40,6 +42,41 @@ const (
Parallel = true
)

// TODO: consider following convenience mehtods:
//
// // Result is a convenience method that returns the first argument ans swollows
// // all others assuming that the first argument contains the important result to
// // focus the test at.
// func Result[T any](result T, swollowed any) T {
// return result
// }

// // Check is a convenience method that returns the second argument and swollows
// // the first used to focus a test on the second.
// func Check[T any](swollowed any, check T) T {
// return check
// }

// // NoError is a convenience method to check whether the second error argument
// // is providing and actual error while extracting the first argument only. If
// // the error argument is an error, the method panics providing the error.
// func NoError[T any](result T, err error) T {
// if err != nil {
// panic(err)
// }
// return result
// }

// // Ok is a conveninence method to check whether the second boolean argument is
// // `true` while returning the first argument. If the boolean argument is
// // `false`, the method panics.
// func Ok[T any](result T, ok bool) T {
// if !ok {
// panic("bool not okay")
// }
// return result
// }

// Reporter is a minimal inferface for abstracting test report methods that are
// needed to setup an isolated test environment for GoMock and Testify.
type Reporter interface {
Expand Down Expand Up @@ -176,7 +213,8 @@ func (t *Tester) Panic(arg any) {
t.failed.Store(true)
defer t.unlock()
if t.expect == Success {
t.Fatalf("panic: %v", arg)
stack := strings.SplitN(string(debug.Stack()), "\n", 10)
t.Fatalf("panic: %v\n%s\n%s", arg, stack[0], stack[9])
} else if t.reporter != nil {
t.reporter.Panic(arg)
}
Expand All @@ -200,6 +238,7 @@ func (t *Tester) Run(test func(Test), parallel bool) Test {
wg := sync.NewWaitGroup()
wg.Add(1)
go func() {
t.Helper()
defer wg.Done()
defer t.recover()
test(t)
Expand Down Expand Up @@ -366,6 +405,8 @@ func (r *runner[P]) wrap(
name string, param P, call func(t Test, param P), parallel bool,
) func(*testing.T) {
return run(r.expect(param), func(t Test) {
t.Helper()

// Helpful for debugging to see the test case.
require.NotEmpty(t, name)

Expand Down
6 changes: 3 additions & 3 deletions test/testing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ var testFailureParams = map[string]TestParam{
func testFailures(t test.Test, param TestParam) {
// Given
if param.setup != nil {
mock.NewMock(t).Expect(param.setup)
mock.NewMocks(t).Expect(param.setup)
}

wg := sync.NewLenientWaitGroup()
Expand Down Expand Up @@ -295,14 +295,14 @@ func TestValidate(t *testing.T) {
test.Map(t, testValidateParams).
Run(func(t test.Test, param ValidateParams) {
// Given
mocks := mock.NewMock(t)
mocks := mock.NewMocks(t)

// When
test.InRun(test.Failure, func(t test.Test) {
// Given
mocks.Expect(test.Fatalf(
"Unexpected call to %T.%v(%v) at %s because: %s",
mock.Get(mock.NewMock(t), test.NewValidator),
mock.Get(mock.NewMocks(t), test.NewValidator),
param.method, param.args, param.caller,
errors.New("there are no expected calls of the "+
"method \""+param.method+"\" for that receiver")))
Expand Down

0 comments on commit 6008a3f

Please sign in to comment.