-
Notifications
You must be signed in to change notification settings - Fork 1
/
README.md.j2
221 lines (167 loc) · 7.84 KB
/
README.md.j2
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# must
`must` is a "design by contract" implementation in golang,
for addressing silent bug that is caused by unexpected input etc.
"Design by contract" requires that some conditions **MUST** be satisfied for the input of a
function, thus the function does not need to do a lot check on arguments.
It is the responsibility of `must` to enable these checking in a test env and to
disable them in production env(for performance concern).
[![Travis-CI](https://api.travis-ci.org/openacid/must.svg?branch=master)](https://travis-ci.org/openacid/must)
[![GoDoc](https://godoc.org/github.com/openacid/must?status.svg)](http://godoc.org/github.com/openacid/must)
[![Report card](https://goreportcard.com/badge/github.com/openacid/must)](https://goreportcard.com/report/github.com/openacid/must)
[![GolangCI](https://golangci.com/badges/github.com/openacid/must.svg)](https://golangci.com/r/github.com/openacid/must)
[![Sourcegraph](https://sourcegraph.com/github.com/openacid/must/-/badge.svg)](https://sourcegraph.com/github.com/openacid/must?badge)
![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [must](#must)
- [Usage](#usage)
- [API](#api)
- [Examples](#examples)
- [Install](#install)
- [Customize tags](#customize-tags)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Usage
To enable expectation check in test environment, use `go build|test -tags debug`.
To disable it for a release, just `go build`.
```go
{% include 'examples/rshift/composite/main.go' %}
```
With the above code:
**Enable check** with `go run -tags debug .`.
It would panic because `a` does not satisfy the input
expectation:
```
panic:
...
Error: Should be true
Messages: a must be multiple of 8
```
**Disable check** with `go run .`
It just silently ignores the expectation and print the result:
```
7
```
## Performance impact
- **Without debug**, `must` statement generates only a `NOPL` instruction.
Thus the performance impact is unnoticeable.
- **With debug**, there are checking statement instructions generated.
- **BUT, using `must.Be.OK()` creates a closure,
which hinders inlining a function**. See [golang-inline-rules](https://github.com/golang/go/wiki/CompilerOptimizations#function-inlining) :
> Function Inlining
>
> Only short and simple functions are inlined. To be inlined a function must
> contain less than ~40 expressions and does not contain complex things like
> function calls, loops, labels, closures, panic's, recover's, select's,
> switch'es, etc.
Since inlining function is part of golang compile time optimization for small
functions,
there will introduce a minor portion of performance impact if you have a lot
calls to small functions.
### Debug mode
```
> go build -o bin-release .
> go tool objdump -S bin-release
TEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.go
mustbe.OK(func() {
0x1246030 90 NOPL
0x1246031 488b4c2410 MOVQ 0x10(SP), CX
return a >> uint(b)
0x1246036 4883f940 CMPQ $0x40, CX
...
0x1246050 c3 RET
```
### Release mode
```
> go build -tags debug -o bin-debug .
> go tool objdump -S bin-debug
TEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.go
func rshift(a, b int) int {
...
mustbe.OK(func() {
0x12481fd 0f57c0 XORPS X0, X0
0x1248200 0f110424 MOVUPS X0, 0(SP)
...
f()
0x124822d 488b1c24 MOVQ 0(SP), BX
...
```
# API
`must` uses the popular [testify](https://github.com/stretchr/testify) as underlying
asserting engine, thus there is a corresponding function defined for every
`testify` assertion function.
And `must.Be.OK(f func())` should be the entry of a set of checks:
```
must.Be.OK(f func())
must.Be.Condition(comp assert.Comparison, msgAndArgs ...interface{})
must.Be.Contains(s, contains interface{}, msgAndArgs ...interface{})
must.Be.DirExists(path string, msgAndArgs ...interface{})
must.Be.ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{})
must.Be.Empty(object interface{}, msgAndArgs ...interface{})
must.Be.Equal(expected, actual interface{}, msgAndArgs ...interface{})
must.Be.EqualError(theError error, errString string, msgAndArgs ...interface{})
must.Be.EqualValues(expected, actual interface{}, msgAndArgs ...interface{})
must.Be.Error(err error, msgAndArgs ...interface{})
must.Be.Exactly(expected, actual interface{}, msgAndArgs ...interface{})
must.Be.Fail(failureMessage string, msgAndArgs ...interface{})
must.Be.FailNow(failureMessage string, msgAndArgs ...interface{})
must.Be.False(value bool, msgAndArgs ...interface{})
must.Be.FileExists(path string, msgAndArgs ...interface{})
must.Be.Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{})
must.Be.InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{})
must.Be.InDeltaMapValues(expected, actual interface{}, delta float64, msgAndArgs ...interface{})
must.Be.InDeltaSlice(expected, actual interface{}, delta float64, msgAndArgs ...interface{})
must.Be.InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})
must.Be.InEpsilonSlice(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})
must.Be.IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{})
must.Be.JSONEq(expected string, actual string, msgAndArgs ...interface{})
must.Be.Len(object interface{}, length int, msgAndArgs ...interface{})
must.Be.Nil(object interface{}, msgAndArgs ...interface{})
must.Be.NoError(err error, msgAndArgs ...interface{})
must.Be.NotContains(s, contains interface{}, msgAndArgs ...interface{})
must.Be.NotEmpty(object interface{}, msgAndArgs ...interface{})
must.Be.NotEqual(expected, actual interface{}, msgAndArgs ...interface{})
must.Be.NotNil(object interface{}, msgAndArgs ...interface{})
must.Be.NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{})
must.Be.NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{})
must.Be.NotSubset(list, subset interface{}, msgAndArgs ...interface{})
must.Be.NotZero(i interface{}, msgAndArgs ...interface{})
must.Be.Panics(f assert.PanicTestFunc, msgAndArgs ...interface{})
must.Be.PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{})
must.Be.Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{})
must.Be.Subset(list, subset interface{}, msgAndArgs ...interface{})
must.Be.True(value bool, msgAndArgs ...interface{})
must.Be.WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{})
must.Be.Zero(i interface{}, msgAndArgs ...interface{})
```
See: [assert-functions](https://godoc.org/github.com/stretchr/testify/assert)
# Examples
[rshift-simple-check](examples/rshift/simple)
[rshift-composite-check](examples/rshift/composite)
# Install
```
go get -u github.com/openacid/must
```
# Customize tags
`must` provides with a default tag "debug" to enable expectation check.
It is also very easy to define your own tags.
To do this, create two files in one of your package, such as `mymust_debug.go` and `mymust_release.go`, like following:
`mymust_debug.go`:
```go
// +build mydebug
package your_package
import "github.com/openacid/must/enabled"
var mymustBe = enabled.Be
```
`mymust_release.go`:
```go
// +build !mydebug
package your_package
import "github.com/openacid/must/disabled"
var mymustBe = disabled.Be
```
And replace `must.Be` with `mymustBe` in your source codes.
Then your could enable it just by:
```
go build -tags mydebug
```
See more: [go-build-constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints)