forked from beego/beego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mock.go
142 lines (135 loc) · 3.57 KB
/
mock.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package bean
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// the mock object must be pointer of struct
// the element in mock object can be slices, structures, basic data types, pointers and interface
func Mock(v interface{}) (err error) {
pv := reflect.ValueOf(v)
// the input must be pointer of struct
if pv.Kind() != reflect.Ptr || pv.IsNil() {
err = fmt.Errorf("not a pointer of struct")
return
}
err = mock(pv)
return
}
func mock(pv reflect.Value) (err error) {
pt := pv.Type()
for i := 0; i < pt.Elem().NumField(); i++ {
ptt := pt.Elem().Field(i)
pvv := pv.Elem().FieldByName(ptt.Name)
if !pvv.CanSet() {
continue
}
kt := ptt.Type.Kind()
tagValue := ptt.Tag.Get("mock")
switch kt {
case reflect.Map:
continue
case reflect.Interface:
if pvv.IsNil() { // when interface is nil,can not sure the type
continue
}
pvv.Set(reflect.New(pvv.Elem().Type().Elem()))
err = mock(pvv.Elem())
case reflect.Ptr:
err = mockPtr(pvv, ptt.Type.Elem())
case reflect.Struct:
err = mock(pvv.Addr())
case reflect.Array, reflect.Slice:
err = mockSlice(tagValue, pvv)
case reflect.String:
pvv.SetString(tagValue)
case reflect.Bool:
err = mockBool(tagValue, pvv)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value, e := strconv.ParseInt(tagValue, 10, 64)
if e != nil || pvv.OverflowInt(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetInt(value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
value, e := strconv.ParseUint(tagValue, 10, 64)
if e != nil || pvv.OverflowUint(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetUint(value)
case reflect.Float32, reflect.Float64:
value, e := strconv.ParseFloat(tagValue, pvv.Type().Bits())
if e != nil || pvv.OverflowFloat(value) {
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
pvv.SetFloat(value)
default:
}
if err != nil {
return
}
}
return
}
// mock slice value
func mockSlice(tagValue string, pvv reflect.Value) (err error) {
if tagValue == "" {
return
}
sliceMetas := strings.Split(tagValue, ":")
if len(sliceMetas) != 2 || sliceMetas[0] != "length" {
err = fmt.Errorf("the value:%s is invalid", tagValue)
return
}
length, e := strconv.Atoi(sliceMetas[1])
if e != nil {
return e
}
sliceType := reflect.SliceOf(pvv.Type().Elem()) // get slice type
itemType := sliceType.Elem() // get the type of item in slice
value := reflect.MakeSlice(sliceType, 0, length)
newSliceValue := make([]reflect.Value, 0, length)
for k := 0; k < length; k++ {
itemValue := reflect.New(itemType).Elem()
// if item in slice is struct or pointer,must set zero value
switch itemType.Kind() {
case reflect.Struct:
err = mock(itemValue.Addr())
case reflect.Ptr:
if itemValue.IsNil() {
itemValue.Set(reflect.New(itemType.Elem()))
if e := mock(itemValue); e != nil {
return e
}
}
}
newSliceValue = append(newSliceValue, itemValue)
if err != nil {
return
}
}
value = reflect.Append(value, newSliceValue...)
pvv.Set(value)
return
}
// mock bool value
func mockBool(tagValue string, pvv reflect.Value) (err error) {
switch tagValue {
case "true":
pvv.SetBool(true)
case "false":
pvv.SetBool(false)
default:
err = fmt.Errorf("the value:%s is invalid", tagValue)
}
return
}
// mock pointer
func mockPtr(pvv reflect.Value, ptt reflect.Type) (err error) {
if pvv.IsNil() {
pvv.Set(reflect.New(ptt)) // must set nil value to zero value
}
err = mock(pvv)
return
}