Recv
func Recv(expectedValue any, timeout ...time.Duration) TestDeep
Recv is a smuggler operator. It reads from a channel or a pointer
to a channel and compares the read value to expectedValue.
expectedValue can be any value including a TestDeep operator. It
can also be RecvNothing to test nothing can be read from the
channel or RecvClosed to check the channel is closed.
If timeout is passed it should be only one item. It means: try to
read the channel during this duration to get a value before giving
up. If timeout is missing or ≤ 0, it defaults to 0 meaning Recv
does not wait for a value but gives up instantly if no value is
available on the channel.
ch := make(chan int, 6)
td.Cmp(t, ch, td.Recv(td.RecvNothing)) // succeeds
td.Cmp(t, ch, td.Recv(42)) // fails, nothing to receive
// recv(DATA): values differ
// got: nothing received on channel
// expected: 42
ch <- 42
td.Cmp(t, ch, td.Recv(td.RecvNothing)) // fails, 42 received instead
// recv(DATA): values differ
// got: 42
// expected: nothing received on channel
td.Cmp(t, ch, td.Recv(42)) // fails, nothing to receive anymore
// recv(DATA): values differ
// got: nothing received on channel
// expected: 42
ch <- 666
td.Cmp(t, ch, td.Recv(td.Between(600, 700))) // succeeds
close(ch)
td.Cmp(t, ch, td.Recv(td.RecvNothing)) // fails as channel is closed
// recv(DATA): values differ
// got: channel is closed
// expected: nothing received on channel
td.Cmp(t, ch, td.Recv(td.RecvClosed)) // succeeds
Note that for convenience Recv accepts pointer on channel:
ch := make(chan int, 6)
ch <- 42
td.Cmp(t, &ch, td.Recv(42)) // succeeds
Each time Recv is called, it tries to consume one item from the
channel, immediately or, if given, before timeout duration. To
consume several items in a same Cmp call, one can use All
operator as in:
ch := make(chan int, 6)
ch <- 1
ch <- 2
ch <- 3
close(ch)
td.Cmp(t, ch, td.All( // succeeds
td.Recv(1),
td.Recv(2),
td.Recv(3),
td.Recv(td.RecvClosed),
))
To check nothing can be received during 100ms on channel ch (if
something is received before, including a close, it fails):
td.Cmp(t, ch, td.Recv(td.RecvNothing, 100*time.Millisecond))
note that in case of success, the above Cmp call always lasts 100ms.
To check 42 can be received from channel ch during the next 100ms
(if nothing is received during these 100ms or something different
from 42, including a close, it fails):
td.Cmp(t, ch, td.Recv(42, 100*time.Millisecond))
note that in case of success, the above Cmp call lasts less than 100ms.
A nil channel is not handled specifically, so it “is never ready
for communication” as specification says:
var ch chan int
td.Cmp(t, ch, td.Recv(td.RecvNothing)) // always succeeds
td.Cmp(t, ch, td.Recv(42)) // or any other value, always fails
td.Cmp(t, ch, td.Recv(td.RecvClosed)) // always fails
so to check if a channel is not nil before reading from it, one can
either do:
td.Cmp(t, ch, td.All(
td.NotNil(),
td.Recv(42),
))
// or
if td.Cmp(t, ch, td.NotNil()) {
td.Cmp(t, ch, td.Recv(42))
}
TypeBehind method returns the reflect.Type of expectedValue,
except if expectedValue is a TestDeep operator. In this case, it
delegates TypeBehind() to the operator.
See also Cap and Len.
See also Recv godoc.
Examples
Basic example
t := &testing.T{}
got := make(chan int, 3)
ok := td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("nothing to receive:", ok)
got <- 1
got <- 2
got <- 3
close(got)
ok = td.Cmp(t, got, td.Recv(1))
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.Cmp(t, got, td.Recv(td.RecvNothing))
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
ChannelPointer example
t := &testing.T{}
got := make(chan int, 3)
ok := td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("nothing to receive:", ok)
got <- 1
got <- 2
got <- 3
close(got)
ok = td.Cmp(t, &got, td.Recv(1))
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.Cmp(t, got, td.Recv(td.RecvNothing))
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
WithTimeout example
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.Cmp(t, got, td.Recv(td.RecvNothing))
// ①
tick <- struct{}{}
ok := td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("① RecvNothing:", ok)
ok = td.Cmp(t, got, td.Recv(0, 150*time.Millisecond))
fmt.Println("① receive 0 w/150ms timeout:", ok)
ok = td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("① RecvNothing:", ok)
// ②
tick <- struct{}{}
ok = td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("② RecvNothing:", ok)
ok = td.Cmp(t, got, td.Recv(1, 150*time.Millisecond))
fmt.Println("② receive 1 w/150ms timeout:", ok)
ok = td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("② RecvNothing:", ok)
// ③
tick <- struct{}{}
ok = td.Cmp(t, got, td.Recv(td.RecvNothing))
fmt.Println("③ RecvNothing:", ok)
ok = td.Cmp(t, got, td.Recv(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
NilChannel example
t := &testing.T{}
var ch chan int
ok := td.Cmp(t, ch, td.Recv(td.RecvNothing))
fmt.Println("nothing to receive from nil channel:", ok)
ok = td.Cmp(t, ch, td.Recv(42))
fmt.Println("something to receive from nil channel:", ok)
ok = td.Cmp(t, ch, td.Recv(td.RecvClosed))
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
CmpRecv shortcut
func CmpRecv(t TestingT, got, expectedValue any, timeout time.Duration, args ...any) bool
CmpRecv is a shortcut for:
td.Cmp(t, got, td.Recv(expectedValue, timeout), args...)
See above 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.
See also CmpRecv godoc.
Examples
Basic example
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
ChannelPointer example
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
WithTimeout example
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
NilChannel example
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
T.Recv shortcut
func (t *T) Recv(got, expectedValue any, timeout time.Duration, args ...any) bool
Recv is a shortcut for:
t.Cmp(got, td.Recv(expectedValue, timeout), args...)
See above 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.
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.
See also T.Recv godoc.
Examples
Basic example
t := td.NewT(&testing.T{})
got := make(chan int, 3)
ok := t.Recv(got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)
got <- 1
got <- 2
got <- 3
close(got)
ok = t.Recv(got, 1, 0)
fmt.Println("1st receive is 1:", ok)
ok = t.Cmp(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 = t.Recv(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
ChannelPointer example
t := td.NewT(&testing.T{})
got := make(chan int, 3)
ok := t.Recv(got, td.RecvNothing, 0)
fmt.Println("nothing to receive:", ok)
got <- 1
got <- 2
got <- 3
close(got)
ok = t.Recv(&got, 1, 0)
fmt.Println("1st receive is 1:", ok)
ok = t.Cmp(&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 = t.Recv(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
WithTimeout example
t := td.NewT(&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)
}()
t.Recv(got, td.RecvNothing, 0)
// ①
tick <- struct{}{}
ok := t.Recv(got, td.RecvNothing, 0)
fmt.Println("① RecvNothing:", ok)
ok = t.Recv(got, 0, 150*time.Millisecond)
fmt.Println("① receive 0 w/150ms timeout:", ok)
ok = t.Recv(got, td.RecvNothing, 0)
fmt.Println("① RecvNothing:", ok)
// ②
tick <- struct{}{}
ok = t.Recv(got, td.RecvNothing, 0)
fmt.Println("② RecvNothing:", ok)
ok = t.Recv(got, 1, 150*time.Millisecond)
fmt.Println("② receive 1 w/150ms timeout:", ok)
ok = t.Recv(got, td.RecvNothing, 0)
fmt.Println("② RecvNothing:", ok)
// ③
tick <- struct{}{}
ok = t.Recv(got, td.RecvNothing, 0)
fmt.Println("③ RecvNothing:", ok)
ok = t.Recv(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
NilChannel example
t := td.NewT(&testing.T{})
var ch chan int
ok := t.Recv(ch, td.RecvNothing, 0)
fmt.Println("nothing to receive from nil channel:", ok)
ok = t.Recv(ch, 42, 0)
fmt.Println("something to receive from nil channel:", ok)
ok = t.Recv(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