Skip to content

Commit

Permalink
feat: add Recv operator, to read from a channel and test the value
Browse files Browse the repository at this point in the history
Signed-off-by: Maxime Soulé <btik-git@scoubidou.com>
  • Loading branch information
maxatome committed Aug 21, 2022
1 parent 143837d commit 31f1fb3
Show file tree
Hide file tree
Showing 15 changed files with 1,027 additions and 14 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ See [FAQ](https://go-testdeep.zetta.rocks/faq/).
[`Ptr`]: https://go-testdeep.zetta.rocks/operators/ptr/
[`Re`]: https://go-testdeep.zetta.rocks/operators/re/
[`ReAll`]: https://go-testdeep.zetta.rocks/operators/reall/
[`Recv`]: https://go-testdeep.zetta.rocks/operators/recv/
[`Set`]: https://go-testdeep.zetta.rocks/operators/set/
[`Shallow`]: https://go-testdeep.zetta.rocks/operators/shallow/
[`Slice`]: https://go-testdeep.zetta.rocks/operators/slice/
Expand Down Expand Up @@ -394,6 +395,7 @@ See [FAQ](https://go-testdeep.zetta.rocks/faq/).
[`CmpPtr`]: https://go-testdeep.zetta.rocks/operators/ptr/#cmpptr-shortcut
[`CmpRe`]: https://go-testdeep.zetta.rocks/operators/re/#cmpre-shortcut
[`CmpReAll`]: https://go-testdeep.zetta.rocks/operators/reall/#cmpreall-shortcut
[`CmpRecv`]: https://go-testdeep.zetta.rocks/operators/recv/#cmprecv-shortcut
[`CmpSet`]: https://go-testdeep.zetta.rocks/operators/set/#cmpset-shortcut
[`CmpShallow`]: https://go-testdeep.zetta.rocks/operators/shallow/#cmpshallow-shortcut
[`CmpSlice`]: https://go-testdeep.zetta.rocks/operators/slice/#cmpslice-shortcut
Expand Down Expand Up @@ -453,6 +455,7 @@ See [FAQ](https://go-testdeep.zetta.rocks/faq/).
[`T.Ptr`]: https://go-testdeep.zetta.rocks/operators/ptr/#tptr-shortcut
[`T.Re`]: https://go-testdeep.zetta.rocks/operators/re/#tre-shortcut
[`T.ReAll`]: https://go-testdeep.zetta.rocks/operators/reall/#treall-shortcut
[`T.Recv`]: https://go-testdeep.zetta.rocks/operators/recv/#trecv-shortcut
[`T.Set`]: https://go-testdeep.zetta.rocks/operators/set/#tset-shortcut
[`T.Shallow`]: https://go-testdeep.zetta.rocks/operators/shallow/#tshallow-shortcut
[`T.Slice`]: https://go-testdeep.zetta.rocks/operators/slice/#tslice-shortcut
Expand Down
19 changes: 19 additions & 0 deletions internal/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,22 @@ func AsOperatorNotJSONMarshallableError(err error) (OperatorNotJSONMarshallableE

return "", false
}

type RecvKind bool

const (
_ RecvKind = (iota & 1) == 0
RecvNothing
RecvClosed
)

func (r RecvKind) _TestDeep() {}

func (r RecvKind) String() string {
if r == RecvNothing {
return "nothing received on channel"
}
return "channel is closed"
}

var _ = []TestDeepStringer{RecvNothing, RecvClosed}
15 changes: 3 additions & 12 deletions internal/types/types_private_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020, Maxime Soulé
// Copyright (c) 2020-2022, Maxime Soulé
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
Expand All @@ -10,19 +10,10 @@ import (
"testing"
)

// Only for coverage...
func TestTypes(t *testing.T) {
s := RawString("foo")
if str := s.String(); str != "foo" {
t.Errorf("Very weird, got %s", str)
}

i := RawInt(42)
if str := i.String(); str != "42" {
t.Errorf("Very weird, got %s", str)
}

// Only for coverage...
(TestDeepStamp{})._TestDeep()
RawString("")._TestDeep()
RawInt(0)._TestDeep()
RecvNothing._TestDeep()
}
28 changes: 27 additions & 1 deletion internal/types/types_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021, Maxime Soulé
// Copyright (c) 2021-2022, Maxime Soulé
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
Expand Down Expand Up @@ -64,3 +64,29 @@ func TestOperatorNotJSONMarshallableError(t *testing.T) {
}
})
}

func TestRawString(t *testing.T) {
s := types.RawString("foo")
if str := s.String(); str != "foo" {
t.Errorf("Very weird, got %s", str)
}
}

func TestRawInt(t *testing.T) {
i := types.RawInt(42)
if str := i.String(); str != "42" {
t.Errorf("Very weird, got %s", str)
}
}

func TestRecvKind(t *testing.T) {
s := types.RecvNothing.String()
if s != "nothing received on channel" {
t.Errorf(`got: %q / expected: "nothing received on channel"`, s)
}

s = types.RecvClosed.String()
if s != "channel is closed" {
t.Errorf(`got: %q / expected: "channel is closed"`, s)
}
}
28 changes: 27 additions & 1 deletion td/cmp_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"time"
)

// allOperators lists the 62 operators.
// allOperators lists the 63 operators.
// nil means not usable in JSON().
var allOperators = map[string]any{
"All": All,
Expand Down Expand Up @@ -57,6 +57,7 @@ var allOperators = map[string]any{
"Ptr": nil,
"Re": Re,
"ReAll": ReAll,
"Recv": nil,
"SStruct": nil,
"Set": Set,
"Shallow": nil,
Expand Down Expand Up @@ -910,6 +911,31 @@ func CmpReAll(t TestingT, got, reg, capture any, args ...any) bool {
return Cmp(t, got, ReAll(reg, capture), args...)
}

// CmpRecv is a shortcut for:
//
// td.Cmp(t, got, td.Recv(expectedValue, timeout), args...)
//
// See [Recv] for details.
//
// [Recv] optional parameter timeout is here mandatory.
// 0 value should be passed to mimic its absence in
// original [Recv] call.
//
// Returns true if the test is OK, false if it fails.
//
// If t is a [*T] then its Config field is inherited.
//
// args... are optional and allow to name the test. This name is
// used in case of failure to qualify the test. If len(args) > 1 and
// the first item of args is a string and contains a '%' rune then
// [fmt.Fprintf] is used to compose the name, else args are passed to
// [fmt.Fprint]. Do not forget it is the name of the test, not the
// reason of a potential failure.
func CmpRecv(t TestingT, got, expectedValue any, timeout time.Duration, args ...any) bool {
t.Helper()
return Cmp(t, got, Recv(expectedValue, timeout), args...)
}

// CmpSet is a shortcut for:
//
// td.Cmp(t, got, td.Set(expectedItems...), args...)
Expand Down
11 changes: 11 additions & 0 deletions td/equal.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,17 @@ func deepValueEqual(ctx ctxerr.Context, got, expected reflect.Value) (err *ctxer

// expected is not a TestDeep operator

if got.Type() == recvKindType || expected.Type() == recvKindType {
if ctx.BooleanError {
return ctxerr.BooleanError
}
return ctx.CollectError(&ctxerr.Error{
Message: "values differ",
Got: got,
Expected: expected,
})
}

if ctx.BeLax && types.IsConvertible(expected, got.Type()) {
return deepValueEqual(ctx, got, expected.Convert(got.Type()))
}
Expand Down
147 changes: 147 additions & 0 deletions td/example_cmp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2232,6 +2232,153 @@ func ExampleCmpReAll_compiledCaptureComplex() {
// false
}

func ExampleCmpRecv_basic() {
t := &testing.T{}

got := make(chan int, 3)

ok := td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)

got <- 1
got <- 2
got <- 3
close(got)

ok = td.CmpRecv(t, got, 1, 0)
fmt.Println("1st receive is 1:", ok)

ok = td.Cmp(t, got, td.All(
td.Recv(2),
td.Recv(td.Between(3, 4)),
td.Recv(td.RecvClosed),
))
fmt.Println("next receives are 2, 3 then closed:", ok)

ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)

// Output:
// nothing to receive: true
// 1st receive is 1: true
// next receives are 2, 3 then closed: true
// nothing to receive: false
}

func ExampleCmpRecv_channelPointer() {
t := &testing.T{}

got := make(chan int, 3)

ok := td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)

got <- 1
got <- 2
got <- 3
close(got)

ok = td.CmpRecv(t, &got, 1, 0)
fmt.Println("1st receive is 1:", ok)

ok = td.Cmp(t, &got, td.All(
td.Recv(2),
td.Recv(td.Between(3, 4)),
td.Recv(td.RecvClosed),
))
fmt.Println("next receives are 2, 3 then closed:", ok)

ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)

// Output:
// nothing to receive: true
// 1st receive is 1: true
// next receives are 2, 3 then closed: true
// nothing to receive: false
}

func ExampleCmpRecv_withTimeout() {
t := &testing.T{}

got := make(chan int, 1)
tick := make(chan struct{})

go func() {
// ①
<-tick
time.Sleep(100 * time.Millisecond)
got <- 0

// ②
<-tick
time.Sleep(100 * time.Millisecond)
got <- 1

// ③
<-tick
time.Sleep(100 * time.Millisecond)
close(got)
}()

td.CmpRecv(t, got, td.RecvNothing, 0)

// ①
tick <- struct{}{}
ok := td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("① RecvNothing:", ok)
ok = td.CmpRecv(t, got, 0, 150*time.Millisecond)
fmt.Println("① receive 0 w/150ms timeout:", ok)
ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("① RecvNothing:", ok)

// ②
tick <- struct{}{}
ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("② RecvNothing:", ok)
ok = td.CmpRecv(t, got, 1, 150*time.Millisecond)
fmt.Println("② receive 1 w/150ms timeout:", ok)
ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("② RecvNothing:", ok)

// ③
tick <- struct{}{}
ok = td.CmpRecv(t, got, td.RecvNothing, 0)
fmt.Println("③ RecvNothing:", ok)
ok = td.CmpRecv(t, got, td.RecvClosed, 150*time.Millisecond)
fmt.Println("③ check closed w/150ms timeout:", ok)

// Output:
// ① RecvNothing: true
// ① receive 0 w/150ms timeout: true
// ① RecvNothing: true
// ② RecvNothing: true
// ② receive 1 w/150ms timeout: true
// ② RecvNothing: true
// ③ RecvNothing: true
// ③ check closed w/150ms timeout: true
}

func ExampleCmpRecv_nilChannel() {
t := &testing.T{}

var ch chan int

ok := td.CmpRecv(t, ch, td.RecvNothing, 0)
fmt.Println("nothing to receive from nil channel:", ok)

ok = td.CmpRecv(t, ch, 42, 0)
fmt.Println("something to receive from nil channel:", ok)

ok = td.CmpRecv(t, ch, td.RecvClosed, 0)
fmt.Println("is a nil channel closed:", ok)

// Output:
// nothing to receive from nil channel: true
// something to receive from nil channel: false
// is a nil channel closed: false
}

func ExampleCmpSet() {
t := &testing.T{}

Expand Down
Loading

0 comments on commit 31f1fb3

Please sign in to comment.