-
Notifications
You must be signed in to change notification settings - Fork 79
/
assertions.go
153 lines (132 loc) · 4.37 KB
/
assertions.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
package goblin
import (
"fmt"
"reflect"
"strings"
)
// Assertion represents a fact stated about a source object. It contains the
// source object and function to call
type Assertion struct {
src interface{}
fail func(interface{})
}
func objectsAreEqual(a, b interface{}) bool {
if reflect.TypeOf(a) != reflect.TypeOf(b) {
return false
}
if reflect.DeepEqual(a, b) {
return true
}
if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
return true
}
return false
}
// Format series of messages provided to an assertion. Separate messages from
// the preamble of assertion with a comma and concatenate messages using spaces.
// Messages that are purely whitespace will be wrapped with square brackets, so
// the developer can glean that something was actually reported in a message.
func formatMessages(messages ...interface{}) string {
// Concatenate messages together.
var fm strings.Builder
for _, message := range messages {
fm.WriteString(" ")
// Format message then wrap with square brackets if only
// whitespace.
m := fmt.Sprintf("%v", message)
if strings.TrimSpace(m) == "" {
m = fmt.Sprintf("[%s]", m)
}
fm.WriteString(m)
}
if fm.Len() == 0 {
return ""
}
return "," + fm.String()
}
// Eql is a shorthand alias of Equal for convenience
func (a *Assertion) Eql(dst interface{}, messages ...interface{}) {
a.Equal(dst, messages)
}
// Equal takes a destination object and asserts that a source object and
// destination object are equal to one another. It will fail the assertion and
// print a corresponding message if the objects are not equivalent.
func (a *Assertion) Equal(dst interface{}, messages ...interface{}) {
if !objectsAreEqual(a.src, dst) {
a.fail(fmt.Sprintf("%#v %s %#v%s", a.src, "does not equal", dst,
formatMessages(messages...)))
}
}
// IsTrue asserts that a source is equal to true. Optional messages can be
// provided for inclusion in the displayed message if the assertion fails. It
// will fail the assertion if the source does not resolve to true.
func (a *Assertion) IsTrue(messages ...interface{}) {
if !objectsAreEqual(a.src, true) {
a.fail(fmt.Sprintf("%v %s%s", a.src,
"expected false to be truthy",
formatMessages(messages...)))
}
}
// IsFalse asserts that a source is equal to false. Optional messages can be
// provided for inclusion in the displayed message if the assertion fails. It
// will fail the assertion if the source does not resolve to false.
func (a *Assertion) IsFalse(messages ...interface{}) {
if !objectsAreEqual(a.src, false) {
a.fail(fmt.Sprintf("%v %s%s", a.src,
"expected true to be falsey",
formatMessages(messages...)))
}
}
// isNil returns whether a.src is nil or not.
func (a *Assertion) isNil() bool {
if !objectsAreEqual(a.src, nil) {
specialKinds := []reflect.Kind{
reflect.Slice, reflect.Chan,
reflect.Map, reflect.Ptr,
reflect.Interface, reflect.Func,
}
t := reflect.TypeOf(a.src).Kind()
for _, kind := range specialKinds {
if t == kind {
return reflect.ValueOf(a.src).IsNil()
}
}
return false
}
return true
}
// IsNil asserts that source is nil.
func (a *Assertion) IsNil(messages ...interface{}) {
if !a.isNil() {
message := fmt.Sprintf("%v %s%v", a.src, "expected to be nil", formatMessages(messages...))
a.fail(message)
}
}
// IsNotNil asserts that source is not nil.
func (a *Assertion) IsNotNil(messages ...interface{}) {
if a.isNil() {
message := fmt.Sprintf("%v %s%v", a.src, "is nil", formatMessages(messages...))
a.fail(message)
}
}
// IsZero asserts that source is a zero value for its respective type.
// If it is a structure, for example, all of its fields must have their
// respective zero value: "" for strings, 0 for int, etc. Slices, arrays
// and maps are only considered zero if they are nil. To check if these
// type of values are empty or not, use the len() from the data source
// with IsZero(). Example: g.Assert(len(list)).IsZero().
func (a *Assertion) IsZero(messages ...interface{}) {
valueOf := reflect.ValueOf(a.src)
if !valueOf.IsZero() {
message := fmt.Sprintf("%#v %s%v", a.src, "is not a zero value", formatMessages(messages...))
a.fail(message)
}
}
// IsNotZero asserts the contrary of IsZero.
func (a *Assertion) IsNotZero(messages ...interface{}) {
valueOf := reflect.ValueOf(a.src)
if valueOf.IsZero() {
message := fmt.Sprintf("%#v %s%v", a.src, "is a zero value", formatMessages(messages...))
a.fail(message)
}
}