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)
}
}
|