-
Notifications
You must be signed in to change notification settings - Fork 0
/
gomock.go
122 lines (107 loc) · 2.95 KB
/
gomock.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package gotest
import (
"fmt"
"reflect"
"github.com/bouk/monkey"
"github.com/stretchr/testify/mock"
)
type Mock struct {
mock.Mock // mock API Document: https://godoc.org/github.com/stretchr/testify/mock
patch map[reflect.Value]reflect.Value
}
// Patch a value to this Mock.
//
// t.PatchValue(&orm.Debug, true)
func (t *Mock) PatchValue(target, replace interface{}) {
tv := reflect.Indirect(reflect.ValueOf(target))
rv := reflect.Indirect(reflect.ValueOf(replace))
if !tv.CanSet() {
panic("target has to be a prt can set")
}
if t.patch == nil {
t.patch = make(map[reflect.Value]reflect.Value)
}
// only save the oldest
if _, ok := t.patch[tv]; !ok {
// copy and save old value
old := reflect.New(tv.Type()).Elem()
old.Set(tv)
t.patch[tv] = old
}
tv.Set(reflect.Indirect(rv))
}
// Stub a func to this Mock.
//
// t.StubFunc("MyMethod", Func)
func (t *Mock) StubFunc(fnIn, fnOut interface{}) {
monkey.Patch(fnIn, fnOut)
return
}
// StubInstanceMethod a func to this Mock.
//
// var d *net.Dialer
// t.StubInstFunc(d, "Dial", Func)
func (t *Mock) StubInstFunc(target interface{}, methodName string, replacement interface{}) {
monkey.PatchInstanceMethod(reflect.TypeOf(target), methodName, replacement)
return
}
// Mock a func to this Mock.
//
// t.MockFunc("MyMethod", Func)
func (t *Mock) MockFunc(methodName string, fn interface{}) {
if v := reflect.ValueOf(fn); v.Kind() != reflect.Func {
panic(fmt.Sprintf("must be a Func in expectations. fn Type is \"%T\")", fn))
}
ft := reflect.TypeOf(fn)
mfn := reflect.MakeFunc(ft, func(args []reflect.Value) (results []reflect.Value) {
vargs := []interface{}{}
for i := range args {
vargs = append(vargs, args[i].Interface())
}
ret := t.MethodCalled(methodName, vargs...)
for i := 0; i < reflect.TypeOf(fn).NumOut(); i++ {
results = append(results, reflect.ValueOf(ret.Get(i)))
}
return
})
monkey.Patch(fn, mfn.Interface())
return
}
// MockInstFunc a func to this Mock.
//
// var d *net.Dialer
// t.MockInstFunc("MyMethod", d, "Dial")
func (t *Mock) MockInstFunc(methodName string, target interface{}) {
tf := reflect.TypeOf(target)
mtd, ok := tf.MethodByName(methodName)
if !ok {
panic(fmt.Sprintf("must be a Func in expectations. fn Type is \"%T\")", target))
}
ft := mtd.Type
if ft.Kind() != reflect.Func {
panic(fmt.Sprintf("must be a Func in expectations. fn Type is \"%T\")", ft))
}
mfn := reflect.MakeFunc(mtd.Type, func(args []reflect.Value) (results []reflect.Value) {
vargs := []interface{}{}
for i := range args {
vargs = append(vargs, args[i].Interface())
}
ret := t.MethodCalled(methodName, vargs...)
for i := 0; i < ft.NumOut(); i++ {
results = append(results, reflect.ValueOf(ret.Get(i)))
}
return
})
monkey.PatchInstanceMethod(tf, methodName, mfn.Interface())
return
}
// Call at the end of this Mock.
//
// t.Close()
func (t *Mock) Close() {
monkey.UnpatchAll()
for v, it := range t.patch {
v.Set(it)
}
return
}