-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.go
167 lines (135 loc) · 3.14 KB
/
utils.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package utils
import (
"bytes"
"crypto/rand"
"encoding/hex"
"encoding/json"
"reflect"
"sync"
"text/template"
"github.com/tidwall/gjson"
)
// JSONResult shortcut for gjson.Result
type JSONResult = *gjson.Result
// Nil used to create empty channel
type Nil struct{}
// Noop swallow all args and do nothing
func Noop(_ ...interface{}) {}
// ErrArg get the last arg as error
func ErrArg(args ...interface{}) error {
return args[len(args)-1].(error)
}
// E the last arg is error, panic it
func E(args ...interface{}) []interface{} {
err, ok := args[len(args)-1].(error)
if ok {
panic(err)
}
return args
}
// E1 if the second arg is error panic it, or return the first arg
func E1(arg interface{}, err error) interface{} {
if err != nil {
panic(err)
}
return arg
}
// ErrInjector let you easily mock error for testing
type ErrInjector struct {
fn func(error) error
}
// CountInject inject err after E is called with specified times
func (e *ErrInjector) CountInject(times int, err error) {
count := 1
e.Inject(func(origin error) error {
if count == times {
e.Inject(nil)
return err
}
count++
return origin
})
}
// Inject the fn and enable the enjection, call it with nil to disable injection
func (e *ErrInjector) Inject(fn func(error) error) {
e.fn = fn
}
// E inject error
func (e *ErrInjector) E(err error) error {
if e.fn == nil {
return err
}
return e.fn(err)
}
// MustToJSONBytes encode data to json bytes
func MustToJSONBytes(data interface{}) []byte {
bytes, err := json.Marshal(data)
E(err)
return bytes
}
// MustToJSON encode data to json string
func MustToJSON(data interface{}) string {
return string(MustToJSONBytes(data))
}
// JSON parse json for easily access the value from json path
func JSON(data interface{}) JSONResult {
var res gjson.Result
switch v := data.(type) {
case string:
res = gjson.Parse(v)
case []byte:
res = gjson.ParseBytes(v)
}
return &res
}
// All run all actions concurrently, returns the wait function for all actions.
func All(actions ...func()) func() {
wg := &sync.WaitGroup{}
wg.Add(len(actions))
runner := func(action func()) {
defer wg.Done()
action()
}
for _, action := range actions {
go runner(action)
}
return wg.Wait
}
// RandBytes generate random bytes with specified byte length
func RandBytes(len int) []byte {
b := make([]byte, len)
_, _ = rand.Read(b)
return b
}
// RandString generate random string with specified string length
func RandString(len int) string {
b := RandBytes(len)
return hex.EncodeToString(b)
}
// Try try fn with recover, return the panic as value
func Try(fn func()) (err interface{}) {
defer func() {
err = recover()
}()
fn()
return err
}
// S Template render, the params is key-value pairs
func S(tpl string, params ...interface{}) string {
var out bytes.Buffer
dict := map[string]interface{}{}
fnDict := template.FuncMap{}
l := len(params)
for i := 0; i < l-1; i += 2 {
k := params[i].(string)
v := params[i+1]
if reflect.TypeOf(v).Kind() == reflect.Func {
fnDict[k] = v
} else {
dict[k] = v
}
}
t := template.Must(template.New("").Funcs(fnDict).Parse(tpl))
E(t.Execute(&out, dict))
return out.String()
}