├── .circleci └── config.yml ├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── is.go ├── is_test.go └── workers.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Golang CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-go/ for more details 4 | version: 2 5 | jobs: 6 | build: 7 | docker: 8 | - image: circleci/golang:1.13 9 | 10 | working_directory: /go/src/github.com/tylerb/is 11 | steps: 12 | - checkout 13 | 14 | - run: go get -v -t -d ./... 15 | - run: go test -v -race ./... -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Tyler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # is [![GoDev](https://img.shields.io/static/v1?label=godev&message=documentation&color=informational&style=plastic&&url=https://pkg.go.dev/github.com/tylerb/is@v3.0.0?tab=doc)](https://pkg.go.dev/github.com/tylerb/is/v3@v3.0.0?tab=doc) [![Build Status](https://circleci.com/gh/tylerb/is/tree/v3.svg?style=shield&circle-token=94428439ffc6eda6471dc218471dab20985f444c)](https://circleci.com/gh/tylerb/is/tree/v3) 2 | 3 | ## Archived 4 | 5 | `is` has been archived in favor of [Proof](https://github.com/tystil/proof) 6 | 7 | ----------- 8 | 9 | Is provides a quick, clean and simple framework for writing Go tests. 10 | 11 | ## Installation 12 | 13 | To install, simply execute: 14 | 15 | ``` 16 | go get -u github.com/tylerb/is/v3 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```go 22 | func TestSomething(t *testing.T) { 23 | assert := is.New(t) 24 | 25 | expected := 10 26 | actual, _ := awesomeFunction() 27 | assert.Equal(actual, expected) 28 | } 29 | ``` 30 | 31 | If you'd like a bit more information when a test fails, you may use the `Msg()` method: 32 | 33 | ```go 34 | func TestSomething(t *testing.T) { 35 | assert := is.New(t) 36 | 37 | expected := 10 38 | actual, details := awesomeFunction() 39 | assert.Msg("actual details: %s", details).Equal(actual, expected) 40 | } 41 | ``` 42 | 43 | By default, any assertion that fails will halt termination of the test. If you would like to run a group of assertions 44 | in a row, you may use the `Lax` method. This is useful for asserting/printing many values at once, so you can correct 45 | all the issues between test runs. 46 | 47 | ```go 48 | func TestSomething(t *testing.T) { 49 | assert := is.New(t) 50 | 51 | assert.Lax(func (lax Asserter) { 52 | lax.Equal(1, 2) 53 | lax.True(false) 54 | lax.ShouldPanic(func(){}) 55 | }) 56 | } 57 | ``` 58 | 59 | If any of the assertions fail inside that function, an additional error will be printed and test execution will halt. 60 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tylerb/is/v3 2 | 3 | go 1.13 4 | 5 | require github.com/google/go-cmp v0.4.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 2 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 3 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 4 | -------------------------------------------------------------------------------- /is.go: -------------------------------------------------------------------------------- 1 | package is 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "reflect" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | // Equaler is used to define equality for types. 12 | // 13 | // For example, this is useful if you have a struct that includes time.Time 14 | // fields. You can implement this method and use time.Time.Equal() to do the 15 | // comparison. 16 | // 17 | // Deprecated 18 | type Equaler interface { 19 | Equal(in interface{}) bool 20 | } 21 | 22 | // EqualityChecker is used to define equality for types during testing. 23 | // 24 | // For example, this is useful if you have a struct that includes time.Time 25 | // fields. You can implement this method and use time.Time.Equal() to do the 26 | // comparison. 27 | type EqualityChecker interface { 28 | IsEqual(in interface{}) bool 29 | } 30 | 31 | // Asserter provides methods that leverage the existing testing capabilities found 32 | // in the Go test framework. The methods provided allow for a more natural, 33 | // efficient and expressive approach to writing tests. The goal is to write 34 | // fewer lines of code while improving communication of intent. 35 | type Asserter interface { 36 | // tb returns the testing object with which this Asserter was originally 37 | // initialized. 38 | TB() testing.TB 39 | 40 | // Msg defines a message to print in the event of a failure. This allows you 41 | // to print out additional information about a failure if it happens. 42 | Msg(format string, args ...interface{}) Asserter 43 | 44 | // AddMsg appends a message to print in the event of a failure. This allows 45 | // you to build a failure message in multiple steps. If no message was 46 | // previously set, simply sets the message. 47 | // 48 | // This method is most useful as a way of setting a default error message, 49 | // then adding additional information to the output for specific assertions. 50 | // For example: 51 | // 52 | // assert := is.New(t).Msg("User ID: %d",u.ID) 53 | // /*do things*/ 54 | // assert.AddMsg("Raw Response: %s",body).Equal(res.StatusCode, http.StatusCreated) 55 | AddMsg(format string, args ...interface{}) Asserter 56 | 57 | // Equal performs a deep compare of the provided objects and fails if they are 58 | // not equal. 59 | // 60 | // Equal does not respect type differences. If the types are different and 61 | // comparable (eg int32 and int64), they will be compared as though they are 62 | // the same type. 63 | Equal(actual interface{}, expected interface{}) 64 | 65 | // NotEqual performs a deep compare of the provided objects and fails if they are 66 | // equal. 67 | // 68 | // NotEqual does not respect type differences. If the types are different and 69 | // comparable (eg int32 and int64), they will be compared as though they are 70 | // the same type. 71 | NotEqual(a interface{}, b interface{}) 72 | 73 | // OneOf performs a deep compare of the provided object and an array of 74 | // comparison objects. It fails if the first object is not equal to one of the 75 | // comparison objects. 76 | // 77 | // OneOf does not respect type differences. If the types are different and 78 | // comparable (eg int32 and int64), they will be compared as though they are 79 | // the same type. 80 | OneOf(a interface{}, b ...interface{}) 81 | 82 | // NotOneOf performs a deep compare of the provided object and an array of 83 | // comparison objects. It fails if the first object is equal to one of the 84 | // comparison objects. 85 | // 86 | // NotOneOf does not respect type differences. If the types are different and 87 | // comparable (eg int32 and int64), they will be compared as though they are 88 | // the same type. 89 | NotOneOf(a interface{}, b ...interface{}) 90 | 91 | // Err checks the provided error object to determine if an error is present. 92 | Err(e error) 93 | 94 | // NotErr checks the provided error object to determine if an error is not 95 | // present. 96 | NotErr(e error) 97 | 98 | // Nil checks the provided object to determine if it is nil. 99 | Nil(o interface{}) 100 | 101 | // NotNil checks the provided object to determine if it is not nil. 102 | NotNil(o interface{}) 103 | 104 | // True checks the provided boolean to determine if it is true. 105 | True(b bool) 106 | 107 | // False checks the provided boolean to determine if is false. 108 | False(b bool) 109 | 110 | // Zero checks the provided object to determine if it is the zero value 111 | // for the type of that object. The zero value is the same as what the object 112 | // would contain when initialized but not assigned. 113 | // 114 | // This method, for example, would be used to determine if a string is empty, 115 | // an array is empty or a map is empty. It could also be used to determine if 116 | // a number is 0. 117 | // 118 | // In cases such as slice, map, array and chan, a nil value is treated the 119 | // same as an object with len == 0 120 | Zero(o interface{}) 121 | 122 | // NotZero checks the provided object to determine if it is not the zero 123 | // value for the type of that object. The zero value is the same as what the 124 | // object would contain when initialized but not assigned. 125 | // 126 | // This method, for example, would be used to determine if a string is not 127 | // empty, an array is not empty or a map is not empty. It could also be used 128 | // to determine if a number is not 0. 129 | // 130 | // In cases such as slice, map, array and chan, a nil value is treated the 131 | // same as an object with len == 0 132 | NotZero(o interface{}) 133 | 134 | // Len checks the provided object to determine if it is the same length as the 135 | // provided length argument. 136 | // 137 | // If the object is not one of type array, slice or map, it will fail. 138 | Len(o interface{}, l int) 139 | 140 | // ShouldPanic expects the provided function to panic. If the function does 141 | // not panic, this assertion fails. 142 | ShouldPanic(f func()) 143 | 144 | // EqualType checks the type of the two provided objects and 145 | // fails if they are not the same. 146 | EqualType(expected, actual interface{}) 147 | 148 | // WaitForTrue waits until the provided func returns true. If the timeout is 149 | // reached before the function returns true, the test will fail. 150 | WaitForTrue(timeout time.Duration, f func() bool) 151 | 152 | // Lax accepts a function inside which a failed assertion will not halt 153 | // test execution. After the function returns, if any assertion had failed, 154 | // an additional message will be printed and test execution will be halted. 155 | // 156 | // This is useful for running assertions on, for example, many values in a struct 157 | // and having all the failed assertions print in one go, rather than having to run 158 | // the test multiple times, correcting a single failure per run. 159 | Lax(fn func(lax Asserter)) 160 | } 161 | 162 | type asserter struct { 163 | tb testing.TB 164 | strict bool 165 | failFormat string 166 | failArgs []interface{} 167 | failed bool 168 | } 169 | 170 | var _ Asserter = (*asserter)(nil) 171 | 172 | // New returns a new Asserter containing the testing object provided. 173 | func New(tb testing.TB) Asserter { 174 | if tb == nil { 175 | log.Fatalln("You must provide a testing object.") 176 | } 177 | return &asserter{tb: tb, strict: true} 178 | } 179 | 180 | func (self *asserter) TB() testing.TB { 181 | return self.tb 182 | } 183 | 184 | // Msg defines a message to print in the event of a failure. This allows you 185 | // to print out additional information about a failure if it happens. 186 | func (self *asserter) Msg(format string, args ...interface{}) Asserter { 187 | return &asserter{ 188 | tb: self.tb, 189 | strict: self.strict, 190 | failFormat: format, 191 | failArgs: args, 192 | } 193 | } 194 | 195 | func (self *asserter) AddMsg(format string, args ...interface{}) Asserter { 196 | if self.failFormat == "" { 197 | return self.Msg(format, args...) 198 | } 199 | return &asserter{ 200 | tb: self.tb, 201 | strict: self.strict, 202 | failFormat: fmt.Sprintf("%s - %s", self.failFormat, format), 203 | failArgs: append(self.failArgs, args...), 204 | } 205 | } 206 | 207 | func (self *asserter) Equal(actual interface{}, expected interface{}) { 208 | self.tb.Helper() 209 | if !isEqual(actual, expected) { 210 | fail(self, "actual value '%v' (%s) should be equal to expected value '%v' (%s)%s", 211 | actual, objectTypeName(actual), 212 | expected, objectTypeName(expected), 213 | diff(actual, expected), 214 | ) 215 | } 216 | } 217 | 218 | func (self *asserter) NotEqual(actual interface{}, expected interface{}) { 219 | self.tb.Helper() 220 | if isEqual(actual, expected) { 221 | fail(self, "actual value '%v' (%s) should not be equal to expected value '%v' (%s)", 222 | actual, objectTypeName(actual), 223 | expected, objectTypeName(expected)) 224 | } 225 | } 226 | 227 | func (self *asserter) OneOf(a interface{}, b ...interface{}) { 228 | self.tb.Helper() 229 | result := false 230 | for _, o := range b { 231 | result = isEqual(a, o) 232 | if result { 233 | break 234 | } 235 | } 236 | if !result { 237 | fail(self, "expected object '%s' to be equal to one of '%s', but got: %v and %v", 238 | objectTypeName(a), 239 | objectTypeNames(b), a, b) 240 | } 241 | } 242 | 243 | func (self *asserter) NotOneOf(a interface{}, b ...interface{}) { 244 | self.tb.Helper() 245 | result := false 246 | for _, o := range b { 247 | result = isEqual(a, o) 248 | if result { 249 | break 250 | } 251 | } 252 | if result { 253 | fail(self, "expected object '%s' not to be equal to one of '%s', but got: %v and %v", 254 | objectTypeName(a), 255 | objectTypeNames(b), a, b) 256 | } 257 | } 258 | 259 | func (self *asserter) Err(err error) { 260 | self.tb.Helper() 261 | if isNil(err) { 262 | fail(self, "expected error") 263 | } 264 | } 265 | 266 | func (self *asserter) NotErr(err error) { 267 | self.tb.Helper() 268 | if !isNil(err) { 269 | fail(self, "expected no error, but got: %v", err) 270 | } 271 | } 272 | 273 | func (self *asserter) Nil(o interface{}) { 274 | self.tb.Helper() 275 | if !isNil(o) { 276 | fail(self, "expected object '%s' to be nil, but got: %v", objectTypeName(o), o) 277 | } 278 | } 279 | 280 | func (self *asserter) NotNil(o interface{}) { 281 | self.tb.Helper() 282 | if isNil(o) { 283 | fail(self, "expected object '%s' not to be nil", objectTypeName(o)) 284 | } 285 | } 286 | 287 | func (self *asserter) True(b bool) { 288 | self.tb.Helper() 289 | if !b { 290 | fail(self, "expected boolean to be true") 291 | } 292 | } 293 | 294 | func (self *asserter) False(b bool) { 295 | self.tb.Helper() 296 | if b { 297 | fail(self, "expected boolean to be false") 298 | } 299 | } 300 | 301 | func (self *asserter) Zero(o interface{}) { 302 | self.tb.Helper() 303 | if !isZero(o) { 304 | fail(self, "expected object '%s' to be zero value, but it was: %v", objectTypeName(o), o) 305 | } 306 | } 307 | 308 | func (self *asserter) NotZero(o interface{}) { 309 | self.tb.Helper() 310 | if isZero(o) { 311 | fail(self, "expected object '%s' not to be zero value", objectTypeName(o)) 312 | } 313 | } 314 | 315 | func (self *asserter) Len(obj interface{}, length int) { 316 | self.tb.Helper() 317 | t := reflect.TypeOf(obj) 318 | if obj == nil || 319 | (t.Kind() != reflect.Array && 320 | t.Kind() != reflect.Slice && 321 | t.Kind() != reflect.Map) { 322 | fail(self, "expected object '%s' to be of length '%d', but the object is not one of array, slice or map", objectTypeName(obj), length) 323 | return 324 | } 325 | 326 | rLen := reflect.ValueOf(obj).Len() 327 | if rLen != length { 328 | fail(self, "expected object '%s' to be of length '%d' but it was: %d", objectTypeName(obj), length, rLen) 329 | } 330 | } 331 | 332 | func (self *asserter) ShouldPanic(fn func()) { 333 | self.tb.Helper() 334 | defer func() { 335 | r := recover() 336 | if r == nil { 337 | fail(self, "expected function to panic") 338 | } 339 | }() 340 | fn() 341 | } 342 | 343 | func (self *asserter) EqualType(expected, actual interface{}) { 344 | self.tb.Helper() 345 | if reflect.TypeOf(expected) != reflect.TypeOf(actual) { 346 | fail(self, "expected objects '%s' to be of the same type as object '%s'", objectTypeName(expected), objectTypeName(actual)) 347 | } 348 | } 349 | 350 | func (self *asserter) WaitForTrue(timeout time.Duration, f func() bool) { 351 | self.tb.Helper() 352 | after := time.After(timeout) 353 | for { 354 | select { 355 | case <-after: 356 | fail(self, "function did not return true within the timeout of %v", timeout) 357 | return 358 | default: 359 | if f() { 360 | return 361 | } 362 | time.Sleep(100 * time.Millisecond) 363 | } 364 | } 365 | } 366 | 367 | func (self *asserter) Lax(fn func(lax Asserter)) { 368 | lax := &asserter{ 369 | tb: self.tb, 370 | strict: false, 371 | failFormat: self.failFormat, 372 | failArgs: self.failArgs, 373 | failed: false, 374 | } 375 | 376 | fn(lax) 377 | 378 | if lax.failed { 379 | fail(self, "at least one assertion in the Lax function failed") 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /is_test.go: -------------------------------------------------------------------------------- 1 | package is 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | var numberTypes = []reflect.Type{ 12 | reflect.TypeOf(int(0)), 13 | reflect.TypeOf(int8(0)), 14 | reflect.TypeOf(int16(0)), 15 | reflect.TypeOf(int32(0)), 16 | reflect.TypeOf(int64(0)), 17 | reflect.TypeOf(uint(0)), 18 | reflect.TypeOf(uint8(0)), 19 | reflect.TypeOf(uint16(0)), 20 | reflect.TypeOf(uint32(0)), 21 | reflect.TypeOf(uint64(0)), 22 | reflect.TypeOf(float32(0)), 23 | reflect.TypeOf(float64(0)), 24 | } 25 | 26 | type testStruct struct { 27 | v int 28 | } 29 | 30 | var tests = []struct { 31 | a interface{} 32 | b interface{} 33 | c interface{} 34 | d interface{} 35 | e interface{} 36 | cTypes []reflect.Type 37 | }{ 38 | { 39 | a: 0, 40 | b: 0, 41 | c: 1, 42 | d: 0, 43 | e: 1, 44 | cTypes: numberTypes, 45 | }, 46 | { 47 | a: "test", 48 | b: "test", 49 | c: "testing", 50 | d: "", 51 | e: "testing", 52 | }, 53 | { 54 | a: struct{}{}, 55 | b: struct{}{}, 56 | c: struct{ v int }{v: 1}, 57 | d: testStruct{}, 58 | e: testStruct{v: 1}, 59 | }, 60 | { 61 | a: &struct{}{}, 62 | b: &struct{}{}, 63 | c: &struct{ v int }{v: 1}, 64 | d: &testStruct{}, 65 | e: &testStruct{v: 1}, 66 | }, 67 | { 68 | a: []int64{0, 1}, 69 | b: []int64{0, 1}, 70 | c: []int64{0, 2}, 71 | d: []int64{}, 72 | e: []int64{0, 2}, 73 | }, 74 | { 75 | a: map[string]int64{"answer": 42}, 76 | b: map[string]int64{"answer": 42}, 77 | c: map[string]int64{"answer": 43}, 78 | d: map[string]int64{}, 79 | e: map[string]int64{"answer": 42}, 80 | }, 81 | { 82 | a: true, 83 | b: true, 84 | c: false, 85 | d: false, 86 | e: true, 87 | }, 88 | } 89 | 90 | func Test(t *testing.T) { 91 | assert := New(t) 92 | 93 | for i, test := range tests { 94 | for _, cType := range test.cTypes { 95 | fail = func(is *asserter, format string, args ...interface{}) { 96 | fmt.Print(fmt.Sprintf(fmt.Sprintf("(test #%d) - ", i)+format, args...)) 97 | t.FailNow() 98 | } 99 | assert.Equal(test.a, reflect.ValueOf(test.b).Convert(cType).Interface()) 100 | } 101 | assert.Equal(test.a, test.b) 102 | } 103 | 104 | for i, test := range tests { 105 | for _, cType := range test.cTypes { 106 | fail = func(is *asserter, format string, args ...interface{}) { 107 | fmt.Print(fmt.Sprintf(fmt.Sprintf("(test #%d) - ", i)+format, args...)) 108 | t.FailNow() 109 | } 110 | assert.NotEqual(test.a, reflect.ValueOf(test.c).Convert(cType).Interface()) 111 | } 112 | assert.NotEqual(test.a, test.c) 113 | } 114 | 115 | for i, test := range tests { 116 | for _, cType := range test.cTypes { 117 | fail = func(is *asserter, format string, args ...interface{}) { 118 | fmt.Print(fmt.Sprintf(fmt.Sprintf("(test #%d) - ", i)+format, args...)) 119 | t.FailNow() 120 | } 121 | assert.Zero(reflect.ValueOf(test.d).Convert(cType).Interface()) 122 | } 123 | assert.Zero(test.d) 124 | } 125 | 126 | for i, test := range tests { 127 | for _, cType := range test.cTypes { 128 | fail = func(is *asserter, format string, args ...interface{}) { 129 | fmt.Print(fmt.Sprintf(fmt.Sprintf("(test #%d) - ", i)+format, args...)) 130 | t.FailNow() 131 | } 132 | assert.NotZero(reflect.ValueOf(test.e).Convert(cType).Interface()) 133 | } 134 | assert.NotZero(test.e) 135 | } 136 | 137 | fail = func(is *asserter, format string, args ...interface{}) { 138 | fmt.Print(fmt.Sprintf(format, args...)) 139 | t.FailNow() 140 | } 141 | assert.Nil(nil) 142 | assert.NotNil(&testStruct{v: 1}) 143 | assert.Err(errors.New("error")) 144 | assert.NotErr(nil) 145 | assert.True(true) 146 | assert.False(false) 147 | assert.Zero(nil) 148 | assert.Nil((*testStruct)(nil)) 149 | assert.OneOf(1, 2, 3, 1) 150 | assert.NotOneOf(1, 2, 3) 151 | 152 | lens := []interface{}{ 153 | []int{1, 2, 3}, 154 | [3]int{1, 2, 3}, 155 | map[int]int{1: 1, 2: 2, 3: 3}, 156 | } 157 | for _, l := range lens { 158 | assert.Len(l, 3) 159 | } 160 | 161 | fail = func(is *asserter, format string, args ...interface{}) {} 162 | assert.Equal((*testStruct)(nil), &testStruct{}) 163 | assert.Equal(&testStruct{}, (*testStruct)(nil)) 164 | assert.Equal((*testStruct)(nil), (*testStruct)(nil)) 165 | 166 | fail = func(is *asserter, format string, args ...interface{}) { 167 | fmt.Print(fmt.Sprintf(format, args...)) 168 | t.FailNow() 169 | } 170 | assert.ShouldPanic(func() { 171 | panic("The sky is falling!") 172 | }) 173 | } 174 | 175 | func TestMsg(t *testing.T) { 176 | assert := New(t) 177 | 178 | assert = assert.Msg("something %s", "else") 179 | if assert.(*asserter).failFormat != "something %s" { 180 | t.Fatal("failFormat not set") 181 | } 182 | if assert.(*asserter).failArgs[0].(string) != "else" { 183 | t.Fatal("failArgs not set") 184 | } 185 | 186 | assert = assert.AddMsg("another %s %s", "couple", "things") 187 | if assert.(*asserter).failFormat != "something %s - another %s %s" { 188 | t.Fatal("failFormat not set") 189 | } 190 | if assert.(*asserter).failArgs[0].(string) != "else" { 191 | t.Fatal("failArgs not set") 192 | } 193 | if assert.(*asserter).failArgs[1].(string) != "couple" { 194 | t.Fatal("failArgs not set") 195 | } 196 | if assert.(*asserter).failArgs[2].(string) != "things" { 197 | t.Fatal("failArgs not set") 198 | } 199 | } 200 | 201 | func TestLaxNoFailure(t *testing.T) { 202 | assert := New(t) 203 | 204 | hit := 0 205 | 206 | fail = func(is *asserter, format string, args ...interface{}) { 207 | hit++ 208 | } 209 | 210 | assert.Lax(func(lax Asserter) { 211 | lax.Equal(1, 1) 212 | }) 213 | 214 | fail = failDefault 215 | 216 | assert.Equal(hit, 0) 217 | } 218 | 219 | func TestLaxFailure(t *testing.T) { 220 | assert := New(t) 221 | 222 | hitLax := 0 223 | hitStrict := 0 224 | 225 | fail = func(is *asserter, format string, args ...interface{}) { 226 | if is.strict { 227 | hitStrict++ 228 | return 229 | } 230 | is.failed = true 231 | hitLax++ 232 | } 233 | 234 | assert.Lax(func(lax Asserter) { 235 | lax.Equal(1, 2) 236 | }) 237 | 238 | fail = failDefault 239 | 240 | assert.Equal(hitLax, 1) 241 | assert.Equal(hitStrict, 1) 242 | } 243 | 244 | func TestOneOf(t *testing.T) { 245 | assert := New(t) 246 | 247 | hit := 0 248 | fail = func(is *asserter, format string, args ...interface{}) { 249 | hit++ 250 | } 251 | assert.OneOf(2, 1, 2, 3) 252 | assert.OneOf(4, 1, 2, 3) 253 | assert.NotOneOf(2, 1, 2, 3) 254 | assert.NotOneOf(4, 1, 2, 3) 255 | 256 | fail = failDefault 257 | assert.Equal(hit, 2) 258 | } 259 | 260 | func TestFailures(t *testing.T) { 261 | assert := New(t) 262 | 263 | hit := 0 264 | fail = func(is *asserter, format string, args ...interface{}) { 265 | hit++ 266 | } 267 | 268 | assert.NotEqual(1, 1) 269 | assert.Err(nil) 270 | assert.NotErr(errors.New("error")) 271 | assert.Nil(&hit) 272 | assert.NotNil(nil) 273 | assert.True(false) 274 | assert.False(true) 275 | assert.Zero(1) 276 | assert.NotZero(0) 277 | assert.Len([]int{}, 1) 278 | assert.Len(nil, 1) 279 | assert.ShouldPanic(func() {}) 280 | 281 | fail = failDefault 282 | assert.Equal(hit, 12) 283 | } 284 | 285 | func TestWaitForTrue(t *testing.T) { 286 | assert := New(t) 287 | 288 | hit := 0 289 | fail = func(is *asserter, format string, args ...interface{}) { 290 | hit++ 291 | } 292 | 293 | assert.WaitForTrue(200*time.Millisecond, func() bool { 294 | return false 295 | }) 296 | assert.Equal(hit, 1) 297 | 298 | assert.WaitForTrue(200*time.Millisecond, func() bool { 299 | return true 300 | }) 301 | assert.Equal(hit, 1) 302 | } 303 | 304 | type equaler struct { 305 | equal bool 306 | called bool 307 | } 308 | 309 | func (e *equaler) Equal(in interface{}) bool { 310 | e.called = true 311 | v, ok := in.(*equaler) 312 | if !ok { 313 | return false 314 | } 315 | return e.equal == v.equal 316 | } 317 | 318 | func TestEqualer(t *testing.T) { 319 | assert := New(t) 320 | 321 | hit := 0 322 | fail = func(is *asserter, format string, args ...interface{}) { 323 | hit++ 324 | } 325 | 326 | a := &equaler{equal: true} 327 | b := &equaler{} 328 | 329 | assert.Equal(a, b) 330 | if !a.called { 331 | t.Fatalf("a.Equal should have been called") 332 | } 333 | 334 | assert.Equal(b, a) 335 | if !b.called { 336 | t.Fatalf("b.Equal should have been called") 337 | } 338 | 339 | if hit != 2 { 340 | t.Fatalf("fail func should have been called 2 times, but was called %d times", hit) 341 | } 342 | 343 | a.called = false 344 | b.called = false 345 | b.equal = true 346 | hit = 0 347 | 348 | assert.NotEqual(a, b) 349 | if !a.called { 350 | t.Fatalf("a.Equal should have been called") 351 | } 352 | 353 | assert.NotEqual(b, a) 354 | if !b.called { 355 | t.Fatalf("b.Equal should have been called") 356 | } 357 | 358 | if hit != 2 { 359 | t.Fatalf("fail func should have been called 2 times, but was called %d times", hit) 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /workers.go: -------------------------------------------------------------------------------- 1 | package is 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/google/go-cmp/cmp" 10 | ) 11 | 12 | func objectTypeName(o interface{}) string { 13 | return fmt.Sprintf("%T", o) 14 | } 15 | 16 | func objectTypeNames(o []interface{}) string { 17 | if o == nil { 18 | return objectTypeName(o) 19 | } 20 | if len(o) == 1 { 21 | return objectTypeName(o[0]) 22 | } 23 | var b bytes.Buffer 24 | b.WriteString(objectTypeName(o[0])) 25 | for _, e := range o[1:] { 26 | b.WriteString(",") 27 | b.WriteString(objectTypeName(e)) 28 | } 29 | return b.String() 30 | } 31 | 32 | func isNil(o interface{}) bool { 33 | if o == nil { 34 | return true 35 | } 36 | value := reflect.ValueOf(o) 37 | kind := value.Kind() 38 | if kind >= reflect.Chan && 39 | kind <= reflect.Slice && 40 | value.IsNil() { 41 | return true 42 | } 43 | return false 44 | } 45 | 46 | func isZero(o interface{}) bool { 47 | if o == nil { 48 | return true 49 | } 50 | v := reflect.ValueOf(o) 51 | switch v.Kind() { 52 | case reflect.Ptr: 53 | return reflect.DeepEqual(o, 54 | reflect.New(v.Type().Elem()).Interface()) 55 | case reflect.Slice, reflect.Array, reflect.Map, reflect.Chan: 56 | if v.Len() == 0 { 57 | return true 58 | } 59 | return false 60 | default: 61 | return reflect.DeepEqual(o, 62 | reflect.Zero(v.Type()).Interface()) 63 | } 64 | } 65 | 66 | func isEqual(a interface{}, b interface{}) bool { 67 | if isNil(a) || isNil(b) { 68 | if isNil(a) && !isNil(b) { 69 | return false 70 | } 71 | if !isNil(a) && isNil(b) { 72 | return false 73 | } 74 | return a == b 75 | } 76 | 77 | // Call a.Equaler if it is implemented 78 | if e, ok := a.(Equaler); ok { 79 | return e.Equal(b) 80 | } 81 | 82 | // Call a.EqualityChecker if it is implemented 83 | if e, ok := a.(EqualityChecker); ok { 84 | return e.IsEqual(b) 85 | } 86 | 87 | if reflect.DeepEqual(a, b) { 88 | return true 89 | } 90 | 91 | aValue := reflect.ValueOf(a) 92 | bValue := reflect.ValueOf(b) 93 | // Convert types and compare 94 | if bValue.Type().ConvertibleTo(aValue.Type()) { 95 | return reflect.DeepEqual(a, bValue.Convert(aValue.Type()).Interface()) 96 | } 97 | 98 | return false 99 | } 100 | 101 | // fail is a function variable that is called by test functions when they 102 | // fail. It is overridden in test code for this package. 103 | var fail = failDefault 104 | 105 | // failDefault is the default failure function. 106 | func failDefault(is *asserter, format string, args ...interface{}) { 107 | is.tb.Helper() 108 | 109 | is.failed = true 110 | 111 | failFmt := format 112 | if len(is.failFormat) != 0 { 113 | failFmt = fmt.Sprintf("%s - %s", format, is.failFormat) 114 | args = append(args, is.failArgs...) 115 | } 116 | if is.strict { 117 | is.tb.Fatalf(failFmt, args...) 118 | } else { 119 | is.tb.Errorf(failFmt, args...) 120 | } 121 | } 122 | 123 | func diff(actual interface{}, expected interface{}) string { 124 | aKind := reflect.TypeOf(actual).Kind() 125 | eKind := reflect.TypeOf(expected).Kind() 126 | if aKind != eKind { 127 | return "" 128 | } 129 | if aKind != reflect.Slice && aKind != reflect.Map { 130 | return "" 131 | } 132 | f := func(src, dest interface{}) bool { 133 | bytes, err := json.Marshal(src) 134 | if err != nil { 135 | return false 136 | } 137 | err = json.Unmarshal(bytes, &dest) 138 | if err != nil { 139 | return false 140 | } 141 | return true 142 | } 143 | var s string 144 | switch aKind { 145 | case reflect.Slice: 146 | var aSlice []interface{} 147 | var eSlice []interface{} 148 | if !f(actual, &aSlice) { 149 | return "" 150 | } 151 | if !f(expected, &eSlice) { 152 | return "" 153 | } 154 | s = cmp.Diff(aSlice, eSlice) 155 | case reflect.Map: 156 | var aMap map[interface{}]interface{} 157 | var eMap map[interface{}]interface{} 158 | if !f(actual, &aMap) { 159 | return "" 160 | } 161 | if !f(expected, &eMap) { 162 | return "" 163 | } 164 | s = cmp.Diff(aMap, eMap) 165 | default: 166 | return "" 167 | } 168 | if s != "" { 169 | return " - Diff:\n" + s 170 | } 171 | return "" 172 | } 173 | --------------------------------------------------------------------------------