├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── be.go ├── be_test.go ├── common.go ├── doc.go ├── else.go ├── expect.go ├── have.go ├── have_test.go ├── helheim_test.go ├── stack_prefix.go ├── stack_prefix_old.go ├── stack_test.go ├── to.go └── to_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | draft 2 | 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.6 4 | - 1.7 5 | install: 6 | - export PATH=$PATH:$HOME/gopath/bin 7 | scripts: 8 | - go test 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ariel Mashraki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Expect.go [![Build status][travis-image]][travis-url] [![License][license-image]][license-url] [![GoDoc][godoc-img]][godoc-url] 2 | > Minimalistic BDD-style assertions for Go (inspired by expect.js) 3 | 4 | ```go 5 | expect := expect.New(t) 6 | 7 | // Numbers 8 | expect(10).To.Be.Above(1).And.Below(20) 9 | expect(5).Not.To.Be.Within(0, 4) 10 | 11 | // Strings 12 | expect("foobarbaz").To.StartWith("foo").And.EndWith("baz").And.Contains("bar") 13 | expect("Foo").To.Match("(?i)foo") 14 | 15 | // Equal 16 | expect(res.StatusCode).To.Equal(200) 17 | expect(false).Not.To.Equal("false") 18 | expect(map[int]int{}).To.Equal(map[int]int{}) 19 | 20 | // Empty 21 | expect(map[int]int{}).To.Be.Empty() 22 | expect("").To.Be.Empty() 23 | expect([2]int{}).Not.To.Be.Empty() 24 | 25 | // Ok (i.e: not "", 0, false, nil) 26 | expect(val).To.Be.Ok() 27 | expect(false).Not.To.Be.Ok() 28 | 29 | // True/False 30 | expect(true).To.Be.True() 31 | expect(false).To.Be.False() 32 | 33 | // Type Assertion 34 | expect("").To.Be.String() 35 | expect(0).To.Be.Int() 36 | expect(1.1).To.Be.Float() 37 | expect(1).Not.To.Be.Bool() 38 | expect(map[string]int{}).To.Be.Map() 39 | expect([...]int{1}).To.Be.Array() 40 | expect([]string{"a"}).To.Be.Slice() 41 | expect(ch).To.Be.Chan() 42 | expect(struct{}{}).To.Be.Struct() 43 | expect(&struct{}{}).To.Be.Ptr() 44 | expect(nil).To.Be.Nil() 45 | expect(Person{}).To.Be.Type("Person") 46 | 47 | // Len 48 | expect("foo").To.Have.Len(3) 49 | expect([]int{1, 2}).To.Have.Len(2) 50 | 51 | // Cap 52 | expect(make([]byte, 2, 10)).To.Have.Cap(10) 53 | expect([2]int{}).To.Have.Cap(2) 54 | 55 | // Maps 56 | m1 := map[string]int{ 57 | "a": 1, 58 | "b": 2, 59 | } 60 | expect(m1).To.Have.Key("a") 61 | expect(m1).To.Have.Key("a", 1) // With value 62 | expect(m1).To.Have.Keys("a", "b") 63 | 64 | // Structs 65 | p := struct { 66 | X, Y int 67 | }{1, 3} 68 | expect(p).To.Have.Field("Y", 3).And.Field("X", 1) 69 | 70 | // Functions 71 | expect(func() {}).Not.To.Panic() 72 | expect(func() { 73 | panic("foo") 74 | }).To.Panic() 75 | expect(func() { 76 | panic("bar") 77 | }).To.Panic("bar") 78 | 79 | // FailNow 80 | expect("foo").To.Equal("bar").Else.FailNow() 81 | ``` 82 | 83 | ## License 84 | MIT 85 | 86 | [travis-image]: https://img.shields.io/travis/a8m/expect.svg?style=flat-square 87 | [travis-url]: https://travis-ci.org/a8m/expect 88 | [license-url]: LICENSE 89 | [license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square 90 | [godoc-url]: https://godoc.org/github.com/a8m/expect 91 | [godoc-img]: https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square 92 | -------------------------------------------------------------------------------- /be.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | type Be struct { 10 | Else *Else 11 | And *Be 12 | t T 13 | actual interface{} 14 | assert bool 15 | } 16 | 17 | func newBe(t T, e *Else, actual interface{}, assert bool) *Be { 18 | be := &Be{ 19 | Else: e, 20 | t: t, 21 | actual: actual, 22 | assert: assert, 23 | } 24 | be.And = be 25 | return be 26 | } 27 | 28 | // Assert numeric value above the given value (> n) 29 | func (b *Be) Above(e float64) *Be { 30 | msg := b.msg(fmt.Sprintf("above %v", e)) 31 | if b.Num() > e != b.assert { 32 | b.fail(2, msg) 33 | } 34 | return b 35 | } 36 | 37 | // Assert numeric value below the given value (< n) 38 | func (b *Be) Below(e float64) *Be { 39 | msg := b.msg(fmt.Sprintf("below %v", e)) 40 | if b.Num() < e != b.assert { 41 | b.fail(2, msg) 42 | } 43 | return b 44 | } 45 | 46 | // Assert inclusive numeric range (<= to and >= from) 47 | func (b *Be) Within(from, to float64) *Be { 48 | msg := b.msg(fmt.Sprintf("between range %v <= x <= %v", from, to)) 49 | x := b.Num() 50 | if x <= to && x >= from != b.assert { 51 | b.fail(2, msg) 52 | } 53 | return b 54 | } 55 | 56 | // Assert given value is empty, Array, Slice, Map or String 57 | func (b *Be) Empty() *Be { 58 | msg := b.msg("empty") 59 | if i, ok := length(b.actual); ok { 60 | if i == 0 != b.assert { 61 | b.fail(2, msg) 62 | } 63 | } else { 64 | b.t.Fatal(invMsg("Array, Slice, Map or String")) 65 | } 66 | return b 67 | } 68 | 69 | // Assert if the given value is truthy(i.e: not "", nil, 0, false) 70 | func (b *Be) Ok() *Be { 71 | msg := b.msg("ok") 72 | var exp bool 73 | switch b.actual.(type) { 74 | case int, int8, int32, int64, uint, uint8, uint32, uint64, float32, float64: 75 | exp = b.actual != 0 76 | case string: 77 | exp = b.actual != "" 78 | case bool: 79 | exp = b.actual != false // TODO(Ariel): without the `!= false`, it's ask for type assertion 80 | default: 81 | exp = b.actual != nil 82 | } 83 | if exp != b.assert { 84 | b.fail(2, msg) 85 | } 86 | return b 87 | } 88 | 89 | // Assert given value is type of string 90 | func (b *Be) String() *Be { 91 | msg := b.msg("string") 92 | if _, ok := b.actual.(string); ok != b.assert { 93 | b.fail(2, msg) 94 | } 95 | return b 96 | } 97 | 98 | // Assert given value is type of int 99 | func (b *Be) Int() *Be { 100 | msg := b.msg("int") 101 | if _, ok := b.actual.(int); ok != b.assert { 102 | b.fail(2, msg) 103 | } 104 | return b 105 | } 106 | 107 | // Assert given value is type of float32/64 108 | func (b *Be) Float() *Be { 109 | msg := b.msg("float") 110 | exp := false 111 | switch b.actual.(type) { 112 | case float32, float64: 113 | exp = true 114 | } 115 | if exp != b.assert { 116 | b.fail(2, msg) 117 | } 118 | return b 119 | } 120 | 121 | // Assert given value is type of boolean 122 | func (b *Be) Bool() *Be { 123 | msg := b.msg("boolean") 124 | if _, ok := b.actual.(bool); ok != b.assert { 125 | b.fail(2, msg) 126 | } 127 | return b 128 | } 129 | 130 | // Assert given value is type of map 131 | func (b *Be) Map() *Be { 132 | msg := b.msg("map") 133 | if reflect.TypeOf(b.actual).Kind() == reflect.Map != b.assert { 134 | b.fail(2, msg) 135 | } 136 | return b 137 | } 138 | 139 | // Assert given value is type of array 140 | func (b *Be) Array() *Be { 141 | msg := b.msg("array") 142 | if reflect.TypeOf(b.actual).Kind() == reflect.Array != b.assert { 143 | b.fail(2, msg) 144 | } 145 | return b 146 | } 147 | 148 | // Assert given value is type of slice 149 | func (b *Be) Slice() *Be { 150 | msg := b.msg("slice") 151 | if reflect.TypeOf(b.actual).Kind() == reflect.Slice != b.assert { 152 | b.fail(2, msg) 153 | } 154 | return b 155 | } 156 | 157 | // Assert given value is type of channel 158 | func (b *Be) Chan() *Be { 159 | msg := b.msg("channel") 160 | if reflect.TypeOf(b.actual).Kind() == reflect.Chan != b.assert { 161 | b.fail(2, msg) 162 | } 163 | return b 164 | } 165 | 166 | // Assert given value is type of struct 167 | func (b *Be) Struct() *Be { 168 | msg := b.msg("struct") 169 | if reflect.TypeOf(b.actual).Kind() == reflect.Struct != b.assert { 170 | b.fail(2, msg) 171 | } 172 | return b 173 | } 174 | 175 | // Assert given value is type of pointer 176 | func (b *Be) Ptr() *Be { 177 | msg := b.msg("pointer") 178 | if reflect.TypeOf(b.actual).Kind() == reflect.Ptr != b.assert { 179 | b.fail(2, msg) 180 | } 181 | return b 182 | } 183 | 184 | // Assert given value is nil 185 | func (b *Be) Nil() *Be { 186 | msg := b.msg("nil") 187 | if b.actual == nil != b.assert { 188 | b.fail(2, msg) 189 | } 190 | return b 191 | } 192 | 193 | // Assert given value is type of the given string 194 | func (b *Be) Type(s string) *Be { 195 | msg := b.msg(fmt.Sprintf("type %v", s)) 196 | if reflect.TypeOf(b.actual).Name() == s != b.assert { 197 | b.fail(2, msg) 198 | } 199 | return b 200 | } 201 | 202 | func (b *Be) fail(callers int, msg string) { 203 | b.Else.failed = true 204 | fail(b.t, callers, msg) 205 | } 206 | 207 | func (b *Be) msg(s string) string { 208 | return errMsg("to be")(b.actual, s, b.assert) 209 | } 210 | 211 | func (b *Be) Num() float64 { 212 | rv := reflect.ValueOf(b.actual) 213 | switch rv.Kind() { 214 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 215 | return float64(rv.Int()) 216 | case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 217 | return float64(rv.Uint()) 218 | case reflect.Float32, reflect.Float64: 219 | return float64(rv.Float()) 220 | default: 221 | b.t.Fatal(invMsg("numeric")) 222 | return 0 223 | } 224 | } 225 | 226 | func (b *Be) True() *Be { 227 | v, err := b.bool() 228 | if err != nil { 229 | b.t.Fatal(invMsg("bool")) 230 | return b 231 | } 232 | if !v { 233 | b.fail(2, b.msg("true")) 234 | } 235 | return b 236 | } 237 | 238 | func (b *Be) False() *Be { 239 | v, err := b.bool() 240 | if err != nil { 241 | b.t.Fatal(invMsg("bool")) 242 | return b 243 | } 244 | if v { 245 | b.fail(2, b.msg("false")) 246 | } 247 | return b 248 | } 249 | 250 | func (b *Be) bool() (bool, error) { 251 | rv := reflect.ValueOf(b.actual) 252 | switch rv.Kind() { 253 | case reflect.Bool: 254 | return rv.Bool(), nil 255 | default: 256 | } 257 | return false, errors.New("not a bool") 258 | } 259 | -------------------------------------------------------------------------------- /be_test.go: -------------------------------------------------------------------------------- 1 | package expect_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/a8m/expect" 7 | ) 8 | 9 | // TODO(Ariel): Create mock that implement TB interface 10 | // and stub `Error` and `Fatal` 11 | 12 | func TestAbove(t *testing.T) { 13 | expect := expect.New(t) 14 | expect(10).To.Be.Above(0) 15 | expect(10).Not.To.Be.Above(20) 16 | } 17 | 18 | func TestBelow(t *testing.T) { 19 | expect := expect.New(t) 20 | expect(10).To.Be.Below(20) 21 | expect(10).Not.To.Be.Below(0) 22 | } 23 | 24 | func TestWithin(t *testing.T) { 25 | expect := expect.New(t) 26 | expect(10).To.Be.Within(10, 20) 27 | expect(5).To.Be.Within(5, 5) 28 | expect(1).Not.To.Be.Within(2, 1) 29 | } 30 | 31 | func TestEmpty(t *testing.T) { 32 | expect := expect.New(t) 33 | expect("").To.Be.Empty() 34 | expect([]int{1, 2, 3}).Not.To.Be.Empty() 35 | expect(make(map[string]int)).To.Be.Empty() 36 | expect([2]int{}).Not.To.Be.Empty() 37 | expect([]byte{}).To.Be.Empty() 38 | } 39 | 40 | func TestOk(t *testing.T) { 41 | expect := expect.New(t) 42 | expect("").Not.To.Be.Ok() 43 | expect(false).Not.To.Be.Ok() 44 | expect(0).Not.To.Be.Ok() 45 | expect(nil).Not.To.Be.Ok() 46 | 47 | expect("foo").To.Be.Ok() 48 | expect(1).To.Be.Ok() 49 | expect(true).To.Be.Ok() 50 | expect(struct{}{}).To.Be.Ok() 51 | expect([]int{}).To.Be.Ok() 52 | } 53 | 54 | func TestTrue(t *testing.T) { 55 | mockT := newMockT() 56 | expect := expect.New(mockT) 57 | 58 | expect(true).To.Be.True() 59 | select { 60 | case <-mockT.ErrorfCalled: 61 | t.Errorf("Expected Errorf() on passing test not to be called") 62 | case <-mockT.FatalCalled: 63 | t.Errorf("Expected Fatal() on passing test not to be called") 64 | case <-mockT.FailNowCalled: 65 | t.Errorf("Expected FailNow() on passing test not to be called") 66 | default: 67 | } 68 | 69 | expect(false).To.Be.True() 70 | select { 71 | case <-mockT.ErrorfCalled: 72 | default: 73 | t.Errorf("Expected Errorf() on failing test to be called") 74 | } 75 | 76 | expect(42).To.Be.True() 77 | select { 78 | case <-mockT.FatalCalled: 79 | default: 80 | t.Errorf("Expected Fatal() on failing test to be called") 81 | } 82 | } 83 | 84 | func TestFalse(t *testing.T) { 85 | mockT := newMockT() 86 | expect := expect.New(mockT) 87 | 88 | expect(false).To.Be.False() 89 | select { 90 | case <-mockT.ErrorfCalled: 91 | t.Errorf("Expected Errorf() on passing test not to be called") 92 | case <-mockT.FatalCalled: 93 | t.Errorf("Expected Fatal() on passing test not to be called") 94 | case <-mockT.FailNowCalled: 95 | t.Errorf("Expected FailNow() on passing test not to be called") 96 | default: 97 | } 98 | 99 | expect(true).To.Be.False() 100 | select { 101 | case <-mockT.ErrorfCalled: 102 | default: 103 | t.Errorf("Expected Errorf() on failing test to be called") 104 | } 105 | 106 | expect(42).To.Be.False() 107 | select { 108 | case <-mockT.FatalCalled: 109 | default: 110 | t.Errorf("Expected Fatal() on failing test to be called") 111 | } 112 | } 113 | 114 | func TestString(t *testing.T) { 115 | expect := expect.New(t) 116 | expect("").To.Be.String() 117 | expect(1).Not.To.Be.String() 118 | } 119 | 120 | func TestInt(t *testing.T) { 121 | expect := expect.New(t) 122 | expect(0).To.Be.Int() 123 | expect("").Not.To.Be.Int() 124 | } 125 | 126 | func TestFloat(t *testing.T) { 127 | expect := expect.New(t) 128 | expect(0).Not.To.Be.Float() 129 | expect(1.1).To.Be.Float() 130 | } 131 | 132 | func TestBool(t *testing.T) { 133 | expect := expect.New(t) 134 | expect(true).To.Be.Bool() 135 | expect(1).Not.To.Be.Bool() 136 | } 137 | 138 | func TestMap(t *testing.T) { 139 | expect := expect.New(t) 140 | expect(1).Not.To.Be.Map() 141 | expect(map[string]int{}).To.Be.Map() 142 | } 143 | 144 | func TestArray(t *testing.T) { 145 | expect := expect.New(t) 146 | expect([]int{}).Not.To.Be.Array() 147 | expect([1]int{}).To.Be.Array() 148 | expect([...]int{1}).To.Be.Array() 149 | } 150 | 151 | func TestSlice(t *testing.T) { 152 | expect := expect.New(t) 153 | expect([]int{}).To.Be.Slice() 154 | expect([]string{"a"}).To.Be.Slice() 155 | expect([1]int{}).Not.To.Be.Slice() 156 | expect([...]int{1}).Not.To.Be.Slice() 157 | } 158 | 159 | func TestChan(t *testing.T) { 160 | expect := expect.New(t) 161 | var ch chan string 162 | expect(ch).To.Be.Chan() 163 | expect(1).Not.To.Be.Chan() 164 | } 165 | 166 | func TestPtr(t *testing.T) { 167 | expect := expect.New(t) 168 | expect(&struct{}{}).To.Be.Ptr() 169 | expect(struct{}{}).Not.To.Be.Ptr() 170 | } 171 | 172 | func TestStruct(t *testing.T) { 173 | expect := expect.New(t) 174 | expect(struct{}{}).To.Be.Struct() 175 | expect(&struct{}{}).Not.To.Be.Struct() 176 | } 177 | 178 | func TestNil(t *testing.T) { 179 | expect := expect.New(t) 180 | expect(nil).To.Be.Nil() 181 | expect(0).Not.To.Be.Nil() 182 | var a interface{} 183 | a = nil 184 | expect(a).To.Be.Nil() 185 | } 186 | 187 | func TestType(t *testing.T) { 188 | expect := expect.New(t) 189 | type Person struct{} 190 | expect(Person{}).To.Be.Type("Person") 191 | expect(1).To.Be.Type("int") 192 | expect(struct{}{}).Not.To.Be.Type("Person") 193 | } 194 | 195 | func TestBeChaining(t *testing.T) { 196 | expect := expect.New(t) 197 | expect(10).To.Be.Above(0).And.Below(20) 198 | expect(10).Not.To.Be.Above(20).And.Below(0) 199 | } 200 | 201 | func TestBeFailNow(t *testing.T) { 202 | mockT := newMockT() 203 | expect := expect.New(mockT) 204 | expect(10).To.Be.Above(0).Else.FailNow() 205 | select { 206 | case <-mockT.FailNowCalled: 207 | t.Errorf("Expected FailNow() on passing test not to be called") 208 | default: 209 | } 210 | expect(10).To.Be.Above(20).Else.FailNow() 211 | select { 212 | case <-mockT.FailNowCalled: 213 | default: 214 | t.Errorf("Expected FailNow() on failing test to be called") 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /common.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "runtime" 7 | "strings" 8 | ) 9 | 10 | func errMsg(t string) func(act, exp interface{}, assert bool) string { 11 | return func(act, exp interface{}, assert bool) (s string) { 12 | not := "not " 13 | if assert { 14 | not = "" 15 | } 16 | s = fmt.Sprintf("Expect %v %v%v %v", act, not, t, exp) 17 | return 18 | } 19 | } 20 | 21 | func invMsg(v string) (s string) { 22 | s = fmt.Sprintf("Invalid argument - expecting %v value.", v) 23 | return 24 | } 25 | 26 | func length(v interface{}) (int, bool) { 27 | switch reflect.TypeOf(v).Kind() { 28 | case reflect.Slice, reflect.Array, reflect.Map, reflect.String, reflect.Chan: 29 | return reflect.ValueOf(v).Len(), true 30 | default: 31 | return 0, false 32 | } 33 | } 34 | 35 | // fail creates a message including the stack trace returned from 36 | // runtime.Caller 37 | func fail(t T, callers int, msg string) { 38 | stack := stackPrefix(fullStack(callers + 1)) 39 | // It makes sense to have the most recent call closest to the 40 | // message. 41 | for i, j := 0, len(stack)-1; i < j; i, j = i+1, j-1 { 42 | stack[i], stack[j] = stack[j], stack[i] 43 | } 44 | prefix := strings.Join(stack, "\n\r\t") 45 | t.Errorf("\r\t%s\n%s", prefix, msg) 46 | } 47 | 48 | // fullStack gets the full call stack, skipping the passed in number 49 | // of callers. 50 | func fullStack(skip int) []uintptr { 51 | var stack []uintptr 52 | next := make([]uintptr, 10) 53 | for { 54 | added := runtime.Callers(skip, next) 55 | stack = append(stack, next[:added]...) 56 | if added < len(next) { 57 | break 58 | } 59 | skip += added 60 | } 61 | return stack 62 | } 63 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Minimalistic BDD-style assertions for Go (inspired by expect.js) 2 | package expect 3 | 4 | //go:generate hel 5 | -------------------------------------------------------------------------------- /else.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | type Else struct { 4 | t T 5 | failed bool 6 | } 7 | 8 | func newElse(t T) *Else { 9 | return &Else{ 10 | t: t, 11 | } 12 | } 13 | 14 | func (e *Else) FailNow() { 15 | if e.failed { 16 | e.t.FailNow() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /expect.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | // T is a type that we can perform assertions with. 4 | type T interface { 5 | Errorf(format string, args ...interface{}) 6 | Fatal(...interface{}) 7 | FailNow() 8 | } 9 | 10 | // Matcher is any type which can perform matches against an actual 11 | // value. A non-nil error means a failed match, and its Error() 12 | // method should return a suffix that finishes the prefix, 13 | // "Expected {actual} to ". 14 | // 15 | // Note that for negated matches (expect(foo).Not...), the matcher 16 | // itself will be printed out using %#v syntax. If you would like 17 | // to customize your output, implement fmt.GoStringer. 18 | // 19 | // Example: 20 | // 21 | // type StatusCodeMatcher int 22 | // 23 | // func (m StatusCodeMatcher) Match(actual interface{}) error { 24 | // resp, ok := actual.(*http.Response) 25 | // if !ok { 26 | // // "Expected {actual} to be of type *http.Response" 27 | // return errors.New("be of type *http.Response") 28 | // } 29 | // if resp.StatusCode != int(m) { 30 | // // "Expected {actual} to have a response code {m}" 31 | // return fmt.Errorf("have a response code of %d", m) 32 | // } 33 | // return nil 34 | // } 35 | // 36 | // // GoString returns representation for m in a negated state, 37 | // // e.g. where a value was *not* supposed to match. 38 | // func (m StatusCodeMatcher) GoString() string { 39 | // return fmt.Sprintf("Status Code %d", m) 40 | // } 41 | // 42 | // // The eventual assertions: 43 | // expect(resp).To.Pass(StatusCodeMatcher(http.StatusOK)) 44 | // expect(resp).Not.To.Pass(StatusCodeMatcher(http.StatusOK)) 45 | type Matcher interface { 46 | Match(actual interface{}) error 47 | } 48 | 49 | // Expect is the result of calling an Expectation with a value to assert 50 | // against. 51 | type Expect struct { 52 | To *To 53 | Not *Not 54 | } 55 | 56 | // Not stores a To that is initialized to be the negation of the main To. 57 | type Not struct { 58 | To *To 59 | } 60 | 61 | // Expectation returns an Expect that is used to make assertions. 62 | type Expectation func(v interface{}) *Expect 63 | 64 | // New returns a function that can be given a value and have `To, To.Be, 65 | // To.Have` assertions chained onto it. 66 | func New(t T) Expectation { 67 | return func(v interface{}) *Expect { 68 | return &Expect{ 69 | To: newTo(t, v, true), 70 | Not: &Not{To: newTo(t, v, false)}, 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /have.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | import ( 4 | . "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Have struct { 9 | Else *Else 10 | And *Have 11 | t T 12 | actual interface{} 13 | assert bool 14 | } 15 | 16 | func newHave(t T, e *Else, actual interface{}, assert bool) *Have { 17 | have := &Have{ 18 | Else: e, 19 | t: t, 20 | actual: actual, 21 | assert: assert, 22 | } 23 | have.And = have 24 | return have 25 | } 26 | 27 | // Assert value to have length of the the given number 28 | func (h *Have) Len(i int) *Have { 29 | msg := h.msg(Sprintf("length of %v", i)) 30 | if l, ok := length(h.actual); ok { 31 | if l == i != h.assert { 32 | h.fail(2, msg) 33 | } 34 | } else { 35 | h.t.Fatal(invMsg("Array, Slice, Map or String")) 36 | } 37 | return h 38 | } 39 | 40 | // Assert value to have capacity of the given number 41 | func (h *Have) Cap(i int) *Have { 42 | msg := h.msg(Sprint("capacity of %v", i)) 43 | switch reflect.TypeOf(h.actual).Kind() { 44 | case reflect.Array, reflect.Slice, reflect.Chan: 45 | if reflect.ValueOf(h.actual).Cap() == i != h.assert { 46 | h.fail(2, msg) 47 | } 48 | default: 49 | h.t.Fatal(invMsg("Array, Slice or Chan")) 50 | } 51 | return h 52 | } 53 | 54 | // Assert `key` exists on the given Map, and has optional value. 55 | func (h *Have) Key(args ...interface{}) *Have { 56 | // Test also value 57 | testVal := len(args) > 1 58 | msg := Sprintf("key: %v", args[0]) 59 | if testVal { 60 | msg += Sprintf(" with value: %v", args[1]) 61 | } 62 | msg = h.msg(msg) 63 | switch reflect.TypeOf(h.actual).Kind() { 64 | case reflect.Map: 65 | v := reflect.ValueOf(h.actual) 66 | k := v.MapIndex(reflect.ValueOf(args[0])) 67 | if (testVal && k.IsValid()) || k.IsValid() == h.assert { 68 | // Compare value 69 | if testVal && reflect.DeepEqual(k.Interface(), args[1]) != h.assert { 70 | h.fail(2, msg) 71 | } 72 | } else { 73 | h.fail(2, msg) 74 | } 75 | default: 76 | h.t.Fatal(invMsg("Map")) 77 | } 78 | return h 79 | } 80 | 81 | // Assert `keys` exists on the given Map 82 | func (h *Have) Keys(args ...interface{}) *Have { 83 | msg := h.msg(Sprintf("keys: %v", args)) 84 | switch reflect.TypeOf(h.actual).Kind() { 85 | case reflect.Map: 86 | v := reflect.ValueOf(h.actual) 87 | for _, k := range args { 88 | vk := v.MapIndex(reflect.ValueOf(k)) 89 | if vk.IsValid() != h.assert { 90 | h.fail(2, msg) 91 | } 92 | } 93 | default: 94 | h.t.Fatal(invMsg("Map")) 95 | } 96 | return h 97 | } 98 | 99 | // Assert `field` exist on the given Struct, and has optional value. 100 | func (h *Have) Field(s string, args ...interface{}) *Have { 101 | // Test also value 102 | testVal := len(args) > 0 103 | msg := Sprintf("field: %v", s) 104 | if testVal { 105 | msg += Sprintf(" with value: %v", args[0]) 106 | } 107 | msg = h.msg(msg) 108 | switch reflect.TypeOf(h.actual).Kind() { 109 | case reflect.Struct: 110 | v := reflect.ValueOf(h.actual) 111 | f := v.FieldByName(s) 112 | if (testVal && f.IsValid()) || f.IsValid() == h.assert { 113 | // Compare value 114 | if testVal && reflect.DeepEqual(f.Interface(), args[0]) != h.assert { 115 | h.fail(2, msg) 116 | } 117 | } else { 118 | h.fail(2, msg) 119 | } 120 | default: 121 | h.t.Fatal(invMsg("Struct")) 122 | } 123 | return h 124 | } 125 | 126 | // Assert `fields` exists on the given Struct 127 | func (h *Have) Fields(args ...string) *Have { 128 | msg := h.msg(Sprintf("fields: %v", args)) 129 | switch reflect.TypeOf(h.actual).Kind() { 130 | case reflect.Struct: 131 | v := reflect.ValueOf(h.actual) 132 | for _, f := range args { 133 | if v.FieldByName(f).IsValid() != h.assert { 134 | h.fail(2, msg) 135 | } 136 | } 137 | default: 138 | h.t.Fatal(invMsg("Struct")) 139 | } 140 | return h 141 | } 142 | 143 | // Assert `method` exist on the given struct/ptr 144 | func (h *Have) Method(m string) *Have { 145 | msg := h.msg(Sprintf("method: %v", m)) 146 | switch reflect.TypeOf(h.actual).Kind() { 147 | case reflect.Struct, reflect.Ptr: 148 | v := reflect.ValueOf(h.actual) 149 | if v.MethodByName(m).IsValid() != h.assert { 150 | h.fail(2, msg) 151 | } 152 | default: 153 | h.t.Fatal(invMsg("Struct or Ptr")) 154 | } 155 | return h 156 | } 157 | 158 | func (h *Have) fail(callers int, msg string) { 159 | h.Else.failed = true 160 | fail(h.t, callers, msg) 161 | } 162 | 163 | func (h *Have) msg(s string) string { 164 | return errMsg("to have")(h.actual, s, h.assert) 165 | } 166 | -------------------------------------------------------------------------------- /have_test.go: -------------------------------------------------------------------------------- 1 | package expect_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/a8m/expect" 7 | ) 8 | 9 | // TODO(Ariel): Create mock that implement TB interface 10 | // and stub `Error` and `Fatal` 11 | 12 | func TestLen(t *testing.T) { 13 | expect := expect.New(t) 14 | expect("foo").To.Have.Len(3) 15 | m := map[string]int{} 16 | expect(m).To.Have.Len(0) 17 | expect(m).Not.To.Have.Len(1) 18 | s := []string{"a", "b"} 19 | expect(s).To.Have.Len(2) 20 | expect(s).Not.To.Have.Len(1) 21 | c := make(chan bool, 5) 22 | c <- true 23 | expect(c).To.Have.Len(1) 24 | expect(c).Not.To.Have.Len(0) 25 | } 26 | 27 | func TestCap(t *testing.T) { 28 | expect := expect.New(t) 29 | expect([2]int{}).To.Have.Cap(2) 30 | expect(make([]byte, 2, 10)).To.Have.Cap(10) 31 | expect(make(chan string, 2)).Not.To.Have.Cap(10) 32 | } 33 | 34 | func TestKey(t *testing.T) { 35 | expect := expect.New(t) 36 | m1 := map[string]int{ 37 | "a": 1, 38 | "b": 2, 39 | } 40 | expect(m1).To.Have.Key("a") 41 | expect(m1).Not.To.Have.Key("c") 42 | expect(m1).To.Have.Key("a", 1) 43 | 44 | m2 := map[int]string{ 45 | 1: "a", 46 | 2: "b", 47 | } 48 | expect(m2).To.Have.Key(1) 49 | expect(m2).Not.To.Have.Key(3) 50 | expect(m2).To.Have.Key(2, "b") 51 | expect(m2).Not.To.Have.Key(1, "c") 52 | 53 | m3 := map[string]interface{}{ 54 | "arr": [1]int{}, 55 | "map": map[int]int{1: 1}, 56 | } 57 | expect(m3).To.Have.Key("arr") 58 | expect(m3).To.Have.Key("map") 59 | expect(m3).Not.To.Have.Key("struct") 60 | expect(m3).To.Have.Key("arr", [1]int{}) 61 | expect(m3).To.Have.Key("map", map[int]int{1: 1}) 62 | expect(m3).Not.To.Have.Key("map", map[string]int{}) 63 | } 64 | 65 | func TestKeys(t *testing.T) { 66 | expect := expect.New(t) 67 | m1 := map[string]int{ 68 | "a": 1, 69 | "b": 2, 70 | "c": 3, 71 | } 72 | expect(m1).To.Have.Keys("a", "b", "c") 73 | expect(m1).Not.To.Have.Keys("d", "e", "i") 74 | 75 | m2 := map[int]string{ 76 | 1: "a", 77 | 2: "b", 78 | 3: "c", 79 | } 80 | expect(m2).To.Have.Keys(1, 2, 3) 81 | expect(m2).Not.To.Have.Keys(4, 5, 6) 82 | } 83 | 84 | func TestField(t *testing.T) { 85 | expect := expect.New(t) 86 | p := struct { 87 | X, Y int 88 | }{1, 3} 89 | expect(p).To.Have.Field("X") 90 | expect(p).To.Have.Field("Y", 3) 91 | expect(p).Not.To.Have.Field("Z") 92 | expect(p).Not.To.Have.Field("Y", 4) 93 | } 94 | 95 | func TestFields(t *testing.T) { 96 | expect := expect.New(t) 97 | p := struct { 98 | X, Y int 99 | }{1, 2} 100 | expect(p).To.Have.Fields("X", "Y") 101 | expect(p).Not.To.Have.Fields("Z") 102 | expect(p).Not.To.Have.Fields("T", "Z") 103 | } 104 | 105 | // Test Method 106 | type Person struct{} 107 | 108 | func (p Person) Hello() {} 109 | func (p *Person) Hallo() {} 110 | 111 | func TestMethod(t *testing.T) { 112 | expect := expect.New(t) 113 | p := Person{} 114 | expect(p).To.Have.Method("Hello") 115 | expect(p).Not.To.Have.Method("Hallo") 116 | expect(&p).To.Have.Method("Hallo") 117 | expect(&p).To.Have.Method("Hello") 118 | } 119 | 120 | func TestHaveFailNow(t *testing.T) { 121 | mockT := newMockT() 122 | expect := expect.New(mockT) 123 | l := []string{"foo"} 124 | expect(l).To.Have.Len(1).Else.FailNow() 125 | select { 126 | case <-mockT.FailNowCalled: 127 | t.Errorf("Expected FailNow() on passing test not to be called") 128 | default: 129 | } 130 | expect(l).To.Have.Len(3).Else.FailNow() 131 | select { 132 | case <-mockT.FailNowCalled: 133 | default: 134 | t.Errorf("Expected FailNow() on failing test to be called") 135 | } 136 | } 137 | 138 | func TestNotHaveFailNow(t *testing.T) { 139 | mockT := newMockT() 140 | expect := expect.New(mockT) 141 | l := []string{"foo"} 142 | expect(l).Not.To.Have.Len(3).Else.FailNow() 143 | select { 144 | case <-mockT.FailNowCalled: 145 | t.Errorf("Expected FailNow() on passing test not to be called") 146 | default: 147 | } 148 | expect(l).Not.To.Have.Len(1).Else.FailNow() 149 | select { 150 | case <-mockT.FailNowCalled: 151 | default: 152 | t.Errorf("Expected FailNow() on failing test to be called") 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /helheim_test.go: -------------------------------------------------------------------------------- 1 | // This file was generated by github.com/nelsam/hel. Do not 2 | // edit this code by hand unless you *really* know what you're 3 | // doing. Expect any changes made manually to be overwritten 4 | // the next time hel regenerates this file. 5 | 6 | package expect_test 7 | 8 | type mockT struct { 9 | ErrorfCalled chan bool 10 | ErrorfInput struct { 11 | Format chan string 12 | Args chan []interface{} 13 | } 14 | FatalCalled chan bool 15 | FatalInput struct { 16 | Arg0 chan []interface{} 17 | } 18 | FailNowCalled chan bool 19 | } 20 | 21 | func newMockT() *mockT { 22 | m := &mockT{} 23 | m.ErrorfCalled = make(chan bool, 100) 24 | m.ErrorfInput.Format = make(chan string, 100) 25 | m.ErrorfInput.Args = make(chan []interface{}, 100) 26 | m.FatalCalled = make(chan bool, 100) 27 | m.FatalInput.Arg0 = make(chan []interface{}, 100) 28 | m.FailNowCalled = make(chan bool, 100) 29 | return m 30 | } 31 | func (m *mockT) Errorf(format string, args ...interface{}) { 32 | m.ErrorfCalled <- true 33 | m.ErrorfInput.Format <- format 34 | m.ErrorfInput.Args <- args 35 | } 36 | func (m *mockT) Fatal(arg0 ...interface{}) { 37 | m.FatalCalled <- true 38 | m.FatalInput.Arg0 <- arg0 39 | } 40 | func (m *mockT) FailNow() { 41 | m.FailNowCalled <- true 42 | } 43 | 44 | type mockMatcher struct { 45 | MatchCalled chan bool 46 | MatchInput struct { 47 | Actual chan interface{} 48 | } 49 | MatchOutput struct { 50 | Ret0 chan error 51 | } 52 | } 53 | 54 | func newMockMatcher() *mockMatcher { 55 | m := &mockMatcher{} 56 | m.MatchCalled = make(chan bool, 100) 57 | m.MatchInput.Actual = make(chan interface{}, 100) 58 | m.MatchOutput.Ret0 = make(chan error, 100) 59 | return m 60 | } 61 | func (m *mockMatcher) Match(actual interface{}) error { 62 | m.MatchCalled <- true 63 | m.MatchInput.Actual <- actual 64 | return <-m.MatchOutput.Ret0 65 | } 66 | -------------------------------------------------------------------------------- /stack_prefix.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package expect 4 | 5 | import ( 6 | "fmt" 7 | "runtime" 8 | ) 9 | 10 | // stackPrefix returns all stack lines. 11 | func stackPrefix(stack []uintptr) []string { 12 | var output []string 13 | frames := runtime.CallersFrames(stack) 14 | for frame, more := frames.Next(); more; frame, more = frames.Next() { 15 | output = append(output, fmt.Sprintf("%s:%d", frame.File, frame.Line)) 16 | } 17 | return output 18 | } 19 | -------------------------------------------------------------------------------- /stack_prefix_old.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package expect 4 | 5 | import ( 6 | "fmt" 7 | "runtime" 8 | ) 9 | 10 | // stackPrefix returns all stack lines. This is the go1.6 11 | // and earlier version, which is reportedly less accurate 12 | // than the logic from 1.7+. 13 | func stackPrefix(stack []uintptr) []string { 14 | var output []string 15 | for _, pc := range stack { 16 | file, line := runtime.FuncForPC(pc).FileLine(pc) 17 | output = append(output, fmt.Sprintf("%s:%d", file, line)) 18 | } 19 | return output 20 | } 21 | -------------------------------------------------------------------------------- /stack_test.go: -------------------------------------------------------------------------------- 1 | package expect_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/a8m/expect" 8 | ) 9 | 10 | func TestStackTrace(t *testing.T) { 11 | mockT := newMockT() 12 | expect := expect.New(mockT) 13 | expect("foo").To.Equal("bar") 14 | 15 | var args []interface{} 16 | select { 17 | case args = <-mockT.ErrorfInput.Args: 18 | default: 19 | t.Fatal("Errorf was never called for a failing expectation") 20 | } 21 | if len(args) != 2 { 22 | t.Fatalf("Wrong number of arguments (expected 2): %d", args) 23 | } 24 | stack, ok := args[0].(string) 25 | if !ok { 26 | t.Fatalf("Expected %#v to be a string") 27 | } 28 | if !strings.Contains(stack, "stack_test.go") { 29 | t.Errorf(`Expected "%s" to contain "stack_test.go"`, stack) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /to.go: -------------------------------------------------------------------------------- 1 | package expect 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "regexp" 7 | "strings" 8 | ) 9 | 10 | type To struct { 11 | Be *Be 12 | Have *Have 13 | Else *Else 14 | And *To 15 | t T 16 | actual interface{} 17 | assert bool 18 | } 19 | 20 | func newTo(t T, actual interface{}, assert bool) *To { 21 | to := &To{ 22 | t: t, 23 | actual: actual, 24 | assert: assert, 25 | } 26 | to.Else = newElse(t) 27 | to.Be = newBe(t, to.Else, actual, assert) 28 | to.Have = newHave(t, to.Else, actual, assert) 29 | to.And = to 30 | return to 31 | } 32 | 33 | // Assert that a string starts with `s` 34 | func (t *To) StartWith(s string) *To { 35 | msg := t.msg(fmt.Sprintf("start with %v", s)) 36 | if strings.HasPrefix(t.Str(), s) != t.assert { 37 | t.fail(2, msg) 38 | } 39 | return t 40 | } 41 | 42 | // Assert that a string ends with `s` 43 | func (t *To) EndWith(s string) *To { 44 | msg := t.msg(fmt.Sprintf("end with %v", s)) 45 | if strings.HasSuffix(t.Str(), s) != t.assert { 46 | t.fail(2, msg) 47 | } 48 | return t 49 | } 50 | 51 | // Assert that a string conatins `s` 52 | func (t *To) Contains(s string) *To { 53 | msg := t.msg(fmt.Sprintf("contains %v", s)) 54 | if strings.Contains(t.Str(), s) != t.assert { 55 | t.fail(2, msg) 56 | } 57 | return t 58 | } 59 | 60 | // Assert whether a textual regular expression matches a string 61 | func (t *To) Match(s string) *To { 62 | msg := t.msg(fmt.Sprintf("matches %v", s)) 63 | matched, err := regexp.MatchString(s, t.Str()) 64 | if err != nil { 65 | t.t.Fatal(err) 66 | } 67 | if matched != t.assert { 68 | t.fail(2, msg) 69 | } 70 | return t 71 | } 72 | 73 | // Assert two values are equals(deeply) 74 | func (t *To) Equal(exp interface{}) *To { 75 | msg := t.msg(fmt.Sprintf("equal to %v", exp)) 76 | if reflect.DeepEqual(t.actual, exp) != t.assert { 77 | t.fail(2, msg) 78 | } 79 | return t 80 | } 81 | 82 | // Assert func to panic 83 | func (t *To) Panic(args ...interface{}) *To { 84 | testMsg := len(args) > 0 85 | switch t.actual.(type) { 86 | case func(): 87 | fn := reflect.ValueOf(t.actual) 88 | if p, m := ifPanic(fn); p != t.assert || testMsg && args[0] == m != t.assert { 89 | if testMsg { 90 | m = args[0] 91 | } 92 | t.fail(2, t.msg(fmt.Sprintf("panic: %v", m))) 93 | } 94 | default: 95 | t.t.Fatal(invMsg("func")) 96 | 97 | } 98 | return t 99 | } 100 | 101 | func (t *To) Pass(matcher Matcher) *To { 102 | err := matcher.Match(t.actual) 103 | switch t.assert { 104 | case true: 105 | if err != nil { 106 | t.fail(2, t.msg(err.Error())) 107 | } 108 | case false: 109 | if err == nil { 110 | t.fail(2, t.msg(fmt.Sprintf("match %#v", matcher))) 111 | } 112 | } 113 | return t 114 | } 115 | 116 | func (t *To) fail(callers int, msg string) { 117 | fail(t.t, callers+1, msg) 118 | t.Else.failed = true 119 | } 120 | 121 | func ifPanic(f reflect.Value) (isPnc bool, msg interface{}) { 122 | func() { 123 | defer func() { 124 | if msg = recover(); msg != nil { 125 | isPnc = true 126 | } 127 | }() 128 | f.Call([]reflect.Value{}) 129 | }() 130 | return 131 | } 132 | 133 | func (t *To) Str() (s string) { 134 | if s, ok := t.actual.(string); ok { 135 | return s 136 | } 137 | t.t.Fatal(invMsg("string")) 138 | return 139 | } 140 | 141 | func (t *To) msg(s string) string { 142 | return errMsg("to")(t.actual, s, t.assert) 143 | } 144 | -------------------------------------------------------------------------------- /to_test.go: -------------------------------------------------------------------------------- 1 | package expect_test 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/a8m/expect" 9 | ) 10 | 11 | // TODO(Ariel): Create mock that implement TB interface 12 | // and stub `Error` and `Fatal` 13 | 14 | func TestStartWith(t *testing.T) { 15 | expect := expect.New(t) 16 | expect("foo").To.StartWith("f") 17 | expect("foo").Not.To.StartWith("bar") 18 | } 19 | 20 | func TestEndWith(t *testing.T) { 21 | expect := expect.New(t) 22 | expect("bar").To.EndWith("ar") 23 | expect("bar").Not.To.EndWith("az") 24 | } 25 | 26 | func TestContains(t *testing.T) { 27 | expect := expect.New(t) 28 | expect("foobar").To.Contains("ba") 29 | expect("foobar").Not.To.Contains("ga") 30 | } 31 | 32 | func TestMatch(t *testing.T) { 33 | expect := expect.New(t) 34 | expect("Foo").To.Match("(?i)foo") 35 | } 36 | 37 | func TestEqual(t *testing.T) { 38 | expect := expect.New(t) 39 | expect("a").To.Equal("a") 40 | expect(1).To.Equal(1) 41 | expect(false).Not.To.Equal("true") 42 | expect(map[int]int{}).To.Equal(map[int]int{}) 43 | expect(struct{ X, Y int }{1, 2}).Not.To.Equal(&struct{ X, Y int }{1, 2}) 44 | } 45 | 46 | func TestPanic(t *testing.T) { 47 | expect := expect.New(t) 48 | expect(func() {}).Not.To.Panic() 49 | expect(func() { 50 | panic("foo") 51 | }).To.Panic() 52 | expect(func() { 53 | panic("bar") 54 | }).To.Panic("bar") 55 | } 56 | 57 | func TestToChaining(t *testing.T) { 58 | expect := expect.New(t) 59 | expect("foobarbaz").To.StartWith("foo").And.EndWith("baz").And.Contains("bar") 60 | expect("foo").Not.To.StartWith("bar").And.EndWith("baz").And.Contains("bob") 61 | expect("foo").To.Match("f").And.Match("(?i)F") 62 | } 63 | 64 | func TestToFailNow(t *testing.T) { 65 | mockT := newMockT() 66 | expect := expect.New(mockT) 67 | expect("foo").To.Equal("foo").Else.FailNow() 68 | select { 69 | case <-mockT.FailNowCalled: 70 | t.Errorf("Expected FailNow() on passing test not to be called") 71 | default: 72 | } 73 | expect("foo").To.Equal("bar").Else.FailNow() 74 | select { 75 | case <-mockT.FailNowCalled: 76 | default: 77 | t.Errorf("Expected FailNow() on failing test to be called") 78 | } 79 | } 80 | 81 | func TestNotToFailNow(t *testing.T) { 82 | mockT := newMockT() 83 | expect := expect.New(mockT) 84 | expect("foo").Not.To.Equal("bar").Else.FailNow() 85 | select { 86 | case <-mockT.FailNowCalled: 87 | t.Errorf("Expected FailNow() on passing test not to be called") 88 | default: 89 | } 90 | expect("foo").Not.To.Equal("foo").Else.FailNow() 91 | select { 92 | case <-mockT.FailNowCalled: 93 | default: 94 | t.Errorf("Expected FailNow() on failing test to be called") 95 | } 96 | } 97 | 98 | func TestToAndHaveFailNow(t *testing.T) { 99 | mockT := newMockT() 100 | expect := expect.New(mockT) 101 | expect("foo").To.Equal("bar").And.Have.Len(3).Else.FailNow() 102 | select { 103 | case <-mockT.FailNowCalled: 104 | default: 105 | t.Errorf("Expected FailNow() on failing test to be called") 106 | } 107 | } 108 | 109 | func TestToAndBeFailNow(t *testing.T) { 110 | mockT := newMockT() 111 | expect := expect.New(mockT) 112 | expect("foo").To.Equal("bar").And.Be.String().Else.FailNow() 113 | select { 114 | case <-mockT.FailNowCalled: 115 | default: 116 | t.Errorf("Expected FailNow() on failing test to be called") 117 | } 118 | } 119 | 120 | func TestPassCustomMatcher(t *testing.T) { 121 | mockT := newMockT() 122 | expect := expect.New(mockT) 123 | 124 | mockMatcher := newMockMatcher() 125 | mockMatcher.MatchOutput.Ret0 <- nil 126 | expect("foo").To.Pass(mockMatcher) 127 | select { 128 | case actual := <-mockMatcher.MatchInput.Actual: 129 | if actual != "foo" { 130 | t.Errorf(`Expected matcher to be called with "foo"`) 131 | } 132 | default: 133 | t.Errorf("Expected matcher to be called") 134 | } 135 | select { 136 | case <-mockT.ErrorfInput.Args: 137 | t.Errorf("Expected Errorf() on passing test not to be called") 138 | default: 139 | } 140 | 141 | uniqueError := "I am a unique error" 142 | mockMatcher.MatchOutput.Ret0 <- errors.New(uniqueError) 143 | expect("foo").To.Pass(mockMatcher) 144 | select { 145 | case args := <-mockT.ErrorfInput.Args: 146 | if len(args) != 2 { 147 | t.Fatalf("Expected %#v to have length 2", args) 148 | } 149 | s, ok := args[1].(string) 150 | if !ok { 151 | t.Errorf("Expected arg %#v to be a string", args[1]) 152 | } 153 | if !strings.Contains(s, uniqueError) { 154 | t.Errorf(`Expected message "%s" to contain "%s"`, s, uniqueError) 155 | } 156 | default: 157 | t.Errorf("Expected Errorf() on failing test to be called") 158 | } 159 | } 160 | 161 | func TestNotPassCustomMatcher(t *testing.T) { 162 | mockT := newMockT() 163 | expect := expect.New(mockT) 164 | 165 | mockMatcher := newMockMatcher() 166 | mockMatcher.MatchOutput.Ret0 <- errors.New("foo") 167 | expect("foo").Not.To.Pass(mockMatcher) 168 | select { 169 | case <-mockT.ErrorfInput.Args: 170 | t.Errorf("Expected Errorf() on passing test not to be called") 171 | default: 172 | } 173 | 174 | mockMatcher.MatchOutput.Ret0 <- nil 175 | expect("foo").Not.To.Pass(mockMatcher) 176 | select { 177 | case args := <-mockT.ErrorfInput.Args: 178 | if len(args) != 2 { 179 | t.Fatalf("Expected %#v to have length 2", args) 180 | } 181 | s, ok := args[1].(string) 182 | if !ok { 183 | t.Errorf("Expected arg %#v to be a string", args[1]) 184 | } 185 | if !strings.Contains(s, "match &expect_test.mockMatcher{") { 186 | t.Errorf(`Expected message "%s" to contain "match mockMatcher{"`, s) 187 | } 188 | default: 189 | t.Errorf("Expected Errorf() on failing test to be called") 190 | } 191 | } 192 | --------------------------------------------------------------------------------