-
Notifications
You must be signed in to change notification settings - Fork 8
/
receive.go
61 lines (53 loc) · 1.48 KB
/
receive.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package matchers
import (
"fmt"
"reflect"
"time"
)
// ReceiveOpt is an option that can be passed to the
// ReceiveMatcher constructor.
type ReceiveOpt func(ReceiveMatcher) ReceiveMatcher
// ReceiveWait is an option that makes the ReceiveMatcher
// wait for values for the provided duration before
// deciding that the channel failed to receive.
func ReceiveWait(t time.Duration) ReceiveOpt {
return func(m ReceiveMatcher) ReceiveMatcher {
m.timeout = t
return m
}
}
// ReceiveMatcher only accepts a readable channel. It will error for anything else.
// It will attempt to receive from the channel but will not block.
// It fails if the channel is closed.
type ReceiveMatcher struct {
timeout time.Duration
}
// Receive will return a ReceiveMatcher
func Receive(opts ...ReceiveOpt) ReceiveMatcher {
var m ReceiveMatcher
for _, opt := range opts {
m = opt(m)
}
return m
}
func (m ReceiveMatcher) Match(actual any) (any, error) {
t := reflect.TypeOf(actual)
if t.Kind() != reflect.Chan || t.ChanDir() == reflect.SendDir {
return nil, fmt.Errorf("%s is not a readable channel", t.String())
}
timeout := reflect.SelectCase{
Dir: reflect.SelectDefault,
}
if m.timeout != 0 {
timeout.Dir = reflect.SelectRecv
timeout.Chan = reflect.ValueOf(time.After(m.timeout))
}
i, v, ok := reflect.Select([]reflect.SelectCase{
{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(actual)},
timeout,
})
if i == 1 || !ok {
return nil, fmt.Errorf("did not receive")
}
return v.Interface(), nil
}