├── .envrc ├── .github └── images │ └── bmc-button.png ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── assertion_compare.go ├── assertion_format.go ├── assertion_order.go ├── assertions.go ├── codegen.sh ├── doc.go ├── errors.go ├── extra.go ├── flake.lock ├── flake.nix ├── go.mod ├── go.sum ├── http_assertions.go ├── prod_assertion_compare.go ├── prod_assertion_format.go ├── prod_assertion_order.go ├── prod_assertions.go ├── prod_errors.go ├── prod_extra.go ├── prod_http_assertions.go └── tests └── assertions_test.go /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/images/bmc-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrel/assert/dcf77153b52ead32375afd500bd546a951d38a48/.github/images/bmc-button.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .direnv/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "testify"] 2 | path = testify 3 | url = https://github.com/stretchr/testify.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alexandre Negrel 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: codegen 2 | codegen: 3 | ./codegen.sh 4 | 5 | .PHONY: clear 6 | clear: 7 | rm -f ./*assertion*.go ./prod_* 8 | 9 | .PHONY: lint 10 | lint: 11 | shellcheck ./codegen.sh 12 | 13 | .PHONY: test 14 | test: 15 | go test -tags assert -v ./... 16 | 17 | .PHONY: bench 18 | bench: bench/assert bench/noassert 19 | 20 | .PHONY: bench/noassert 21 | bench/noassert: 22 | @echo "ASSERTIONS DISABLED" 23 | go test -bench=. -run=^$$ -v ./... 24 | 25 | .PHONY: bench/assert 26 | bench/assert: 27 | @echo "ASSERTIONS ENABLED" 28 | go test -bench=. -run=^$$ -tags assert -v ./... 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | gopher illustration 3 |

4 | 5 |

6 | 7 | PkgGoDev 8 | 9 | 10 | Go Report Card 11 | 12 |

13 | 14 | # `assert` - Zero cost debug assertions. 15 | 16 | This package provides zero cost debug assertions to your Go programs. It is based 17 | on the excellent [`github.com/stretchr/testify/assert`](https://github.com/stretchr/testify) 18 | package and provide the same API (minus `t testing.T` parameter). 19 | 20 | ## Why? 21 | 22 | This is a complete rewrite of [`debuggo`](https://github.com/negrel/debuggo) that aims 23 | to be up to date and more maintainable. 24 | 25 | It aims to provide the same API as [`github.com/stretchr/testify/assert`](https://github.com/stretchr/testify). 26 | * Prints friendly, easy to read failure descriptions 27 | * Allows for very readable code 28 | * Optionally annotate each assertion with a message 29 | * No performance impact on production build (see benchmarks) 30 | 31 | Debug assertions main use is to assert invariant that can't be encoded in the 32 | type systems. For example, a method that should be called only when mutex is 33 | locked: 34 | 35 | ```go 36 | package mypkg 37 | 38 | import ( 39 | "sync" 40 | "github.com/negrel/assert" 41 | ) 42 | 43 | type myType struct { 44 | mu sync.Mutex 45 | // other fields... 46 | } 47 | 48 | // doWork perform internal work. Caller must hold mutex while calling this 49 | // function. 50 | func (mt *myType) doWork(k string) { 51 | assert.Locked(&mt.mu) // panic if assertions are enabled and mutex isn't locked 52 | 53 | // Do work... 54 | } 55 | ``` 56 | 57 | ## How does it works? 58 | 59 | [Read my blog post](https://www.negrel.dev/blog/zero-cost-debug-assertions-in-go/) 60 | about to understand how `assert` works and why it is designed that way. 61 | 62 | ## Getting started 63 | 64 | Here is our example program: 65 | 66 | ```go 67 | package main 68 | 69 | import ( 70 | "github.com/negrel/assert" 71 | ) 72 | 73 | func main() { 74 | assert.True(false) 75 | println("Hello world!") 76 | } 77 | ``` 78 | 79 | A simple `go run .` will simply print `Hello world!` as all `assert` functions 80 | are removed by the compiler. 81 | 82 | Now, if we compile and run it with assertions enabled `go run -tags assert .`, 83 | it will output something like: 84 | 85 | ``` 86 | panic: 87 | Error Trace: /home/anegrel/code/go/assert/example/main.go:8 88 | /usr/share/go/src/runtime/proc.go:267 89 | /usr/share/go/src/runtime/asm_amd64.s:1650 90 | Error: Should be true 91 | 92 | 93 | goroutine 1 [running]: 94 | github.com/negrel/assert.Fail({0x568dc2, 0xe}, {0x0, 0x0, 0x0}) 95 | /home/anegrel/code/go/assert/assertions.go:349 +0x168 96 | github.com/negrel/assert.True(...) 97 | /home/anegrel/code/go/assert/assertions.go:754 98 | main.main() 99 | /home/anegrel/code/go/assert/example/main.go:8 +0x27 100 | exit status 2 101 | ``` 102 | 103 | Note that most `go` subcommands (build, run, test, ...) supports `-tags` flag. 104 | You may want to set `GOFLAGS` environment variable to `-tags assert` make it 105 | permanent and avoid specifying it on each command. 106 | 107 | ## Benchmarks 108 | 109 | As we've seen previously, assertions are hidden behind a compilation flag. If 110 | the flag is absent, all assertions functions will be empty/noop function that 111 | the compiler will optimize. 112 | 113 | **WITH** `-tags assert`: 114 | 115 | ``` 116 | goos: linux 117 | goarch: amd64 118 | pkg: github.com/negrel/assert/tests 119 | cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz 120 | BenchmarkSliceIndexWithoutBoundCheckAssertions 121 | BenchmarkSliceIndexWithoutBoundCheckAssertions-8 728439501 1.407 ns/op 122 | BenchmarkSliceIndexWithBoundCheckAssertions 123 | BenchmarkSliceIndexWithBoundCheckAssertions-8 27423670 40.80 ns/op 124 | PASS 125 | ok github.com/negrel/assert/tests 3.338s 126 | ``` 127 | 128 | **WITHOUT** `-tags assert`: 129 | 130 | ``` 131 | goos: linux 132 | goarch: amd64 133 | pkg: github.com/negrel/assert/tests 134 | cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz 135 | BenchmarkSliceIndexWithoutBoundCheckAssertions 136 | BenchmarkSliceIndexWithoutBoundCheckAssertions-8 772181695 1.399 ns/op 137 | BenchmarkSliceIndexWithBoundCheckAssertions 138 | BenchmarkSliceIndexWithBoundCheckAssertions-8 802181890 1.412 ns/op 139 | PASS 140 | ok github.com/negrel/assert/tests 2.531s 141 | ``` 142 | 143 | However, keep in mind that `assert` may slightly increase binary size (~100 KiB) 144 | as it imports `net/http` and `reflect`. 145 | 146 | ## Contributing 147 | 148 | If you want to contribute to `assert` to add a feature or improve the code contact 149 | me at [negrel.dev@protonmail.com](mailto:negrel.dev@protonmail.com), open an 150 | [issue](https://github.com/negrel/assert/issues) or make a 151 | [pull request](https://github.com/negrel/assert/pulls). 152 | 153 | ## :stars: Show your support 154 | 155 | Please give a :star: if this project helped you! 156 | 157 | [![buy me a coffee](.github/images/bmc-button.png)](https://www.buymeacoffee.com/negrel) 158 | 159 | ## :scroll: License 160 | 161 | MIT © [Alexandre Negrel](https://www.negrel.dev/) 162 | -------------------------------------------------------------------------------- /assertion_compare.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "reflect" 9 | "time" 10 | ) 11 | 12 | // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it. 13 | type CompareType = compareResult 14 | 15 | type compareResult int 16 | 17 | const ( 18 | compareLess compareResult = iota - 1 19 | compareEqual 20 | compareGreater 21 | ) 22 | 23 | var ( 24 | intType = reflect.TypeOf(int(1)) 25 | int8Type = reflect.TypeOf(int8(1)) 26 | int16Type = reflect.TypeOf(int16(1)) 27 | int32Type = reflect.TypeOf(int32(1)) 28 | int64Type = reflect.TypeOf(int64(1)) 29 | 30 | uintType = reflect.TypeOf(uint(1)) 31 | uint8Type = reflect.TypeOf(uint8(1)) 32 | uint16Type = reflect.TypeOf(uint16(1)) 33 | uint32Type = reflect.TypeOf(uint32(1)) 34 | uint64Type = reflect.TypeOf(uint64(1)) 35 | 36 | uintptrType = reflect.TypeOf(uintptr(1)) 37 | 38 | float32Type = reflect.TypeOf(float32(1)) 39 | float64Type = reflect.TypeOf(float64(1)) 40 | 41 | stringType = reflect.TypeOf("") 42 | 43 | timeType = reflect.TypeOf(time.Time{}) 44 | bytesType = reflect.TypeOf([]byte{}) 45 | ) 46 | 47 | func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) { 48 | obj1Value := reflect.ValueOf(obj1) 49 | obj2Value := reflect.ValueOf(obj2) 50 | 51 | // throughout this switch we try and avoid calling .Convert() if possible, 52 | // as this has a pretty big performance impact 53 | switch kind { 54 | case reflect.Int: 55 | { 56 | intobj1, ok := obj1.(int) 57 | if !ok { 58 | intobj1 = obj1Value.Convert(intType).Interface().(int) 59 | } 60 | intobj2, ok := obj2.(int) 61 | if !ok { 62 | intobj2 = obj2Value.Convert(intType).Interface().(int) 63 | } 64 | if intobj1 > intobj2 { 65 | return compareGreater, true 66 | } 67 | if intobj1 == intobj2 { 68 | return compareEqual, true 69 | } 70 | if intobj1 < intobj2 { 71 | return compareLess, true 72 | } 73 | } 74 | case reflect.Int8: 75 | { 76 | int8obj1, ok := obj1.(int8) 77 | if !ok { 78 | int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) 79 | } 80 | int8obj2, ok := obj2.(int8) 81 | if !ok { 82 | int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) 83 | } 84 | if int8obj1 > int8obj2 { 85 | return compareGreater, true 86 | } 87 | if int8obj1 == int8obj2 { 88 | return compareEqual, true 89 | } 90 | if int8obj1 < int8obj2 { 91 | return compareLess, true 92 | } 93 | } 94 | case reflect.Int16: 95 | { 96 | int16obj1, ok := obj1.(int16) 97 | if !ok { 98 | int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) 99 | } 100 | int16obj2, ok := obj2.(int16) 101 | if !ok { 102 | int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) 103 | } 104 | if int16obj1 > int16obj2 { 105 | return compareGreater, true 106 | } 107 | if int16obj1 == int16obj2 { 108 | return compareEqual, true 109 | } 110 | if int16obj1 < int16obj2 { 111 | return compareLess, true 112 | } 113 | } 114 | case reflect.Int32: 115 | { 116 | int32obj1, ok := obj1.(int32) 117 | if !ok { 118 | int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) 119 | } 120 | int32obj2, ok := obj2.(int32) 121 | if !ok { 122 | int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) 123 | } 124 | if int32obj1 > int32obj2 { 125 | return compareGreater, true 126 | } 127 | if int32obj1 == int32obj2 { 128 | return compareEqual, true 129 | } 130 | if int32obj1 < int32obj2 { 131 | return compareLess, true 132 | } 133 | } 134 | case reflect.Int64: 135 | { 136 | int64obj1, ok := obj1.(int64) 137 | if !ok { 138 | int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) 139 | } 140 | int64obj2, ok := obj2.(int64) 141 | if !ok { 142 | int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) 143 | } 144 | if int64obj1 > int64obj2 { 145 | return compareGreater, true 146 | } 147 | if int64obj1 == int64obj2 { 148 | return compareEqual, true 149 | } 150 | if int64obj1 < int64obj2 { 151 | return compareLess, true 152 | } 153 | } 154 | case reflect.Uint: 155 | { 156 | uintobj1, ok := obj1.(uint) 157 | if !ok { 158 | uintobj1 = obj1Value.Convert(uintType).Interface().(uint) 159 | } 160 | uintobj2, ok := obj2.(uint) 161 | if !ok { 162 | uintobj2 = obj2Value.Convert(uintType).Interface().(uint) 163 | } 164 | if uintobj1 > uintobj2 { 165 | return compareGreater, true 166 | } 167 | if uintobj1 == uintobj2 { 168 | return compareEqual, true 169 | } 170 | if uintobj1 < uintobj2 { 171 | return compareLess, true 172 | } 173 | } 174 | case reflect.Uint8: 175 | { 176 | uint8obj1, ok := obj1.(uint8) 177 | if !ok { 178 | uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) 179 | } 180 | uint8obj2, ok := obj2.(uint8) 181 | if !ok { 182 | uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) 183 | } 184 | if uint8obj1 > uint8obj2 { 185 | return compareGreater, true 186 | } 187 | if uint8obj1 == uint8obj2 { 188 | return compareEqual, true 189 | } 190 | if uint8obj1 < uint8obj2 { 191 | return compareLess, true 192 | } 193 | } 194 | case reflect.Uint16: 195 | { 196 | uint16obj1, ok := obj1.(uint16) 197 | if !ok { 198 | uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) 199 | } 200 | uint16obj2, ok := obj2.(uint16) 201 | if !ok { 202 | uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) 203 | } 204 | if uint16obj1 > uint16obj2 { 205 | return compareGreater, true 206 | } 207 | if uint16obj1 == uint16obj2 { 208 | return compareEqual, true 209 | } 210 | if uint16obj1 < uint16obj2 { 211 | return compareLess, true 212 | } 213 | } 214 | case reflect.Uint32: 215 | { 216 | uint32obj1, ok := obj1.(uint32) 217 | if !ok { 218 | uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) 219 | } 220 | uint32obj2, ok := obj2.(uint32) 221 | if !ok { 222 | uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) 223 | } 224 | if uint32obj1 > uint32obj2 { 225 | return compareGreater, true 226 | } 227 | if uint32obj1 == uint32obj2 { 228 | return compareEqual, true 229 | } 230 | if uint32obj1 < uint32obj2 { 231 | return compareLess, true 232 | } 233 | } 234 | case reflect.Uint64: 235 | { 236 | uint64obj1, ok := obj1.(uint64) 237 | if !ok { 238 | uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) 239 | } 240 | uint64obj2, ok := obj2.(uint64) 241 | if !ok { 242 | uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) 243 | } 244 | if uint64obj1 > uint64obj2 { 245 | return compareGreater, true 246 | } 247 | if uint64obj1 == uint64obj2 { 248 | return compareEqual, true 249 | } 250 | if uint64obj1 < uint64obj2 { 251 | return compareLess, true 252 | } 253 | } 254 | case reflect.Float32: 255 | { 256 | float32obj1, ok := obj1.(float32) 257 | if !ok { 258 | float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) 259 | } 260 | float32obj2, ok := obj2.(float32) 261 | if !ok { 262 | float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) 263 | } 264 | if float32obj1 > float32obj2 { 265 | return compareGreater, true 266 | } 267 | if float32obj1 == float32obj2 { 268 | return compareEqual, true 269 | } 270 | if float32obj1 < float32obj2 { 271 | return compareLess, true 272 | } 273 | } 274 | case reflect.Float64: 275 | { 276 | float64obj1, ok := obj1.(float64) 277 | if !ok { 278 | float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) 279 | } 280 | float64obj2, ok := obj2.(float64) 281 | if !ok { 282 | float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) 283 | } 284 | if float64obj1 > float64obj2 { 285 | return compareGreater, true 286 | } 287 | if float64obj1 == float64obj2 { 288 | return compareEqual, true 289 | } 290 | if float64obj1 < float64obj2 { 291 | return compareLess, true 292 | } 293 | } 294 | case reflect.String: 295 | { 296 | stringobj1, ok := obj1.(string) 297 | if !ok { 298 | stringobj1 = obj1Value.Convert(stringType).Interface().(string) 299 | } 300 | stringobj2, ok := obj2.(string) 301 | if !ok { 302 | stringobj2 = obj2Value.Convert(stringType).Interface().(string) 303 | } 304 | if stringobj1 > stringobj2 { 305 | return compareGreater, true 306 | } 307 | if stringobj1 == stringobj2 { 308 | return compareEqual, true 309 | } 310 | if stringobj1 < stringobj2 { 311 | return compareLess, true 312 | } 313 | } 314 | // Check for known struct types we can check for compare results. 315 | case reflect.Struct: 316 | { 317 | // All structs enter here. We're not interested in most types. 318 | if !obj1Value.CanConvert(timeType) { 319 | break 320 | } 321 | 322 | // time.Time can be compared! 323 | timeObj1, ok := obj1.(time.Time) 324 | if !ok { 325 | timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) 326 | } 327 | 328 | timeObj2, ok := obj2.(time.Time) 329 | if !ok { 330 | timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) 331 | } 332 | 333 | if timeObj1.Before(timeObj2) { 334 | return compareLess, true 335 | } 336 | if timeObj1.Equal(timeObj2) { 337 | return compareEqual, true 338 | } 339 | return compareGreater, true 340 | } 341 | case reflect.Slice: 342 | { 343 | // We only care about the []byte type. 344 | if !obj1Value.CanConvert(bytesType) { 345 | break 346 | } 347 | 348 | // []byte can be compared! 349 | bytesObj1, ok := obj1.([]byte) 350 | if !ok { 351 | bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte) 352 | 353 | } 354 | bytesObj2, ok := obj2.([]byte) 355 | if !ok { 356 | bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) 357 | } 358 | 359 | return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true 360 | } 361 | case reflect.Uintptr: 362 | { 363 | uintptrObj1, ok := obj1.(uintptr) 364 | if !ok { 365 | uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr) 366 | } 367 | uintptrObj2, ok := obj2.(uintptr) 368 | if !ok { 369 | uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr) 370 | } 371 | if uintptrObj1 > uintptrObj2 { 372 | return compareGreater, true 373 | } 374 | if uintptrObj1 == uintptrObj2 { 375 | return compareEqual, true 376 | } 377 | if uintptrObj1 < uintptrObj2 { 378 | return compareLess, true 379 | } 380 | } 381 | } 382 | 383 | return compareEqual, false 384 | } 385 | 386 | // Greater asserts that the first element is greater than the second 387 | // 388 | // assert.Greater(2, 1) 389 | // assert.Greater(float64(2), float64(1)) 390 | // assert.Greater("b", "a") 391 | func Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { 392 | return compareTwoValues(e1, e2, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) 393 | } 394 | 395 | // GreaterOrEqual asserts that the first element is greater than or equal to the second 396 | // 397 | // assert.GreaterOrEqual(2, 1) 398 | // assert.GreaterOrEqual(2, 2) 399 | // assert.GreaterOrEqual("b", "a") 400 | // assert.GreaterOrEqual("b", "b") 401 | func GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { 402 | return compareTwoValues(e1, e2, []compareResult{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) 403 | } 404 | 405 | // Less asserts that the first element is less than the second 406 | // 407 | // assert.Less(1, 2) 408 | // assert.Less(float64(1), float64(2)) 409 | // assert.Less("a", "b") 410 | func Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { 411 | return compareTwoValues(e1, e2, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) 412 | } 413 | 414 | // LessOrEqual asserts that the first element is less than or equal to the second 415 | // 416 | // assert.LessOrEqual(1, 2) 417 | // assert.LessOrEqual(2, 2) 418 | // assert.LessOrEqual("a", "b") 419 | // assert.LessOrEqual("b", "b") 420 | func LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { 421 | return compareTwoValues(e1, e2, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) 422 | } 423 | 424 | // Positive asserts that the specified element is positive 425 | // 426 | // assert.Positive(1) 427 | // assert.Positive(1.23) 428 | func Positive(e interface{}, msgAndArgs ...interface{}) bool { 429 | zero := reflect.Zero(reflect.TypeOf(e)) 430 | return compareTwoValues(e, zero.Interface(), []compareResult{compareGreater}, "\"%v\" is not positive", msgAndArgs...) 431 | } 432 | 433 | // Negative asserts that the specified element is negative 434 | // 435 | // assert.Negative(-1) 436 | // assert.Negative(-1.23) 437 | func Negative(e interface{}, msgAndArgs ...interface{}) bool { 438 | zero := reflect.Zero(reflect.TypeOf(e)) 439 | return compareTwoValues(e, zero.Interface(), []compareResult{compareLess}, "\"%v\" is not negative", msgAndArgs...) 440 | } 441 | 442 | func compareTwoValues(e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { 443 | 444 | e1Kind := reflect.ValueOf(e1).Kind() 445 | e2Kind := reflect.ValueOf(e2).Kind() 446 | if e1Kind != e2Kind { 447 | return Fail("Elements should be the same type", msgAndArgs...) 448 | } 449 | 450 | compareResult, isComparable := compare(e1, e2, e1Kind) 451 | if !isComparable { 452 | return Fail(fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) 453 | } 454 | 455 | if !containsValue(allowedComparesResults, compareResult) { 456 | return Fail(fmt.Sprintf(failMessage, e1, e2), msgAndArgs...) 457 | } 458 | 459 | return true 460 | } 461 | 462 | func containsValue(values []compareResult, value compareResult) bool { 463 | for _, v := range values { 464 | if v == value { 465 | return true 466 | } 467 | } 468 | 469 | return false 470 | } 471 | -------------------------------------------------------------------------------- /assertion_format.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. 4 | 5 | package assert 6 | 7 | import ( 8 | http "net/http" 9 | url "net/url" 10 | time "time" 11 | ) 12 | 13 | // Conditionf uses a Comparison to assert a complex condition. 14 | func Conditionf(comp Comparison, msg string, args ...interface{}) bool { 15 | return Condition(comp, append([]interface{}{msg}, args...)...) 16 | } 17 | 18 | // Containsf asserts that the specified string, list(array, slice...) or map contains the 19 | // specified substring or element. 20 | // 21 | // assert.Containsf("Hello World", "World", "error message %s", "formatted") 22 | // assert.Containsf(["Hello", "World"], "World", "error message %s", "formatted") 23 | // assert.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") 24 | func Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { 25 | return Contains(s, contains, append([]interface{}{msg}, args...)...) 26 | } 27 | 28 | // DirExistsf checks whether a directory exists in the given path. It also fails 29 | // if the path is a file rather a directory or there is an error checking whether it exists. 30 | func DirExistsf(path string, msg string, args ...interface{}) bool { 31 | return DirExists(path, append([]interface{}{msg}, args...)...) 32 | } 33 | 34 | // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified 35 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 36 | // the number of appearances of each of them in both lists should match. 37 | // 38 | // assert.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") 39 | func ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { 40 | return ElementsMatch(listA, listB, append([]interface{}{msg}, args...)...) 41 | } 42 | 43 | // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either 44 | // a slice or a channel with len == 0. 45 | // 46 | // assert.Emptyf(obj, "error message %s", "formatted") 47 | func Emptyf(object interface{}, msg string, args ...interface{}) bool { 48 | return Empty(object, append([]interface{}{msg}, args...)...) 49 | } 50 | 51 | // Equalf asserts that two objects are equal. 52 | // 53 | // assert.Equalf(123, 123, "error message %s", "formatted") 54 | // 55 | // Pointer variable equality is determined based on the equality of the 56 | // referenced values (as opposed to the memory addresses). Function equality 57 | // cannot be determined and will always fail. 58 | func Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 59 | return Equal(expected, actual, append([]interface{}{msg}, args...)...) 60 | } 61 | 62 | // EqualErrorf asserts that a function returned an error (i.e. not `nil`) 63 | // and that it is equal to the provided error. 64 | // 65 | // actualObj, err := SomeFunction() 66 | // assert.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") 67 | func EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { 68 | return EqualError(theError, errString, append([]interface{}{msg}, args...)...) 69 | } 70 | 71 | // EqualExportedValuesf asserts that the types of two objects are equal and their public 72 | // fields are also equal. This is useful for comparing structs that have private fields 73 | // that could potentially differ. 74 | // 75 | // type S struct { 76 | // Exported int 77 | // notExported int 78 | // } 79 | // assert.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true 80 | // assert.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false 81 | func EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 82 | return EqualExportedValues(expected, actual, append([]interface{}{msg}, args...)...) 83 | } 84 | 85 | // EqualValuesf asserts that two objects are equal or convertible to the larger 86 | // type and equal. 87 | // 88 | // assert.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") 89 | func EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 90 | return EqualValues(expected, actual, append([]interface{}{msg}, args...)...) 91 | } 92 | 93 | // Errorf asserts that a function returned an error (i.e. not `nil`). 94 | // 95 | // actualObj, err := SomeFunction() 96 | // if assert.Errorf(err, "error message %s", "formatted") { 97 | // assert.Equal(expectedErrorf, err) 98 | // } 99 | func Errorf(err error, msg string, args ...interface{}) bool { 100 | return Error(err, append([]interface{}{msg}, args...)...) 101 | } 102 | 103 | // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. 104 | // This is a wrapper for errors.As. 105 | func ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { 106 | return ErrorAs(err, target, append([]interface{}{msg}, args...)...) 107 | } 108 | 109 | // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) 110 | // and that the error contains the specified substring. 111 | // 112 | // actualObj, err := SomeFunction() 113 | // assert.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") 114 | func ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { 115 | return ErrorContains(theError, contains, append([]interface{}{msg}, args...)...) 116 | } 117 | 118 | // ErrorIsf asserts that at least one of the errors in err's chain matches target. 119 | // This is a wrapper for errors.Is. 120 | func ErrorIsf(err error, target error, msg string, args ...interface{}) bool { 121 | return ErrorIs(err, target, append([]interface{}{msg}, args...)...) 122 | } 123 | 124 | // Eventuallyf asserts that given condition will be met in waitFor time, 125 | // periodically checking target function each tick. 126 | // 127 | // assert.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") 128 | func Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { 129 | return Eventually(condition, waitFor, tick, append([]interface{}{msg}, args...)...) 130 | } 131 | 132 | // EventuallyWithTf asserts that given condition will be met in waitFor time, 133 | // periodically checking target function each tick. In contrast to Eventually, 134 | // it supplies a CollectT to the condition function, so that the condition 135 | // function can use the CollectT to call other assertions. 136 | // The condition is considered "met" if no errors are raised in a tick. 137 | // The supplied CollectT collects all errors from one tick (if there are any). 138 | // If the condition is not met before waitFor, the collected errors of 139 | // the last tick are copied to t. 140 | // 141 | // externalValue := false 142 | // go func() { 143 | // time.Sleep(8*time.Second) 144 | // externalValue = true 145 | // }() 146 | // assert.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { 147 | // // add assertions as needed; any assertion failure will fail the current tick 148 | // assert.True(c, externalValue, "expected 'externalValue' to be true") 149 | // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") 150 | func EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { 151 | return EventuallyWithT(condition, waitFor, tick, append([]interface{}{msg}, args...)...) 152 | } 153 | 154 | // Exactlyf asserts that two objects are equal in value and type. 155 | // 156 | // assert.Exactlyf(int32(123), int64(123), "error message %s", "formatted") 157 | func Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 158 | return Exactly(expected, actual, append([]interface{}{msg}, args...)...) 159 | } 160 | 161 | // Failf reports a failure through 162 | func Failf(failureMessage string, msg string, args ...interface{}) bool { 163 | return Fail(failureMessage, append([]interface{}{msg}, args...)...) 164 | } 165 | 166 | // FailNowf fails test 167 | func FailNowf(failureMessage string, msg string, args ...interface{}) bool { 168 | return FailNow(failureMessage, append([]interface{}{msg}, args...)...) 169 | } 170 | 171 | // Falsef asserts that the specified value is false. 172 | // 173 | // assert.Falsef(myBool, "error message %s", "formatted") 174 | func Falsef(value bool, msg string, args ...interface{}) bool { 175 | return False(value, append([]interface{}{msg}, args...)...) 176 | } 177 | 178 | // FileExistsf checks whether a file exists in the given path. It also fails if 179 | // the path points to a directory or there is an error when trying to check the file. 180 | func FileExistsf(path string, msg string, args ...interface{}) bool { 181 | return FileExists(path, append([]interface{}{msg}, args...)...) 182 | } 183 | 184 | // Greaterf asserts that the first element is greater than the second 185 | // 186 | // assert.Greaterf(2, 1, "error message %s", "formatted") 187 | // assert.Greaterf(float64(2), float64(1), "error message %s", "formatted") 188 | // assert.Greaterf("b", "a", "error message %s", "formatted") 189 | func Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { 190 | return Greater(e1, e2, append([]interface{}{msg}, args...)...) 191 | } 192 | 193 | // GreaterOrEqualf asserts that the first element is greater than or equal to the second 194 | // 195 | // assert.GreaterOrEqualf(2, 1, "error message %s", "formatted") 196 | // assert.GreaterOrEqualf(2, 2, "error message %s", "formatted") 197 | // assert.GreaterOrEqualf("b", "a", "error message %s", "formatted") 198 | // assert.GreaterOrEqualf("b", "b", "error message %s", "formatted") 199 | func GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { 200 | return GreaterOrEqual(e1, e2, append([]interface{}{msg}, args...)...) 201 | } 202 | 203 | // HTTPBodyContainsf asserts that a specified handler returns a 204 | // body that contains a string. 205 | // 206 | // assert.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") 207 | // 208 | // Returns whether the assertion was successful (true) or not (false). 209 | func HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { 210 | return HTTPBodyContains(handler, method, url, values, str, append([]interface{}{msg}, args...)...) 211 | } 212 | 213 | // HTTPBodyNotContainsf asserts that a specified handler returns a 214 | // body that does not contain a string. 215 | // 216 | // assert.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") 217 | // 218 | // Returns whether the assertion was successful (true) or not (false). 219 | func HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { 220 | return HTTPBodyNotContains(handler, method, url, values, str, append([]interface{}{msg}, args...)...) 221 | } 222 | 223 | // HTTPErrorf asserts that a specified handler returns an error status code. 224 | // 225 | // assert.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 226 | // 227 | // Returns whether the assertion was successful (true) or not (false). 228 | func HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { 229 | return HTTPError(handler, method, url, values, append([]interface{}{msg}, args...)...) 230 | } 231 | 232 | // HTTPRedirectf asserts that a specified handler returns a redirect status code. 233 | // 234 | // assert.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 235 | // 236 | // Returns whether the assertion was successful (true) or not (false). 237 | func HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { 238 | return HTTPRedirect(handler, method, url, values, append([]interface{}{msg}, args...)...) 239 | } 240 | 241 | // HTTPStatusCodef asserts that a specified handler returns a specified status code. 242 | // 243 | // assert.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") 244 | // 245 | // Returns whether the assertion was successful (true) or not (false). 246 | func HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { 247 | return HTTPStatusCode(handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...) 248 | } 249 | 250 | // HTTPSuccessf asserts that a specified handler returns a success status code. 251 | // 252 | // assert.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") 253 | // 254 | // Returns whether the assertion was successful (true) or not (false). 255 | func HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { 256 | return HTTPSuccess(handler, method, url, values, append([]interface{}{msg}, args...)...) 257 | } 258 | 259 | // Implementsf asserts that an object is implemented by the specified interface. 260 | // 261 | // assert.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") 262 | func Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { 263 | return Implements(interfaceObject, object, append([]interface{}{msg}, args...)...) 264 | } 265 | 266 | // InDeltaf asserts that the two numerals are within delta of each other. 267 | // 268 | // assert.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") 269 | func InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { 270 | return InDelta(expected, actual, delta, append([]interface{}{msg}, args...)...) 271 | } 272 | 273 | // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. 274 | func InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { 275 | return InDeltaMapValues(expected, actual, delta, append([]interface{}{msg}, args...)...) 276 | } 277 | 278 | // InDeltaSlicef is the same as InDelta, except it compares two slices. 279 | func InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { 280 | return InDeltaSlice(expected, actual, delta, append([]interface{}{msg}, args...)...) 281 | } 282 | 283 | // InEpsilonf asserts that expected and actual have a relative error less than epsilon 284 | func InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { 285 | return InEpsilon(expected, actual, epsilon, append([]interface{}{msg}, args...)...) 286 | } 287 | 288 | // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. 289 | func InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { 290 | return InEpsilonSlice(expected, actual, epsilon, append([]interface{}{msg}, args...)...) 291 | } 292 | 293 | // IsDecreasingf asserts that the collection is decreasing 294 | // 295 | // assert.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") 296 | // assert.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") 297 | // assert.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") 298 | func IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { 299 | return IsDecreasing(object, append([]interface{}{msg}, args...)...) 300 | } 301 | 302 | // IsIncreasingf asserts that the collection is increasing 303 | // 304 | // assert.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") 305 | // assert.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") 306 | // assert.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") 307 | func IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { 308 | return IsIncreasing(object, append([]interface{}{msg}, args...)...) 309 | } 310 | 311 | // IsNonDecreasingf asserts that the collection is not decreasing 312 | // 313 | // assert.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") 314 | // assert.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") 315 | // assert.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") 316 | func IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { 317 | return IsNonDecreasing(object, append([]interface{}{msg}, args...)...) 318 | } 319 | 320 | // IsNonIncreasingf asserts that the collection is not increasing 321 | // 322 | // assert.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") 323 | // assert.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") 324 | // assert.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") 325 | func IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { 326 | return IsNonIncreasing(object, append([]interface{}{msg}, args...)...) 327 | } 328 | 329 | // IsTypef asserts that the specified objects are of the same type. 330 | func IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { 331 | return IsType(expectedType, object, append([]interface{}{msg}, args...)...) 332 | } 333 | 334 | // JSONEqf asserts that two JSON strings are equivalent. 335 | // 336 | // assert.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") 337 | func JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { 338 | return JSONEq(expected, actual, append([]interface{}{msg}, args...)...) 339 | } 340 | 341 | // Lenf asserts that the specified object has specific length. 342 | // Lenf also fails if the object has a type that len() not accept. 343 | // 344 | // assert.Lenf(mySlice, 3, "error message %s", "formatted") 345 | func Lenf(object interface{}, length int, msg string, args ...interface{}) bool { 346 | return Len(object, length, append([]interface{}{msg}, args...)...) 347 | } 348 | 349 | // Lessf asserts that the first element is less than the second 350 | // 351 | // assert.Lessf(1, 2, "error message %s", "formatted") 352 | // assert.Lessf(float64(1), float64(2), "error message %s", "formatted") 353 | // assert.Lessf("a", "b", "error message %s", "formatted") 354 | func Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { 355 | return Less(e1, e2, append([]interface{}{msg}, args...)...) 356 | } 357 | 358 | // LessOrEqualf asserts that the first element is less than or equal to the second 359 | // 360 | // assert.LessOrEqualf(1, 2, "error message %s", "formatted") 361 | // assert.LessOrEqualf(2, 2, "error message %s", "formatted") 362 | // assert.LessOrEqualf("a", "b", "error message %s", "formatted") 363 | // assert.LessOrEqualf("b", "b", "error message %s", "formatted") 364 | func LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { 365 | return LessOrEqual(e1, e2, append([]interface{}{msg}, args...)...) 366 | } 367 | 368 | // Negativef asserts that the specified element is negative 369 | // 370 | // assert.Negativef(-1, "error message %s", "formatted") 371 | // assert.Negativef(-1.23, "error message %s", "formatted") 372 | func Negativef(e interface{}, msg string, args ...interface{}) bool { 373 | return Negative(e, append([]interface{}{msg}, args...)...) 374 | } 375 | 376 | // Neverf asserts that the given condition doesn't satisfy in waitFor time, 377 | // periodically checking the target function each tick. 378 | // 379 | // assert.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") 380 | func Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { 381 | return Never(condition, waitFor, tick, append([]interface{}{msg}, args...)...) 382 | } 383 | 384 | // Nilf asserts that the specified object is nil. 385 | // 386 | // assert.Nilf(err, "error message %s", "formatted") 387 | func Nilf(object interface{}, msg string, args ...interface{}) bool { 388 | return Nil(object, append([]interface{}{msg}, args...)...) 389 | } 390 | 391 | // NoDirExistsf checks whether a directory does not exist in the given path. 392 | // It fails if the path points to an existing _directory_ only. 393 | func NoDirExistsf(path string, msg string, args ...interface{}) bool { 394 | return NoDirExists(path, append([]interface{}{msg}, args...)...) 395 | } 396 | 397 | // NoErrorf asserts that a function returned no error (i.e. `nil`). 398 | // 399 | // actualObj, err := SomeFunction() 400 | // if assert.NoErrorf(err, "error message %s", "formatted") { 401 | // assert.Equal(expectedObj, actualObj) 402 | // } 403 | func NoErrorf(err error, msg string, args ...interface{}) bool { 404 | return NoError(err, append([]interface{}{msg}, args...)...) 405 | } 406 | 407 | // NoFileExistsf checks whether a file does not exist in a given path. It fails 408 | // if the path points to an existing _file_ only. 409 | func NoFileExistsf(path string, msg string, args ...interface{}) bool { 410 | return NoFileExists(path, append([]interface{}{msg}, args...)...) 411 | } 412 | 413 | // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the 414 | // specified substring or element. 415 | // 416 | // assert.NotContainsf("Hello World", "Earth", "error message %s", "formatted") 417 | // assert.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") 418 | // assert.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") 419 | func NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { 420 | return NotContains(s, contains, append([]interface{}{msg}, args...)...) 421 | } 422 | 423 | // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified 424 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 425 | // the number of appearances of each of them in both lists should not match. 426 | // This is an inverse of ElementsMatch. 427 | // 428 | // assert.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false 429 | // 430 | // assert.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true 431 | // 432 | // assert.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true 433 | func NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { 434 | return NotElementsMatch(listA, listB, append([]interface{}{msg}, args...)...) 435 | } 436 | 437 | // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either 438 | // a slice or a channel with len == 0. 439 | // 440 | // if assert.NotEmptyf(obj, "error message %s", "formatted") { 441 | // assert.Equal("two", obj[1]) 442 | // } 443 | func NotEmptyf(object interface{}, msg string, args ...interface{}) bool { 444 | return NotEmpty(object, append([]interface{}{msg}, args...)...) 445 | } 446 | 447 | // NotEqualf asserts that the specified values are NOT equal. 448 | // 449 | // assert.NotEqualf(obj1, obj2, "error message %s", "formatted") 450 | // 451 | // Pointer variable equality is determined based on the equality of the 452 | // referenced values (as opposed to the memory addresses). 453 | func NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 454 | return NotEqual(expected, actual, append([]interface{}{msg}, args...)...) 455 | } 456 | 457 | // NotEqualValuesf asserts that two objects are not equal even when converted to the same type 458 | // 459 | // assert.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") 460 | func NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 461 | return NotEqualValues(expected, actual, append([]interface{}{msg}, args...)...) 462 | } 463 | 464 | // NotErrorAsf asserts that none of the errors in err's chain matches target, 465 | // but if so, sets target to that error value. 466 | func NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { 467 | return NotErrorAs(err, target, append([]interface{}{msg}, args...)...) 468 | } 469 | 470 | // NotErrorIsf asserts that none of the errors in err's chain matches target. 471 | // This is a wrapper for errors.Is. 472 | func NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { 473 | return NotErrorIs(err, target, append([]interface{}{msg}, args...)...) 474 | } 475 | 476 | // NotImplementsf asserts that an object does not implement the specified interface. 477 | // 478 | // assert.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") 479 | func NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { 480 | return NotImplements(interfaceObject, object, append([]interface{}{msg}, args...)...) 481 | } 482 | 483 | // NotNilf asserts that the specified object is not nil. 484 | // 485 | // assert.NotNilf(err, "error message %s", "formatted") 486 | func NotNilf(object interface{}, msg string, args ...interface{}) bool { 487 | return NotNil(object, append([]interface{}{msg}, args...)...) 488 | } 489 | 490 | // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. 491 | // 492 | // assert.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") 493 | func NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { 494 | return NotPanics(f, append([]interface{}{msg}, args...)...) 495 | } 496 | 497 | // NotRegexpf asserts that a specified regexp does not match a string. 498 | // 499 | // assert.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") 500 | // assert.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") 501 | func NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { 502 | return NotRegexp(rx, str, append([]interface{}{msg}, args...)...) 503 | } 504 | 505 | // NotSamef asserts that two pointers do not reference the same object. 506 | // 507 | // assert.NotSamef(ptr1, ptr2, "error message %s", "formatted") 508 | // 509 | // Both arguments must be pointer variables. Pointer variable sameness is 510 | // determined based on the equality of both type and value. 511 | func NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 512 | return NotSame(expected, actual, append([]interface{}{msg}, args...)...) 513 | } 514 | 515 | // NotSubsetf asserts that the specified list(array, slice...) or map does NOT 516 | // contain all elements given in the specified subset list(array, slice...) or 517 | // map. 518 | // 519 | // assert.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") 520 | // assert.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") 521 | func NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { 522 | return NotSubset(list, subset, append([]interface{}{msg}, args...)...) 523 | } 524 | 525 | // NotZerof asserts that i is not the zero value for its type. 526 | func NotZerof(i interface{}, msg string, args ...interface{}) bool { 527 | return NotZero(i, append([]interface{}{msg}, args...)...) 528 | } 529 | 530 | // Panicsf asserts that the code inside the specified PanicTestFunc panics. 531 | // 532 | // assert.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") 533 | func Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { 534 | return Panics(f, append([]interface{}{msg}, args...)...) 535 | } 536 | 537 | // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc 538 | // panics, and that the recovered panic value is an error that satisfies the 539 | // EqualError comparison. 540 | // 541 | // assert.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") 542 | func PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { 543 | return PanicsWithError(errString, f, append([]interface{}{msg}, args...)...) 544 | } 545 | 546 | // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that 547 | // the recovered panic value equals the expected panic value. 548 | // 549 | // assert.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") 550 | func PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { 551 | return PanicsWithValue(expected, f, append([]interface{}{msg}, args...)...) 552 | } 553 | 554 | // Positivef asserts that the specified element is positive 555 | // 556 | // assert.Positivef(1, "error message %s", "formatted") 557 | // assert.Positivef(1.23, "error message %s", "formatted") 558 | func Positivef(e interface{}, msg string, args ...interface{}) bool { 559 | return Positive(e, append([]interface{}{msg}, args...)...) 560 | } 561 | 562 | // Regexpf asserts that a specified regexp matches a string. 563 | // 564 | // assert.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") 565 | // assert.Regexpf("start...$", "it's not starting", "error message %s", "formatted") 566 | func Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { 567 | return Regexp(rx, str, append([]interface{}{msg}, args...)...) 568 | } 569 | 570 | // Samef asserts that two pointers reference the same object. 571 | // 572 | // assert.Samef(ptr1, ptr2, "error message %s", "formatted") 573 | // 574 | // Both arguments must be pointer variables. Pointer variable sameness is 575 | // determined based on the equality of both type and value. 576 | func Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { 577 | return Same(expected, actual, append([]interface{}{msg}, args...)...) 578 | } 579 | 580 | // Subsetf asserts that the specified list(array, slice...) or map contains all 581 | // elements given in the specified subset list(array, slice...) or map. 582 | // 583 | // assert.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") 584 | // assert.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") 585 | func Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { 586 | return Subset(list, subset, append([]interface{}{msg}, args...)...) 587 | } 588 | 589 | // Truef asserts that the specified value is true. 590 | // 591 | // assert.Truef(myBool, "error message %s", "formatted") 592 | func Truef(value bool, msg string, args ...interface{}) bool { 593 | return True(value, append([]interface{}{msg}, args...)...) 594 | } 595 | 596 | // WithinDurationf asserts that the two times are within duration delta of each other. 597 | // 598 | // assert.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") 599 | func WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { 600 | return WithinDuration(expected, actual, delta, append([]interface{}{msg}, args...)...) 601 | } 602 | 603 | // WithinRangef asserts that a time is within a time range (inclusive). 604 | // 605 | // assert.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") 606 | func WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { 607 | return WithinRange(actual, start, end, append([]interface{}{msg}, args...)...) 608 | } 609 | 610 | // YAMLEqf asserts that two YAML strings are equivalent. 611 | 612 | // Zerof asserts that i is the zero value for its type. 613 | func Zerof(i interface{}, msg string, args ...interface{}) bool { 614 | return Zero(i, append([]interface{}{msg}, args...)...) 615 | } 616 | -------------------------------------------------------------------------------- /assertion_order.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import ( 6 | "fmt" 7 | "reflect" 8 | ) 9 | 10 | // isOrdered checks that collection contains orderable elements. 11 | func isOrdered(object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { 12 | objKind := reflect.TypeOf(object).Kind() 13 | if objKind != reflect.Slice && objKind != reflect.Array { 14 | return false 15 | } 16 | 17 | objValue := reflect.ValueOf(object) 18 | objLen := objValue.Len() 19 | 20 | if objLen <= 1 { 21 | return true 22 | } 23 | 24 | value := objValue.Index(0) 25 | valueInterface := value.Interface() 26 | firstValueKind := value.Kind() 27 | 28 | for i := 1; i < objLen; i++ { 29 | prevValue := value 30 | prevValueInterface := valueInterface 31 | 32 | value = objValue.Index(i) 33 | valueInterface = value.Interface() 34 | 35 | compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) 36 | 37 | if !isComparable { 38 | return Fail(fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) 39 | } 40 | 41 | if !containsValue(allowedComparesResults, compareResult) { 42 | return Fail(fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) 43 | } 44 | } 45 | 46 | return true 47 | } 48 | 49 | // IsIncreasing asserts that the collection is increasing 50 | // 51 | // assert.IsIncreasing([]int{1, 2, 3}) 52 | // assert.IsIncreasing([]float{1, 2}) 53 | // assert.IsIncreasing([]string{"a", "b"}) 54 | func IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { 55 | return isOrdered(object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) 56 | } 57 | 58 | // IsNonIncreasing asserts that the collection is not increasing 59 | // 60 | // assert.IsNonIncreasing([]int{2, 1, 1}) 61 | // assert.IsNonIncreasing([]float{2, 1}) 62 | // assert.IsNonIncreasing([]string{"b", "a"}) 63 | func IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { 64 | return isOrdered(object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) 65 | } 66 | 67 | // IsDecreasing asserts that the collection is decreasing 68 | // 69 | // assert.IsDecreasing([]int{2, 1, 0}) 70 | // assert.IsDecreasing([]float{2, 1}) 71 | // assert.IsDecreasing([]string{"b", "a"}) 72 | func IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { 73 | return isOrdered(object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) 74 | } 75 | 76 | // IsNonDecreasing asserts that the collection is not decreasing 77 | // 78 | // assert.IsNonDecreasing([]int{1, 1, 2}) 79 | // assert.IsNonDecreasing([]float{1, 2}) 80 | // assert.IsNonDecreasing([]string{"a", "b"}) 81 | func IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { 82 | return isOrdered(object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) 83 | } 84 | -------------------------------------------------------------------------------- /assertions.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import ( 6 | "bufio" 7 | "bytes" 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | "math" 12 | "os" 13 | "reflect" 14 | "regexp" 15 | "runtime" 16 | "runtime/debug" 17 | "strings" 18 | "time" 19 | "unicode" 20 | "unicode/utf8" 21 | 22 | "github.com/davecgh/go-spew/spew" 23 | "github.com/pmezard/go-difflib/difflib" 24 | // Wrapper around gopkg.in/yaml.v3 25 | ) 26 | 27 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" 28 | 29 | // TestingT is an interface wrapper around *testing.T 30 | type TestingT interface { 31 | Errorf(format string, args ...interface{}) 32 | } 33 | 34 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 35 | // for table driven tests. 36 | type ComparisonAssertionFunc func(interface{}, interface{}, ...interface{}) bool 37 | 38 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 39 | // for table driven tests. 40 | type ValueAssertionFunc func(interface{}, ...interface{}) bool 41 | 42 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 43 | // for table driven tests. 44 | type BoolAssertionFunc func(bool, ...interface{}) bool 45 | 46 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 47 | // for table driven tests. 48 | type ErrorAssertionFunc func(error, ...interface{}) bool 49 | 50 | // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful 51 | // for table driven tests. 52 | type PanicAssertionFunc = func(f PanicTestFunc, msgAndArgs ...interface{}) bool 53 | 54 | // Comparison is a custom function that returns true on success and false on failure 55 | type Comparison func() (success bool) 56 | 57 | /* 58 | Helper functions 59 | */ 60 | 61 | // ObjectsAreEqual determines if two objects are considered equal. 62 | // 63 | // This function does no assertion of any kind. 64 | func ObjectsAreEqual(expected, actual interface{}) bool { 65 | if expected == nil || actual == nil { 66 | return expected == actual 67 | } 68 | 69 | exp, ok := expected.([]byte) 70 | if !ok { 71 | return reflect.DeepEqual(expected, actual) 72 | } 73 | 74 | act, ok := actual.([]byte) 75 | if !ok { 76 | return false 77 | } 78 | if exp == nil || act == nil { 79 | return exp == nil && act == nil 80 | } 81 | return bytes.Equal(exp, act) 82 | } 83 | 84 | // copyExportedFields iterates downward through nested data structures and creates a copy 85 | // that only contains the exported struct fields. 86 | func copyExportedFields(expected interface{}) interface{} { 87 | if isNil(expected) { 88 | return expected 89 | } 90 | 91 | expectedType := reflect.TypeOf(expected) 92 | expectedKind := expectedType.Kind() 93 | expectedValue := reflect.ValueOf(expected) 94 | 95 | switch expectedKind { 96 | case reflect.Struct: 97 | result := reflect.New(expectedType).Elem() 98 | for i := 0; i < expectedType.NumField(); i++ { 99 | field := expectedType.Field(i) 100 | isExported := field.IsExported() 101 | if isExported { 102 | fieldValue := expectedValue.Field(i) 103 | if isNil(fieldValue) || isNil(fieldValue.Interface()) { 104 | continue 105 | } 106 | newValue := copyExportedFields(fieldValue.Interface()) 107 | result.Field(i).Set(reflect.ValueOf(newValue)) 108 | } 109 | } 110 | return result.Interface() 111 | 112 | case reflect.Ptr: 113 | result := reflect.New(expectedType.Elem()) 114 | unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface()) 115 | result.Elem().Set(reflect.ValueOf(unexportedRemoved)) 116 | return result.Interface() 117 | 118 | case reflect.Array, reflect.Slice: 119 | var result reflect.Value 120 | if expectedKind == reflect.Array { 121 | result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem() 122 | } else { 123 | result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len()) 124 | } 125 | for i := 0; i < expectedValue.Len(); i++ { 126 | index := expectedValue.Index(i) 127 | if isNil(index) { 128 | continue 129 | } 130 | unexportedRemoved := copyExportedFields(index.Interface()) 131 | result.Index(i).Set(reflect.ValueOf(unexportedRemoved)) 132 | } 133 | return result.Interface() 134 | 135 | case reflect.Map: 136 | result := reflect.MakeMap(expectedType) 137 | for _, k := range expectedValue.MapKeys() { 138 | index := expectedValue.MapIndex(k) 139 | unexportedRemoved := copyExportedFields(index.Interface()) 140 | result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved)) 141 | } 142 | return result.Interface() 143 | 144 | default: 145 | return expected 146 | } 147 | } 148 | 149 | // ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are 150 | // considered equal. This comparison of only exported fields is applied recursively to nested data 151 | // structures. 152 | // 153 | // This function does no assertion of any kind. 154 | // 155 | // Deprecated: Use [EqualExportedValues] instead. 156 | func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool { 157 | expectedCleaned := copyExportedFields(expected) 158 | actualCleaned := copyExportedFields(actual) 159 | return ObjectsAreEqualValues(expectedCleaned, actualCleaned) 160 | } 161 | 162 | // ObjectsAreEqualValues gets whether two objects are equal, or if their 163 | // values are equal. 164 | func ObjectsAreEqualValues(expected, actual interface{}) bool { 165 | if ObjectsAreEqual(expected, actual) { 166 | return true 167 | } 168 | 169 | expectedValue := reflect.ValueOf(expected) 170 | actualValue := reflect.ValueOf(actual) 171 | if !expectedValue.IsValid() || !actualValue.IsValid() { 172 | return false 173 | } 174 | 175 | expectedType := expectedValue.Type() 176 | actualType := actualValue.Type() 177 | if !expectedType.ConvertibleTo(actualType) { 178 | return false 179 | } 180 | 181 | if !isNumericType(expectedType) || !isNumericType(actualType) { 182 | // Attempt comparison after type conversion 183 | return reflect.DeepEqual( 184 | expectedValue.Convert(actualType).Interface(), actual, 185 | ) 186 | } 187 | 188 | // If BOTH values are numeric, there are chances of false positives due 189 | // to overflow or underflow. So, we need to make sure to always convert 190 | // the smaller type to a larger type before comparing. 191 | if expectedType.Size() >= actualType.Size() { 192 | return actualValue.Convert(expectedType).Interface() == expected 193 | } 194 | 195 | return expectedValue.Convert(actualType).Interface() == actual 196 | } 197 | 198 | // isNumericType returns true if the type is one of: 199 | // int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, 200 | // float32, float64, complex64, complex128 201 | func isNumericType(t reflect.Type) bool { 202 | return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128 203 | } 204 | 205 | /* CallerInfo is necessary because the assert functions use the testing object 206 | internally, causing it to print the file:line of the assert method, rather than where 207 | the problem actually occurred in calling code.*/ 208 | 209 | // CallerInfo returns an array of strings containing the file and line number 210 | // of each stack frame leading from the current test to the assert call that 211 | // failed. 212 | func CallerInfo() []string { 213 | 214 | var pc uintptr 215 | var ok bool 216 | var file string 217 | var line int 218 | var name string 219 | 220 | callers := []string{} 221 | for i := 0; ; i++ { 222 | pc, file, line, ok = runtime.Caller(i) 223 | if !ok { 224 | // The breaks below failed to terminate the loop, and we ran off the 225 | // end of the call stack. 226 | break 227 | } 228 | 229 | // This is a huge edge case, but it will panic if this is the case, see #180 230 | if file == "" { 231 | break 232 | } 233 | 234 | f := runtime.FuncForPC(pc) 235 | if f == nil { 236 | break 237 | } 238 | name = f.Name() 239 | 240 | // testing.tRunner is the standard library function that calls 241 | // tests. Subtests are called directly by tRunner, without going through 242 | // the Test/Benchmark/Example function that contains the t.Run calls, so 243 | // with subtests we should break when we hit tRunner, without adding it 244 | // to the list of callers. 245 | if name == "testing.tRunner" { 246 | break 247 | } 248 | 249 | parts := strings.Split(file, "/") 250 | if len(parts) > 1 { 251 | filename := parts[len(parts)-1] 252 | dir := parts[len(parts)-2] 253 | if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" { 254 | callers = append(callers, fmt.Sprintf("%s:%d", file, line)) 255 | } 256 | } 257 | 258 | // Drop the package 259 | segments := strings.Split(name, ".") 260 | name = segments[len(segments)-1] 261 | if isTest(name, "Test") || 262 | isTest(name, "Benchmark") || 263 | isTest(name, "Example") { 264 | break 265 | } 266 | } 267 | 268 | return callers 269 | } 270 | 271 | // Stolen from the `go test` tool. 272 | // isTest tells whether name looks like a test (or benchmark, according to prefix). 273 | // It is a Test (say) if there is a character after Test that is not a lower-case letter. 274 | // We don't want TesticularCancer. 275 | func isTest(name, prefix string) bool { 276 | if !strings.HasPrefix(name, prefix) { 277 | return false 278 | } 279 | if len(name) == len(prefix) { // "Test" is ok 280 | return true 281 | } 282 | r, _ := utf8.DecodeRuneInString(name[len(prefix):]) 283 | return !unicode.IsLower(r) 284 | } 285 | 286 | func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { 287 | if len(msgAndArgs) == 0 || msgAndArgs == nil { 288 | return "" 289 | } 290 | if len(msgAndArgs) == 1 { 291 | msg := msgAndArgs[0] 292 | if msgAsStr, ok := msg.(string); ok { 293 | return msgAsStr 294 | } 295 | return fmt.Sprintf("%+v", msg) 296 | } 297 | if len(msgAndArgs) > 1 { 298 | return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) 299 | } 300 | return "" 301 | } 302 | 303 | // Aligns the provided message so that all lines after the first line start at the same location as the first line. 304 | // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). 305 | // The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the 306 | // basis on which the alignment occurs). 307 | func indentMessageLines(message string, longestLabelLen int) string { 308 | outBuf := new(bytes.Buffer) 309 | 310 | for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { 311 | // no need to align first line because it starts at the correct location (after the label) 312 | if i != 0 { 313 | // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab 314 | outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") 315 | } 316 | outBuf.WriteString(scanner.Text()) 317 | } 318 | 319 | return outBuf.String() 320 | } 321 | 322 | type failNower interface { 323 | FailNow() 324 | } 325 | 326 | // FailNow fails test 327 | func FailNow(failureMessage string, msgAndArgs ...interface{}) bool { 328 | Fail(failureMessage, msgAndArgs...) 329 | 330 | // We cannot extend TestingT with FailNow() and 331 | // maintain backwards compatibility, so we fallback 332 | // to panicking when FailNow is not available in 333 | // TestingT. 334 | // See issue #263 335 | 336 | return false 337 | } 338 | 339 | // Fail reports a failure through 340 | func Fail(failureMessage string, msgAndArgs ...interface{}) bool { 341 | content := []labeledContent{ 342 | {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, 343 | {"Error", failureMessage}, 344 | } 345 | 346 | // Add test name if the Go version supports it 347 | 348 | message := messageFromMsgAndArgs(msgAndArgs...) 349 | if len(message) > 0 { 350 | content = append(content, labeledContent{"Messages", message}) 351 | } 352 | 353 | panic(fmt.Errorf("\n%s", ""+labeledOutput(content...))) 354 | 355 | return false 356 | } 357 | 358 | type labeledContent struct { 359 | label string 360 | content string 361 | } 362 | 363 | // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: 364 | // 365 | // \t{{label}}:{{align_spaces}}\t{{content}}\n 366 | // 367 | // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. 368 | // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this 369 | // alignment is achieved, "\t{{content}}\n" is added for the output. 370 | // 371 | // If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. 372 | func labeledOutput(content ...labeledContent) string { 373 | longestLabel := 0 374 | for _, v := range content { 375 | if len(v.label) > longestLabel { 376 | longestLabel = len(v.label) 377 | } 378 | } 379 | var output string 380 | for _, v := range content { 381 | output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" 382 | } 383 | return output 384 | } 385 | 386 | // Implements asserts that an object is implemented by the specified interface. 387 | // 388 | // assert.Implements((*MyInterface)(nil), new(MyObject)) 389 | func Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { 390 | interfaceType := reflect.TypeOf(interfaceObject).Elem() 391 | 392 | if object == nil { 393 | return Fail(fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...) 394 | } 395 | if !reflect.TypeOf(object).Implements(interfaceType) { 396 | return Fail(fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) 397 | } 398 | 399 | return true 400 | } 401 | 402 | // NotImplements asserts that an object does not implement the specified interface. 403 | // 404 | // assert.NotImplements((*MyInterface)(nil), new(MyObject)) 405 | func NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { 406 | interfaceType := reflect.TypeOf(interfaceObject).Elem() 407 | 408 | if object == nil { 409 | return Fail(fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...) 410 | } 411 | if reflect.TypeOf(object).Implements(interfaceType) { 412 | return Fail(fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...) 413 | } 414 | 415 | return true 416 | } 417 | 418 | // IsType asserts that the specified objects are of the same type. 419 | func IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { 420 | 421 | if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) { 422 | return Fail(fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...) 423 | } 424 | 425 | return true 426 | } 427 | 428 | // Equal asserts that two objects are equal. 429 | // 430 | // assert.Equal(123, 123) 431 | // 432 | // Pointer variable equality is determined based on the equality of the 433 | // referenced values (as opposed to the memory addresses). Function equality 434 | // cannot be determined and will always fail. 435 | func Equal(expected, actual interface{}, msgAndArgs ...interface{}) bool { 436 | if err := validateEqualArgs(expected, actual); err != nil { 437 | return Fail(fmt.Sprintf("Invalid operation: %#v == %#v (%s)", 438 | expected, actual, err), msgAndArgs...) 439 | } 440 | 441 | if !ObjectsAreEqual(expected, actual) { 442 | diff := diff(expected, actual) 443 | expected, actual = formatUnequalValues(expected, actual) 444 | return Fail(fmt.Sprintf("Not equal: \n"+ 445 | "expected: %s\n"+ 446 | "actual : %s%s", expected, actual, diff), msgAndArgs...) 447 | } 448 | 449 | return true 450 | 451 | } 452 | 453 | // validateEqualArgs checks whether provided arguments can be safely used in the 454 | // Equal/NotEqual functions. 455 | func validateEqualArgs(expected, actual interface{}) error { 456 | if expected == nil && actual == nil { 457 | return nil 458 | } 459 | 460 | if isFunction(expected) || isFunction(actual) { 461 | return errors.New("cannot take func type as argument") 462 | } 463 | return nil 464 | } 465 | 466 | // Same asserts that two pointers reference the same object. 467 | // 468 | // assert.Same(ptr1, ptr2) 469 | // 470 | // Both arguments must be pointer variables. Pointer variable sameness is 471 | // determined based on the equality of both type and value. 472 | func Same(expected, actual interface{}, msgAndArgs ...interface{}) bool { 473 | 474 | same, ok := samePointers(expected, actual) 475 | if !ok { 476 | return Fail("Both arguments must be pointers", msgAndArgs...) 477 | } 478 | 479 | if !same { 480 | // both are pointers but not the same type & pointing to the same address 481 | return Fail(fmt.Sprintf("Not same: \n"+ 482 | "expected: %p %#v\n"+ 483 | "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) 484 | } 485 | 486 | return true 487 | } 488 | 489 | // NotSame asserts that two pointers do not reference the same object. 490 | // 491 | // assert.NotSame(ptr1, ptr2) 492 | // 493 | // Both arguments must be pointer variables. Pointer variable sameness is 494 | // determined based on the equality of both type and value. 495 | func NotSame(expected, actual interface{}, msgAndArgs ...interface{}) bool { 496 | 497 | same, ok := samePointers(expected, actual) 498 | if !ok { 499 | //fails when the arguments are not pointers 500 | return !(Fail("Both arguments must be pointers", msgAndArgs...)) 501 | } 502 | 503 | if same { 504 | return Fail(fmt.Sprintf( 505 | "Expected and actual point to the same object: %p %#v", 506 | expected, expected), msgAndArgs...) 507 | } 508 | return true 509 | } 510 | 511 | // samePointers checks if two generic interface objects are pointers of the same 512 | // type pointing to the same object. It returns two values: same indicating if 513 | // they are the same type and point to the same object, and ok indicating that 514 | // both inputs are pointers. 515 | func samePointers(first, second interface{}) (same bool, ok bool) { 516 | firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) 517 | if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { 518 | return false, false //not both are pointers 519 | } 520 | 521 | firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) 522 | if firstType != secondType { 523 | return false, true // both are pointers, but of different types 524 | } 525 | 526 | // compare pointer addresses 527 | return first == second, true 528 | } 529 | 530 | // formatUnequalValues takes two values of arbitrary types and returns string 531 | // representations appropriate to be presented to the user. 532 | // 533 | // If the values are not of like type, the returned strings will be prefixed 534 | // with the type name, and the value will be enclosed in parentheses similar 535 | // to a type conversion in the Go grammar. 536 | func formatUnequalValues(expected, actual interface{}) (e string, a string) { 537 | if reflect.TypeOf(expected) != reflect.TypeOf(actual) { 538 | return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), 539 | fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) 540 | } 541 | switch expected.(type) { 542 | case time.Duration: 543 | return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) 544 | } 545 | return truncatingFormat(expected), truncatingFormat(actual) 546 | } 547 | 548 | // truncatingFormat formats the data and truncates it if it's too long. 549 | // 550 | // This helps keep formatted error messages lines from exceeding the 551 | // bufio.MaxScanTokenSize max line length that the go testing framework imposes. 552 | func truncatingFormat(data interface{}) string { 553 | value := fmt.Sprintf("%#v", data) 554 | max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. 555 | if len(value) > max { 556 | value = value[0:max] + "<... truncated>" 557 | } 558 | return value 559 | } 560 | 561 | // EqualValues asserts that two objects are equal or convertible to the larger 562 | // type and equal. 563 | // 564 | // assert.EqualValues(uint32(123), int32(123)) 565 | func EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) bool { 566 | 567 | if !ObjectsAreEqualValues(expected, actual) { 568 | diff := diff(expected, actual) 569 | expected, actual = formatUnequalValues(expected, actual) 570 | return Fail(fmt.Sprintf("Not equal: \n"+ 571 | "expected: %s\n"+ 572 | "actual : %s%s", expected, actual, diff), msgAndArgs...) 573 | } 574 | 575 | return true 576 | 577 | } 578 | 579 | // EqualExportedValues asserts that the types of two objects are equal and their public 580 | // fields are also equal. This is useful for comparing structs that have private fields 581 | // that could potentially differ. 582 | // 583 | // type S struct { 584 | // Exported int 585 | // notExported int 586 | // } 587 | // assert.EqualExportedValues(S{1, 2}, S{1, 3}) => true 588 | // assert.EqualExportedValues(S{1, 2}, S{2, 3}) => false 589 | func EqualExportedValues(expected, actual interface{}, msgAndArgs ...interface{}) bool { 590 | 591 | aType := reflect.TypeOf(expected) 592 | bType := reflect.TypeOf(actual) 593 | 594 | if aType != bType { 595 | return Fail(fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) 596 | } 597 | 598 | expected = copyExportedFields(expected) 599 | actual = copyExportedFields(actual) 600 | 601 | if !ObjectsAreEqualValues(expected, actual) { 602 | diff := diff(expected, actual) 603 | expected, actual = formatUnequalValues(expected, actual) 604 | return Fail(fmt.Sprintf("Not equal (comparing only exported fields): \n"+ 605 | "expected: %s\n"+ 606 | "actual : %s%s", expected, actual, diff), msgAndArgs...) 607 | } 608 | 609 | return true 610 | } 611 | 612 | // Exactly asserts that two objects are equal in value and type. 613 | // 614 | // assert.Exactly(int32(123), int64(123)) 615 | func Exactly(expected, actual interface{}, msgAndArgs ...interface{}) bool { 616 | 617 | aType := reflect.TypeOf(expected) 618 | bType := reflect.TypeOf(actual) 619 | 620 | if aType != bType { 621 | return Fail(fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) 622 | } 623 | 624 | return Equal(expected, actual, msgAndArgs...) 625 | 626 | } 627 | 628 | // NotNil asserts that the specified object is not nil. 629 | // 630 | // assert.NotNil(err) 631 | func NotNil(object interface{}, msgAndArgs ...interface{}) bool { 632 | if !isNil(object) { 633 | return true 634 | } 635 | return Fail("Expected value not to be nil.", msgAndArgs...) 636 | } 637 | 638 | // isNil checks if a specified object is nil or not, without Failing. 639 | func isNil(object interface{}) bool { 640 | if object == nil { 641 | return true 642 | } 643 | 644 | value := reflect.ValueOf(object) 645 | switch value.Kind() { 646 | case 647 | reflect.Chan, reflect.Func, 648 | reflect.Interface, reflect.Map, 649 | reflect.Ptr, reflect.Slice, reflect.UnsafePointer: 650 | 651 | return value.IsNil() 652 | } 653 | 654 | return false 655 | } 656 | 657 | // Nil asserts that the specified object is nil. 658 | // 659 | // assert.Nil(err) 660 | func Nil(object interface{}, msgAndArgs ...interface{}) bool { 661 | if isNil(object) { 662 | return true 663 | } 664 | return Fail(fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) 665 | } 666 | 667 | // isEmpty gets whether the specified object is considered empty or not. 668 | func isEmpty(object interface{}) bool { 669 | 670 | // get nil case out of the way 671 | if object == nil { 672 | return true 673 | } 674 | 675 | objValue := reflect.ValueOf(object) 676 | 677 | switch objValue.Kind() { 678 | // collection types are empty when they have no element 679 | case reflect.Chan, reflect.Map, reflect.Slice: 680 | return objValue.Len() == 0 681 | // pointers are empty if nil or if the value they point to is empty 682 | case reflect.Ptr: 683 | if objValue.IsNil() { 684 | return true 685 | } 686 | deref := objValue.Elem().Interface() 687 | return isEmpty(deref) 688 | // for all other types, compare against the zero value 689 | // array types are empty when they match their zero-initialized state 690 | default: 691 | zero := reflect.Zero(objValue.Type()) 692 | return reflect.DeepEqual(object, zero.Interface()) 693 | } 694 | } 695 | 696 | // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either 697 | // a slice or a channel with len == 0. 698 | // 699 | // assert.Empty(obj) 700 | func Empty(object interface{}, msgAndArgs ...interface{}) bool { 701 | pass := isEmpty(object) 702 | if !pass { 703 | Fail(fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) 704 | } 705 | 706 | return pass 707 | 708 | } 709 | 710 | // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either 711 | // a slice or a channel with len == 0. 712 | // 713 | // if assert.NotEmpty(obj) { 714 | // assert.Equal("two", obj[1]) 715 | // } 716 | func NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { 717 | pass := !isEmpty(object) 718 | if !pass { 719 | Fail(fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) 720 | } 721 | 722 | return pass 723 | 724 | } 725 | 726 | // getLen tries to get the length of an object. 727 | // It returns (0, false) if impossible. 728 | func getLen(x interface{}) (length int, ok bool) { 729 | v := reflect.ValueOf(x) 730 | defer func() { 731 | ok = recover() == nil 732 | }() 733 | return v.Len(), true 734 | } 735 | 736 | // Len asserts that the specified object has specific length. 737 | // Len also fails if the object has a type that len() not accept. 738 | // 739 | // assert.Len(mySlice, 3) 740 | func Len(object interface{}, length int, msgAndArgs ...interface{}) bool { 741 | l, ok := getLen(object) 742 | if !ok { 743 | return Fail(fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...) 744 | } 745 | 746 | if l != length { 747 | return Fail(fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) 748 | } 749 | return true 750 | } 751 | 752 | // True asserts that the specified value is true. 753 | // 754 | // assert.True(myBool) 755 | func True(value bool, msgAndArgs ...interface{}) bool { 756 | if !value { 757 | return Fail("Should be true", msgAndArgs...) 758 | } 759 | 760 | return true 761 | 762 | } 763 | 764 | // False asserts that the specified value is false. 765 | // 766 | // assert.False(myBool) 767 | func False(value bool, msgAndArgs ...interface{}) bool { 768 | if value { 769 | return Fail("Should be false", msgAndArgs...) 770 | } 771 | 772 | return true 773 | 774 | } 775 | 776 | // NotEqual asserts that the specified values are NOT equal. 777 | // 778 | // assert.NotEqual(obj1, obj2) 779 | // 780 | // Pointer variable equality is determined based on the equality of the 781 | // referenced values (as opposed to the memory addresses). 782 | func NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool { 783 | if err := validateEqualArgs(expected, actual); err != nil { 784 | return Fail(fmt.Sprintf("Invalid operation: %#v != %#v (%s)", 785 | expected, actual, err), msgAndArgs...) 786 | } 787 | 788 | if ObjectsAreEqual(expected, actual) { 789 | return Fail(fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) 790 | } 791 | 792 | return true 793 | 794 | } 795 | 796 | // NotEqualValues asserts that two objects are not equal even when converted to the same type 797 | // 798 | // assert.NotEqualValues(obj1, obj2) 799 | func NotEqualValues(expected, actual interface{}, msgAndArgs ...interface{}) bool { 800 | 801 | if ObjectsAreEqualValues(expected, actual) { 802 | return Fail(fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) 803 | } 804 | 805 | return true 806 | } 807 | 808 | // containsElement try loop over the list check if the list includes the element. 809 | // return (false, false) if impossible. 810 | // return (true, false) if element was not found. 811 | // return (true, true) if element was found. 812 | func containsElement(list interface{}, element interface{}) (ok, found bool) { 813 | 814 | listValue := reflect.ValueOf(list) 815 | listType := reflect.TypeOf(list) 816 | if listType == nil { 817 | return false, false 818 | } 819 | listKind := listType.Kind() 820 | defer func() { 821 | if e := recover(); e != nil { 822 | ok = false 823 | found = false 824 | } 825 | }() 826 | 827 | if listKind == reflect.String { 828 | elementValue := reflect.ValueOf(element) 829 | return true, strings.Contains(listValue.String(), elementValue.String()) 830 | } 831 | 832 | if listKind == reflect.Map { 833 | mapKeys := listValue.MapKeys() 834 | for i := 0; i < len(mapKeys); i++ { 835 | if ObjectsAreEqual(mapKeys[i].Interface(), element) { 836 | return true, true 837 | } 838 | } 839 | return true, false 840 | } 841 | 842 | for i := 0; i < listValue.Len(); i++ { 843 | if ObjectsAreEqual(listValue.Index(i).Interface(), element) { 844 | return true, true 845 | } 846 | } 847 | return true, false 848 | 849 | } 850 | 851 | // Contains asserts that the specified string, list(array, slice...) or map contains the 852 | // specified substring or element. 853 | // 854 | // assert.Contains("Hello World", "World") 855 | // assert.Contains(["Hello", "World"], "World") 856 | // assert.Contains({"Hello": "World"}, "Hello") 857 | func Contains(s, contains interface{}, msgAndArgs ...interface{}) bool { 858 | 859 | ok, found := containsElement(s, contains) 860 | if !ok { 861 | return Fail(fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) 862 | } 863 | if !found { 864 | return Fail(fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) 865 | } 866 | 867 | return true 868 | 869 | } 870 | 871 | // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the 872 | // specified substring or element. 873 | // 874 | // assert.NotContains("Hello World", "Earth") 875 | // assert.NotContains(["Hello", "World"], "Earth") 876 | // assert.NotContains({"Hello": "World"}, "Earth") 877 | func NotContains(s, contains interface{}, msgAndArgs ...interface{}) bool { 878 | 879 | ok, found := containsElement(s, contains) 880 | if !ok { 881 | return Fail(fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) 882 | } 883 | if found { 884 | return Fail(fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...) 885 | } 886 | 887 | return true 888 | 889 | } 890 | 891 | // Subset asserts that the specified list(array, slice...) or map contains all 892 | // elements given in the specified subset list(array, slice...) or map. 893 | // 894 | // assert.Subset([1, 2, 3], [1, 2]) 895 | // assert.Subset({"x": 1, "y": 2}, {"x": 1}) 896 | func Subset(list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { 897 | if subset == nil { 898 | return true // we consider nil to be equal to the nil set 899 | } 900 | 901 | listKind := reflect.TypeOf(list).Kind() 902 | if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { 903 | return Fail(fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) 904 | } 905 | 906 | subsetKind := reflect.TypeOf(subset).Kind() 907 | if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { 908 | return Fail(fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) 909 | } 910 | 911 | if subsetKind == reflect.Map && listKind == reflect.Map { 912 | subsetMap := reflect.ValueOf(subset) 913 | actualMap := reflect.ValueOf(list) 914 | 915 | for _, k := range subsetMap.MapKeys() { 916 | ev := subsetMap.MapIndex(k) 917 | av := actualMap.MapIndex(k) 918 | 919 | if !av.IsValid() { 920 | return Fail(fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) 921 | } 922 | if !ObjectsAreEqual(ev.Interface(), av.Interface()) { 923 | return Fail(fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) 924 | } 925 | } 926 | 927 | return true 928 | } 929 | 930 | subsetList := reflect.ValueOf(subset) 931 | for i := 0; i < subsetList.Len(); i++ { 932 | element := subsetList.Index(i).Interface() 933 | ok, found := containsElement(list, element) 934 | if !ok { 935 | return Fail(fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) 936 | } 937 | if !found { 938 | return Fail(fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...) 939 | } 940 | } 941 | 942 | return true 943 | } 944 | 945 | // NotSubset asserts that the specified list(array, slice...) or map does NOT 946 | // contain all elements given in the specified subset list(array, slice...) or 947 | // map. 948 | // 949 | // assert.NotSubset([1, 3, 4], [1, 2]) 950 | // assert.NotSubset({"x": 1, "y": 2}, {"z": 3}) 951 | func NotSubset(list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { 952 | if subset == nil { 953 | return Fail("nil is the empty set which is a subset of every set", msgAndArgs...) 954 | } 955 | 956 | listKind := reflect.TypeOf(list).Kind() 957 | if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { 958 | return Fail(fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) 959 | } 960 | 961 | subsetKind := reflect.TypeOf(subset).Kind() 962 | if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { 963 | return Fail(fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) 964 | } 965 | 966 | if subsetKind == reflect.Map && listKind == reflect.Map { 967 | subsetMap := reflect.ValueOf(subset) 968 | actualMap := reflect.ValueOf(list) 969 | 970 | for _, k := range subsetMap.MapKeys() { 971 | ev := subsetMap.MapIndex(k) 972 | av := actualMap.MapIndex(k) 973 | 974 | if !av.IsValid() { 975 | return true 976 | } 977 | if !ObjectsAreEqual(ev.Interface(), av.Interface()) { 978 | return true 979 | } 980 | } 981 | 982 | return Fail(fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) 983 | } 984 | 985 | subsetList := reflect.ValueOf(subset) 986 | for i := 0; i < subsetList.Len(); i++ { 987 | element := subsetList.Index(i).Interface() 988 | ok, found := containsElement(list, element) 989 | if !ok { 990 | return Fail(fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) 991 | } 992 | if !found { 993 | return true 994 | } 995 | } 996 | 997 | return Fail(fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) 998 | } 999 | 1000 | // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified 1001 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 1002 | // the number of appearances of each of them in both lists should match. 1003 | // 1004 | // assert.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) 1005 | func ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { 1006 | if isEmpty(listA) && isEmpty(listB) { 1007 | return true 1008 | } 1009 | 1010 | if !isList(listA, msgAndArgs...) || !isList(listB, msgAndArgs...) { 1011 | return false 1012 | } 1013 | 1014 | extraA, extraB := diffLists(listA, listB) 1015 | 1016 | if len(extraA) == 0 && len(extraB) == 0 { 1017 | return true 1018 | } 1019 | 1020 | return Fail(formatListDiff(listA, listB, extraA, extraB), msgAndArgs...) 1021 | } 1022 | 1023 | // isList checks that the provided value is array or slice. 1024 | func isList(list interface{}, msgAndArgs ...interface{}) (ok bool) { 1025 | kind := reflect.TypeOf(list).Kind() 1026 | if kind != reflect.Array && kind != reflect.Slice { 1027 | return Fail(fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), 1028 | msgAndArgs...) 1029 | } 1030 | return true 1031 | } 1032 | 1033 | // diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. 1034 | // If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and 1035 | // 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. 1036 | func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { 1037 | aValue := reflect.ValueOf(listA) 1038 | bValue := reflect.ValueOf(listB) 1039 | 1040 | aLen := aValue.Len() 1041 | bLen := bValue.Len() 1042 | 1043 | // Mark indexes in bValue that we already used 1044 | visited := make([]bool, bLen) 1045 | for i := 0; i < aLen; i++ { 1046 | element := aValue.Index(i).Interface() 1047 | found := false 1048 | for j := 0; j < bLen; j++ { 1049 | if visited[j] { 1050 | continue 1051 | } 1052 | if ObjectsAreEqual(bValue.Index(j).Interface(), element) { 1053 | visited[j] = true 1054 | found = true 1055 | break 1056 | } 1057 | } 1058 | if !found { 1059 | extraA = append(extraA, element) 1060 | } 1061 | } 1062 | 1063 | for j := 0; j < bLen; j++ { 1064 | if visited[j] { 1065 | continue 1066 | } 1067 | extraB = append(extraB, bValue.Index(j).Interface()) 1068 | } 1069 | 1070 | return 1071 | } 1072 | 1073 | func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string { 1074 | var msg bytes.Buffer 1075 | 1076 | msg.WriteString("elements differ") 1077 | if len(extraA) > 0 { 1078 | msg.WriteString("\n\nextra elements in list A:\n") 1079 | msg.WriteString(spewConfig.Sdump(extraA)) 1080 | } 1081 | if len(extraB) > 0 { 1082 | msg.WriteString("\n\nextra elements in list B:\n") 1083 | msg.WriteString(spewConfig.Sdump(extraB)) 1084 | } 1085 | msg.WriteString("\n\nlistA:\n") 1086 | msg.WriteString(spewConfig.Sdump(listA)) 1087 | msg.WriteString("\n\nlistB:\n") 1088 | msg.WriteString(spewConfig.Sdump(listB)) 1089 | 1090 | return msg.String() 1091 | } 1092 | 1093 | // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified 1094 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 1095 | // the number of appearances of each of them in both lists should not match. 1096 | // This is an inverse of ElementsMatch. 1097 | // 1098 | // assert.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false 1099 | // 1100 | // assert.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true 1101 | // 1102 | // assert.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true 1103 | func NotElementsMatch(listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { 1104 | if isEmpty(listA) && isEmpty(listB) { 1105 | return Fail("listA and listB contain the same elements", msgAndArgs) 1106 | } 1107 | 1108 | if !isList(listA, msgAndArgs...) { 1109 | return Fail("listA is not a list type", msgAndArgs...) 1110 | } 1111 | if !isList(listB, msgAndArgs...) { 1112 | return Fail("listB is not a list type", msgAndArgs...) 1113 | } 1114 | 1115 | extraA, extraB := diffLists(listA, listB) 1116 | if len(extraA) == 0 && len(extraB) == 0 { 1117 | return Fail("listA and listB contain the same elements", msgAndArgs) 1118 | } 1119 | 1120 | return true 1121 | } 1122 | 1123 | // Condition uses a Comparison to assert a complex condition. 1124 | func Condition(comp Comparison, msgAndArgs ...interface{}) bool { 1125 | result := comp() 1126 | if !result { 1127 | Fail("Condition failed!", msgAndArgs...) 1128 | } 1129 | return result 1130 | } 1131 | 1132 | // PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics 1133 | // methods, and represents a simple func that takes no arguments, and returns nothing. 1134 | type PanicTestFunc func() 1135 | 1136 | // didPanic returns true if the function passed to it panics. Otherwise, it returns false. 1137 | func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { 1138 | didPanic = true 1139 | 1140 | defer func() { 1141 | message = recover() 1142 | if didPanic { 1143 | stack = string(debug.Stack()) 1144 | } 1145 | }() 1146 | 1147 | // call the target function 1148 | f() 1149 | didPanic = false 1150 | 1151 | return 1152 | } 1153 | 1154 | // Panics asserts that the code inside the specified PanicTestFunc panics. 1155 | // 1156 | // assert.Panics(func(){ GoCrazy() }) 1157 | func Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { 1158 | 1159 | if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic { 1160 | return Fail(fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) 1161 | } 1162 | 1163 | return true 1164 | } 1165 | 1166 | // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that 1167 | // the recovered panic value equals the expected panic value. 1168 | // 1169 | // assert.PanicsWithValue("crazy error", func(){ GoCrazy() }) 1170 | func PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { 1171 | 1172 | funcDidPanic, panicValue, panickedStack := didPanic(f) 1173 | if !funcDidPanic { 1174 | return Fail(fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) 1175 | } 1176 | if panicValue != expected { 1177 | return Fail(fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...) 1178 | } 1179 | 1180 | return true 1181 | } 1182 | 1183 | // PanicsWithError asserts that the code inside the specified PanicTestFunc 1184 | // panics, and that the recovered panic value is an error that satisfies the 1185 | // EqualError comparison. 1186 | // 1187 | // assert.PanicsWithError("crazy error", func(){ GoCrazy() }) 1188 | func PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { 1189 | 1190 | funcDidPanic, panicValue, panickedStack := didPanic(f) 1191 | if !funcDidPanic { 1192 | return Fail(fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) 1193 | } 1194 | panicErr, ok := panicValue.(error) 1195 | if !ok || panicErr.Error() != errString { 1196 | return Fail(fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) 1197 | } 1198 | 1199 | return true 1200 | } 1201 | 1202 | // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. 1203 | // 1204 | // assert.NotPanics(func(){ RemainCalm() }) 1205 | func NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { 1206 | 1207 | if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic { 1208 | return Fail(fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...) 1209 | } 1210 | 1211 | return true 1212 | } 1213 | 1214 | // WithinDuration asserts that the two times are within duration delta of each other. 1215 | // 1216 | // assert.WithinDuration(time.Now(), time.Now(), 10*time.Second) 1217 | func WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { 1218 | 1219 | dt := expected.Sub(actual) 1220 | if dt < -delta || dt > delta { 1221 | return Fail(fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) 1222 | } 1223 | 1224 | return true 1225 | } 1226 | 1227 | // WithinRange asserts that a time is within a time range (inclusive). 1228 | // 1229 | // assert.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) 1230 | func WithinRange(actual, start, end time.Time, msgAndArgs ...interface{}) bool { 1231 | 1232 | if end.Before(start) { 1233 | return Fail("Start should be before end", msgAndArgs...) 1234 | } 1235 | 1236 | if actual.Before(start) { 1237 | return Fail(fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...) 1238 | } else if actual.After(end) { 1239 | return Fail(fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...) 1240 | } 1241 | 1242 | return true 1243 | } 1244 | 1245 | func toFloat(x interface{}) (float64, bool) { 1246 | var xf float64 1247 | xok := true 1248 | 1249 | switch xn := x.(type) { 1250 | case uint: 1251 | xf = float64(xn) 1252 | case uint8: 1253 | xf = float64(xn) 1254 | case uint16: 1255 | xf = float64(xn) 1256 | case uint32: 1257 | xf = float64(xn) 1258 | case uint64: 1259 | xf = float64(xn) 1260 | case int: 1261 | xf = float64(xn) 1262 | case int8: 1263 | xf = float64(xn) 1264 | case int16: 1265 | xf = float64(xn) 1266 | case int32: 1267 | xf = float64(xn) 1268 | case int64: 1269 | xf = float64(xn) 1270 | case float32: 1271 | xf = float64(xn) 1272 | case float64: 1273 | xf = xn 1274 | case time.Duration: 1275 | xf = float64(xn) 1276 | default: 1277 | xok = false 1278 | } 1279 | 1280 | return xf, xok 1281 | } 1282 | 1283 | // InDelta asserts that the two numerals are within delta of each other. 1284 | // 1285 | // assert.InDelta(math.Pi, 22/7.0, 0.01) 1286 | func InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { 1287 | 1288 | af, aok := toFloat(expected) 1289 | bf, bok := toFloat(actual) 1290 | 1291 | if !aok || !bok { 1292 | return Fail("Parameters must be numerical", msgAndArgs...) 1293 | } 1294 | 1295 | if math.IsNaN(af) && math.IsNaN(bf) { 1296 | return true 1297 | } 1298 | 1299 | if math.IsNaN(af) { 1300 | return Fail("Expected must not be NaN", msgAndArgs...) 1301 | } 1302 | 1303 | if math.IsNaN(bf) { 1304 | return Fail(fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...) 1305 | } 1306 | 1307 | dt := af - bf 1308 | if dt < -delta || dt > delta { 1309 | return Fail(fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) 1310 | } 1311 | 1312 | return true 1313 | } 1314 | 1315 | // InDeltaSlice is the same as InDelta, except it compares two slices. 1316 | func InDeltaSlice(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { 1317 | if expected == nil || actual == nil || 1318 | reflect.TypeOf(actual).Kind() != reflect.Slice || 1319 | reflect.TypeOf(expected).Kind() != reflect.Slice { 1320 | return Fail("Parameters must be slice", msgAndArgs...) 1321 | } 1322 | 1323 | actualSlice := reflect.ValueOf(actual) 1324 | expectedSlice := reflect.ValueOf(expected) 1325 | 1326 | for i := 0; i < actualSlice.Len(); i++ { 1327 | result := InDelta(actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...) 1328 | if !result { 1329 | return result 1330 | } 1331 | } 1332 | 1333 | return true 1334 | } 1335 | 1336 | // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. 1337 | func InDeltaMapValues(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { 1338 | if expected == nil || actual == nil || 1339 | reflect.TypeOf(actual).Kind() != reflect.Map || 1340 | reflect.TypeOf(expected).Kind() != reflect.Map { 1341 | return Fail("Arguments must be maps", msgAndArgs...) 1342 | } 1343 | 1344 | expectedMap := reflect.ValueOf(expected) 1345 | actualMap := reflect.ValueOf(actual) 1346 | 1347 | if expectedMap.Len() != actualMap.Len() { 1348 | return Fail("Arguments must have the same number of keys", msgAndArgs...) 1349 | } 1350 | 1351 | for _, k := range expectedMap.MapKeys() { 1352 | ev := expectedMap.MapIndex(k) 1353 | av := actualMap.MapIndex(k) 1354 | 1355 | if !ev.IsValid() { 1356 | return Fail(fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...) 1357 | } 1358 | 1359 | if !av.IsValid() { 1360 | return Fail(fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...) 1361 | } 1362 | 1363 | if !InDelta( 1364 | 1365 | ev.Interface(), 1366 | av.Interface(), 1367 | delta, 1368 | msgAndArgs..., 1369 | ) { 1370 | return false 1371 | } 1372 | } 1373 | 1374 | return true 1375 | } 1376 | 1377 | func calcRelativeError(expected, actual interface{}) (float64, error) { 1378 | af, aok := toFloat(expected) 1379 | bf, bok := toFloat(actual) 1380 | if !aok || !bok { 1381 | return 0, fmt.Errorf("Parameters must be numerical") 1382 | } 1383 | if math.IsNaN(af) && math.IsNaN(bf) { 1384 | return 0, nil 1385 | } 1386 | if math.IsNaN(af) { 1387 | return 0, errors.New("expected value must not be NaN") 1388 | } 1389 | if af == 0 { 1390 | return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") 1391 | } 1392 | if math.IsNaN(bf) { 1393 | return 0, errors.New("actual value must not be NaN") 1394 | } 1395 | 1396 | return math.Abs(af-bf) / math.Abs(af), nil 1397 | } 1398 | 1399 | // InEpsilon asserts that expected and actual have a relative error less than epsilon 1400 | func InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { 1401 | if math.IsNaN(epsilon) { 1402 | return Fail("epsilon must not be NaN", msgAndArgs...) 1403 | } 1404 | actualEpsilon, err := calcRelativeError(expected, actual) 1405 | if err != nil { 1406 | return Fail(err.Error(), msgAndArgs...) 1407 | } 1408 | if math.IsNaN(actualEpsilon) { 1409 | return Fail("relative error is NaN", msgAndArgs...) 1410 | } 1411 | if actualEpsilon > epsilon { 1412 | return Fail(fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ 1413 | " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...) 1414 | } 1415 | 1416 | return true 1417 | } 1418 | 1419 | // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. 1420 | func InEpsilonSlice(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { 1421 | 1422 | if expected == nil || actual == nil { 1423 | return Fail("Parameters must be slice", msgAndArgs...) 1424 | } 1425 | 1426 | expectedSlice := reflect.ValueOf(expected) 1427 | actualSlice := reflect.ValueOf(actual) 1428 | 1429 | if expectedSlice.Type().Kind() != reflect.Slice { 1430 | return Fail("Expected value must be slice", msgAndArgs...) 1431 | } 1432 | 1433 | expectedLen := expectedSlice.Len() 1434 | if !IsType(expected, actual) || !Len(actual, expectedLen) { 1435 | return false 1436 | } 1437 | 1438 | for i := 0; i < expectedLen; i++ { 1439 | if !InEpsilon(expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) { 1440 | return false 1441 | } 1442 | } 1443 | 1444 | return true 1445 | } 1446 | 1447 | /* 1448 | Errors 1449 | */ 1450 | 1451 | // NoError asserts that a function returned no error (i.e. `nil`). 1452 | // 1453 | // actualObj, err := SomeFunction() 1454 | // if assert.NoError(err) { 1455 | // assert.Equal(expectedObj, actualObj) 1456 | // } 1457 | func NoError(err error, msgAndArgs ...interface{}) bool { 1458 | if err != nil { 1459 | return Fail(fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) 1460 | } 1461 | 1462 | return true 1463 | } 1464 | 1465 | // Error asserts that a function returned an error (i.e. not `nil`). 1466 | // 1467 | // actualObj, err := SomeFunction() 1468 | // if assert.Error(err) { 1469 | // assert.Equal(expectedError, err) 1470 | // } 1471 | func Error(err error, msgAndArgs ...interface{}) bool { 1472 | if err == nil { 1473 | return Fail("An error is expected but got nil.", msgAndArgs...) 1474 | } 1475 | 1476 | return true 1477 | } 1478 | 1479 | // EqualError asserts that a function returned an error (i.e. not `nil`) 1480 | // and that it is equal to the provided error. 1481 | // 1482 | // actualObj, err := SomeFunction() 1483 | // assert.EqualError(err, expectedErrorString) 1484 | func EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { 1485 | if !Error(theError, msgAndArgs...) { 1486 | return false 1487 | } 1488 | expected := errString 1489 | actual := theError.Error() 1490 | // don't need to use deep equals here, we know they are both strings 1491 | if expected != actual { 1492 | return Fail(fmt.Sprintf("Error message not equal:\n"+ 1493 | "expected: %q\n"+ 1494 | "actual : %q", expected, actual), msgAndArgs...) 1495 | } 1496 | return true 1497 | } 1498 | 1499 | // ErrorContains asserts that a function returned an error (i.e. not `nil`) 1500 | // and that the error contains the specified substring. 1501 | // 1502 | // actualObj, err := SomeFunction() 1503 | // assert.ErrorContains(err, expectedErrorSubString) 1504 | func ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { 1505 | if !Error(theError, msgAndArgs...) { 1506 | return false 1507 | } 1508 | 1509 | actual := theError.Error() 1510 | if !strings.Contains(actual, contains) { 1511 | return Fail(fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) 1512 | } 1513 | 1514 | return true 1515 | } 1516 | 1517 | // matchRegexp return true if a specified regexp matches a string. 1518 | func matchRegexp(rx interface{}, str interface{}) bool { 1519 | var r *regexp.Regexp 1520 | if rr, ok := rx.(*regexp.Regexp); ok { 1521 | r = rr 1522 | } else { 1523 | r = regexp.MustCompile(fmt.Sprint(rx)) 1524 | } 1525 | 1526 | switch v := str.(type) { 1527 | case []byte: 1528 | return r.Match(v) 1529 | case string: 1530 | return r.MatchString(v) 1531 | default: 1532 | return r.MatchString(fmt.Sprint(v)) 1533 | } 1534 | 1535 | } 1536 | 1537 | // Regexp asserts that a specified regexp matches a string. 1538 | // 1539 | // assert.Regexp(regexp.MustCompile("start"), "it's starting") 1540 | // assert.Regexp("start...$", "it's not starting") 1541 | func Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { 1542 | 1543 | match := matchRegexp(rx, str) 1544 | 1545 | if !match { 1546 | Fail(fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...) 1547 | } 1548 | 1549 | return match 1550 | } 1551 | 1552 | // NotRegexp asserts that a specified regexp does not match a string. 1553 | // 1554 | // assert.NotRegexp(regexp.MustCompile("starts"), "it's starting") 1555 | // assert.NotRegexp("^start", "it's not starting") 1556 | func NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { 1557 | match := matchRegexp(rx, str) 1558 | 1559 | if match { 1560 | Fail(fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) 1561 | } 1562 | 1563 | return !match 1564 | 1565 | } 1566 | 1567 | // Zero asserts that i is the zero value for its type. 1568 | func Zero(i interface{}, msgAndArgs ...interface{}) bool { 1569 | if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { 1570 | return Fail(fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) 1571 | } 1572 | return true 1573 | } 1574 | 1575 | // NotZero asserts that i is not the zero value for its type. 1576 | func NotZero(i interface{}, msgAndArgs ...interface{}) bool { 1577 | if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { 1578 | return Fail(fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) 1579 | } 1580 | return true 1581 | } 1582 | 1583 | // FileExists checks whether a file exists in the given path. It also fails if 1584 | // the path points to a directory or there is an error when trying to check the file. 1585 | func FileExists(path string, msgAndArgs ...interface{}) bool { 1586 | info, err := os.Lstat(path) 1587 | if err != nil { 1588 | if os.IsNotExist(err) { 1589 | return Fail(fmt.Sprintf("unable to find file %q", path), msgAndArgs...) 1590 | } 1591 | return Fail(fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) 1592 | } 1593 | if info.IsDir() { 1594 | return Fail(fmt.Sprintf("%q is a directory", path), msgAndArgs...) 1595 | } 1596 | return true 1597 | } 1598 | 1599 | // NoFileExists checks whether a file does not exist in a given path. It fails 1600 | // if the path points to an existing _file_ only. 1601 | func NoFileExists(path string, msgAndArgs ...interface{}) bool { 1602 | info, err := os.Lstat(path) 1603 | if err != nil { 1604 | return true 1605 | } 1606 | if info.IsDir() { 1607 | return true 1608 | } 1609 | return Fail(fmt.Sprintf("file %q exists", path), msgAndArgs...) 1610 | } 1611 | 1612 | // DirExists checks whether a directory exists in the given path. It also fails 1613 | // if the path is a file rather a directory or there is an error checking whether it exists. 1614 | func DirExists(path string, msgAndArgs ...interface{}) bool { 1615 | info, err := os.Lstat(path) 1616 | if err != nil { 1617 | if os.IsNotExist(err) { 1618 | return Fail(fmt.Sprintf("unable to find file %q", path), msgAndArgs...) 1619 | } 1620 | return Fail(fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) 1621 | } 1622 | if !info.IsDir() { 1623 | return Fail(fmt.Sprintf("%q is a file", path), msgAndArgs...) 1624 | } 1625 | return true 1626 | } 1627 | 1628 | // NoDirExists checks whether a directory does not exist in the given path. 1629 | // It fails if the path points to an existing _directory_ only. 1630 | func NoDirExists(path string, msgAndArgs ...interface{}) bool { 1631 | info, err := os.Lstat(path) 1632 | if err != nil { 1633 | if os.IsNotExist(err) { 1634 | return true 1635 | } 1636 | return true 1637 | } 1638 | if !info.IsDir() { 1639 | return true 1640 | } 1641 | return Fail(fmt.Sprintf("directory %q exists", path), msgAndArgs...) 1642 | } 1643 | 1644 | // JSONEq asserts that two JSON strings are equivalent. 1645 | // 1646 | // assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) 1647 | func JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { 1648 | var expectedJSONAsInterface, actualJSONAsInterface interface{} 1649 | 1650 | if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { 1651 | return Fail(fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) 1652 | } 1653 | 1654 | if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { 1655 | return Fail(fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) 1656 | } 1657 | 1658 | return Equal(expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) 1659 | } 1660 | 1661 | // YAMLEq asserts that two YAML strings are equivalent. 1662 | 1663 | func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { 1664 | t := reflect.TypeOf(v) 1665 | k := t.Kind() 1666 | 1667 | if k == reflect.Ptr { 1668 | t = t.Elem() 1669 | k = t.Kind() 1670 | } 1671 | return t, k 1672 | } 1673 | 1674 | // diff returns a diff of both values as long as both are of the same type and 1675 | // are a struct, map, slice, array or string. Otherwise it returns an empty string. 1676 | func diff(expected interface{}, actual interface{}) string { 1677 | if expected == nil || actual == nil { 1678 | return "" 1679 | } 1680 | 1681 | et, ek := typeAndKind(expected) 1682 | at, _ := typeAndKind(actual) 1683 | 1684 | if et != at { 1685 | return "" 1686 | } 1687 | 1688 | if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { 1689 | return "" 1690 | } 1691 | 1692 | var e, a string 1693 | 1694 | switch et { 1695 | case reflect.TypeOf(""): 1696 | e = reflect.ValueOf(expected).String() 1697 | a = reflect.ValueOf(actual).String() 1698 | case reflect.TypeOf(time.Time{}): 1699 | e = spewConfigStringerEnabled.Sdump(expected) 1700 | a = spewConfigStringerEnabled.Sdump(actual) 1701 | default: 1702 | e = spewConfig.Sdump(expected) 1703 | a = spewConfig.Sdump(actual) 1704 | } 1705 | 1706 | diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ 1707 | A: difflib.SplitLines(e), 1708 | B: difflib.SplitLines(a), 1709 | FromFile: "Expected", 1710 | FromDate: "", 1711 | ToFile: "Actual", 1712 | ToDate: "", 1713 | Context: 1, 1714 | }) 1715 | 1716 | return "\n\nDiff:\n" + diff 1717 | } 1718 | 1719 | func isFunction(arg interface{}) bool { 1720 | if arg == nil { 1721 | return false 1722 | } 1723 | return reflect.TypeOf(arg).Kind() == reflect.Func 1724 | } 1725 | 1726 | var spewConfig = spew.ConfigState{ 1727 | Indent: " ", 1728 | DisablePointerAddresses: true, 1729 | DisableCapacities: true, 1730 | SortKeys: true, 1731 | DisableMethods: true, 1732 | MaxDepth: 10, 1733 | } 1734 | 1735 | var spewConfigStringerEnabled = spew.ConfigState{ 1736 | Indent: " ", 1737 | DisablePointerAddresses: true, 1738 | DisableCapacities: true, 1739 | SortKeys: true, 1740 | MaxDepth: 10, 1741 | } 1742 | 1743 | type tHelper = interface { 1744 | Helper() 1745 | } 1746 | 1747 | // Eventually asserts that given condition will be met in waitFor time, 1748 | // periodically checking target function each tick. 1749 | // 1750 | // assert.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) 1751 | func Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { 1752 | 1753 | ch := make(chan bool, 1) 1754 | 1755 | timer := time.NewTimer(waitFor) 1756 | defer timer.Stop() 1757 | 1758 | ticker := time.NewTicker(tick) 1759 | defer ticker.Stop() 1760 | 1761 | for tick := ticker.C; ; { 1762 | select { 1763 | case <-timer.C: 1764 | return Fail("Condition never satisfied", msgAndArgs...) 1765 | case <-tick: 1766 | tick = nil 1767 | go func() { ch <- condition() }() 1768 | case v := <-ch: 1769 | if v { 1770 | return true 1771 | } 1772 | tick = ticker.C 1773 | } 1774 | } 1775 | } 1776 | 1777 | // CollectT implements the TestingT interface and collects all errors. 1778 | type CollectT struct { 1779 | // A slice of errors. Non-nil slice denotes a failure. 1780 | // If it's non-nil but len(c.errors) == 0, this is also a failure 1781 | // obtained by direct c.FailNow() call. 1782 | errors []error 1783 | } 1784 | 1785 | // Errorf collects the error. 1786 | func (c *CollectT) Errorf(format string, args ...interface{}) { 1787 | c.errors = append(c.errors, fmt.Errorf(format, args...)) 1788 | } 1789 | 1790 | // FailNow stops execution by calling runtime.Goexit. 1791 | func (c *CollectT) FailNow() { 1792 | c.fail() 1793 | runtime.Goexit() 1794 | } 1795 | 1796 | // Deprecated: That was a method for internal usage that should not have been published. Now just panics. 1797 | func (*CollectT) Reset() { 1798 | panic("Reset() is deprecated") 1799 | } 1800 | 1801 | // Deprecated: That was a method for internal usage that should not have been published. Now just panics. 1802 | func (*CollectT) Copy(TestingT) { 1803 | panic("Copy() is deprecated") 1804 | } 1805 | 1806 | func (c *CollectT) fail() { 1807 | if !c.failed() { 1808 | c.errors = []error{} // Make it non-nil to mark a failure. 1809 | } 1810 | } 1811 | 1812 | func (c *CollectT) failed() bool { 1813 | return c.errors != nil 1814 | } 1815 | 1816 | // EventuallyWithT asserts that given condition will be met in waitFor time, 1817 | // periodically checking target function each tick. In contrast to Eventually, 1818 | // it supplies a CollectT to the condition function, so that the condition 1819 | // function can use the CollectT to call other assertions. 1820 | // The condition is considered "met" if no errors are raised in a tick. 1821 | // The supplied CollectT collects all errors from one tick (if there are any). 1822 | // If the condition is not met before waitFor, the collected errors of 1823 | // the last tick are copied to t. 1824 | // 1825 | // externalValue := false 1826 | // go func() { 1827 | // time.Sleep(8*time.Second) 1828 | // externalValue = true 1829 | // }() 1830 | // assert.EventuallyWithT(func(c *assert.CollectT) { 1831 | // // add assertions as needed; any assertion failure will fail the current tick 1832 | // assert.True(c, externalValue, "expected 'externalValue' to be true") 1833 | // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") 1834 | func EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { 1835 | 1836 | var lastFinishedTickErrs []error 1837 | ch := make(chan *CollectT, 1) 1838 | 1839 | timer := time.NewTimer(waitFor) 1840 | defer timer.Stop() 1841 | 1842 | ticker := time.NewTicker(tick) 1843 | defer ticker.Stop() 1844 | 1845 | for tick := ticker.C; ; { 1846 | select { 1847 | case <-timer.C: 1848 | for _, err := range lastFinishedTickErrs { 1849 | panic(fmt.Errorf("%v", err)) 1850 | } 1851 | return Fail("Condition never satisfied", msgAndArgs...) 1852 | case <-tick: 1853 | tick = nil 1854 | go func() { 1855 | collect := new(CollectT) 1856 | defer func() { 1857 | ch <- collect 1858 | }() 1859 | condition(collect) 1860 | }() 1861 | case collect := <-ch: 1862 | if !collect.failed() { 1863 | return true 1864 | } 1865 | // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. 1866 | lastFinishedTickErrs = collect.errors 1867 | tick = ticker.C 1868 | } 1869 | } 1870 | } 1871 | 1872 | // Never asserts that the given condition doesn't satisfy in waitFor time, 1873 | // periodically checking the target function each tick. 1874 | // 1875 | // assert.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) 1876 | func Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { 1877 | 1878 | ch := make(chan bool, 1) 1879 | 1880 | timer := time.NewTimer(waitFor) 1881 | defer timer.Stop() 1882 | 1883 | ticker := time.NewTicker(tick) 1884 | defer ticker.Stop() 1885 | 1886 | for tick := ticker.C; ; { 1887 | select { 1888 | case <-timer.C: 1889 | return true 1890 | case <-tick: 1891 | tick = nil 1892 | go func() { ch <- condition() }() 1893 | case v := <-ch: 1894 | if v { 1895 | return Fail("Condition satisfied", msgAndArgs...) 1896 | } 1897 | tick = ticker.C 1898 | } 1899 | } 1900 | } 1901 | 1902 | // ErrorIs asserts that at least one of the errors in err's chain matches target. 1903 | // This is a wrapper for errors.Is. 1904 | func ErrorIs(err, target error, msgAndArgs ...interface{}) bool { 1905 | if errors.Is(err, target) { 1906 | return true 1907 | } 1908 | 1909 | var expectedText string 1910 | if target != nil { 1911 | expectedText = target.Error() 1912 | } 1913 | 1914 | chain := buildErrorChainString(err) 1915 | 1916 | return Fail(fmt.Sprintf("Target error should be in err chain:\n"+ 1917 | "expected: %q\n"+ 1918 | "in chain: %s", expectedText, chain, 1919 | ), msgAndArgs...) 1920 | } 1921 | 1922 | // NotErrorIs asserts that none of the errors in err's chain matches target. 1923 | // This is a wrapper for errors.Is. 1924 | func NotErrorIs(err, target error, msgAndArgs ...interface{}) bool { 1925 | if !errors.Is(err, target) { 1926 | return true 1927 | } 1928 | 1929 | var expectedText string 1930 | if target != nil { 1931 | expectedText = target.Error() 1932 | } 1933 | 1934 | chain := buildErrorChainString(err) 1935 | 1936 | return Fail(fmt.Sprintf("Target error should not be in err chain:\n"+ 1937 | "found: %q\n"+ 1938 | "in chain: %s", expectedText, chain, 1939 | ), msgAndArgs...) 1940 | } 1941 | 1942 | // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. 1943 | // This is a wrapper for errors.As. 1944 | func ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { 1945 | if errors.As(err, target) { 1946 | return true 1947 | } 1948 | 1949 | chain := buildErrorChainString(err) 1950 | 1951 | return Fail(fmt.Sprintf("Should be in error chain:\n"+ 1952 | "expected: %q\n"+ 1953 | "in chain: %s", target, chain, 1954 | ), msgAndArgs...) 1955 | } 1956 | 1957 | // NotErrorAs asserts that none of the errors in err's chain matches target, 1958 | // but if so, sets target to that error value. 1959 | func NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { 1960 | if !errors.As(err, target) { 1961 | return true 1962 | } 1963 | 1964 | chain := buildErrorChainString(err) 1965 | 1966 | return Fail(fmt.Sprintf("Target error should not be in err chain:\n"+ 1967 | "found: %q\n"+ 1968 | "in chain: %s", target, chain, 1969 | ), msgAndArgs...) 1970 | } 1971 | 1972 | func buildErrorChainString(err error) string { 1973 | if err == nil { 1974 | return "" 1975 | } 1976 | 1977 | e := errors.Unwrap(err) 1978 | chain := fmt.Sprintf("%q", err.Error()) 1979 | for e != nil { 1980 | chain += fmt.Sprintf("\n\t%q", e.Error()) 1981 | e = errors.Unwrap(e) 1982 | } 1983 | return chain 1984 | } 1985 | -------------------------------------------------------------------------------- /codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | shopt -s inherit_errexit 5 | 6 | testify_file_skiplist=("assertion_forward.go" "forward_assertions.go" "doc.go" "extra") 7 | 8 | # Copy testify files. 9 | for f in ./testify/assert/*.go; do 10 | basename_f="$(basename "$f")" 11 | 12 | # Skip file. 13 | # shellcheck disable=SC2076 14 | if [[ " ${testify_file_skiplist[*]} " =~ " $basename_f " ]]; then 15 | echo "skipping $f" 16 | continue 17 | fi 18 | 19 | cp "$f" "$basename_f" 20 | done 21 | 22 | rm -f ./*_test.go 23 | 24 | for f in ./*.go; do 25 | # Remove TestingT arguments in function signature. 26 | sed -i -E 's/(t )?TestingT, //g' "$f" 27 | 28 | # Remove TestingT arguments in function call. 29 | sed -i 's/(t, /(/g' "$f" 30 | sed -i -E 's/^\s+t,$//g' "$f" 31 | 32 | # Remove: 33 | # if h, ok := t.(tHelper); ok { 34 | # h.Helper() 35 | # } 36 | sed -i '/if h, ok := t.(tHelper); ok {/,/}/d' "$f" 37 | 38 | # Remove: 39 | # if n, ok := t.(interface { 40 | # Name() string 41 | # }); ok { 42 | # content = append(content, labeledContent{"Test", n.Name()}) 43 | # } 44 | sed -i '/if n, ok := t.(interface {/,/}$/d' "$f" 45 | 46 | # Replace: 47 | # t.Errorf(.*) with panic(fmt.Errorf(.*)) 48 | sed -i -E 's/\s+t\.Errorf\((.*)\)/panic(fmt.Errorf(\1))/g' "$f" 49 | 50 | # Delete: 51 | # if t, ok := t.(failNower); ok { 52 | # t.FailNow() 53 | # } else { 54 | # panic("test failed and t is missing `FailNow()`") 55 | # } 56 | sed -i '/if t, ok := t.(failNower); ok {/,/}$/d' "$f" 57 | 58 | # Delete YAML functions: 59 | sed -i '/func YAML.*{/,/^}$/d' "$f" 60 | done 61 | 62 | # Create prod_* files that will contain empty function. 63 | for f in *.go; do 64 | if [ "$f" == "doc.go" ]; then 65 | continue 66 | fi 67 | 68 | # Prepend build tag to files if needed. 69 | if ! grep "//go:build assert" < "$f" > /dev/null; then 70 | sed -i '1i //go:build assert' "$f" 71 | fi 72 | 73 | cp "$f" "prod_$f" 74 | 75 | # Change build tag on prod file. 76 | sed -i 's|^//go:build assert|//go:build !assert|' "prod_$f" 77 | 78 | # Remove function body in prod file. 79 | sed -i 's/func\(.*\){$/func\1{}\n{/' "prod_$f" 80 | sed -i '/^{$/,/^}$/d' "prod_$f" 81 | 82 | # Replace: 83 | # func () returnType with func () 84 | sed -i 's/func\(.*\) [^()]* {}$/func\1{}/' "prod_$f" 85 | sed -i 's/func\(.*\) \(([^)]*)\) {}$/func\1{}/' "prod_$f" 86 | done 87 | 88 | gofmt -w ./*.go 89 | goimports -w ./*.go 90 | go mod tidy 91 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive debug assertions. 2 | // 3 | // # Example Usage 4 | // 5 | // The following is a complete example using assert in a function: 6 | // 7 | // import ( 8 | // "github.com/negrel/assert" 9 | // ) 10 | // 11 | // func Divide(a, b int) int { 12 | // assert.NotEqual(b, 0, "Can't divide by 0.") 13 | // return a / b 14 | // } 15 | // 16 | // # Debug Assertions 17 | // 18 | // Debug assertions are programming statements that help developers catch 19 | // logical errors during development by verifying assumptions about the 20 | // program's state. They're typically used to check conditions that should 21 | // always be true during normal program execution. If the condition is false, 22 | // the assertions is either wrong or there is a programming error. In 23 | // both case, program panics if it was compiled with the `assert` tags 24 | // (`go build -tags assert ./path/to/my/package`) 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package assert 29 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import ( 6 | "errors" 7 | ) 8 | 9 | // AnError is an error instance useful for testing. If the code does not care 10 | // about error specifics, and only needs to return the error for example, this 11 | // error should be used to make the test code more readable. 12 | var AnError = errors.New("assert.AnError general error for testing") 13 | -------------------------------------------------------------------------------- /extra.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import "sync" 6 | 7 | // A TryLocker represents an object that can attempt to acquire a lock and report 8 | // whether it succeeded. 9 | // 10 | // [sync.Mutex] and [sync.RWMutex] implements this interface. 11 | type TryLocker interface { 12 | sync.Locker 13 | TryLock() bool 14 | } 15 | 16 | // Locked asserts that the [TryLocker] is already locked. 17 | // 18 | // assert.IsDecreasing([]int{2, 1, 0}) 19 | // assert.IsDecreasing([]float{2, 1}) 20 | // assert.IsDecreasing([]string{"b", "a"}) 21 | func Locked(locker TryLocker, msgAndArgs ...any) { 22 | if locker.TryLock() { 23 | Fail("Expected sync.Locker to be locked", msgAndArgs...) 24 | } 25 | } 26 | 27 | // Lockedf asserts that the [TryLocker] is already locked. 28 | // 29 | // assert.IsDecreasing([]int{2, 1, 0}) 30 | // assert.IsDecreasing([]float{2, 1}) 31 | // assert.IsDecreasing([]string{"b", "a"}) 32 | func Lockedf(locker TryLocker, msg string, args ...any) { 33 | Locked(locker, append([]interface{}{msg}, args...)...) 34 | } 35 | 36 | // Unlocked asserts that the [TryLocker] is unlocked. 37 | // 38 | // assert.IsDecreasing([]int{2, 1, 0}) 39 | // assert.IsDecreasing([]float{2, 1}) 40 | // assert.IsDecreasing([]string{"b", "a"}) 41 | func Unlocked(locker TryLocker, msgAndArgs ...any) { 42 | if !locker.TryLock() { 43 | Fail("Expected sync.Locker to be unlocked", msgAndArgs...) 44 | } 45 | locker.Unlock() 46 | } 47 | 48 | // UnLockedf asserts that the [TryLocker] is unlocked. 49 | // 50 | // assert.IsDecreasing([]int{2, 1, 0}) 51 | // assert.IsDecreasing([]float{2, 1}) 52 | // assert.IsDecreasing([]string{"b", "a"}) 53 | func Unlockedf(locker TryLocker, msg string, args ...any) { 54 | Unlocked(locker, append([]interface{}{msg}, args...)...) 55 | } 56 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1694529238, 9 | "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1698890957, 24 | "narHash": "sha256-DJ+SppjpPBoJr0Aro9TAcP3sxApCSieY6BYBCoWGUX8=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "c082856b850ec60cda9f0a0db2bc7bd8900d708c", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "id": "nixpkgs", 32 | "type": "indirect" 33 | } 34 | }, 35 | "root": { 36 | "inputs": { 37 | "flake-utils": "flake-utils", 38 | "nixpkgs": "nixpkgs" 39 | } 40 | }, 41 | "systems": { 42 | "locked": { 43 | "lastModified": 1681028828, 44 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 45 | "owner": "nix-systems", 46 | "repo": "default", 47 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 48 | "type": "github" 49 | }, 50 | "original": { 51 | "owner": "nix-systems", 52 | "repo": "default", 53 | "type": "github" 54 | } 55 | } 56 | }, 57 | "root": "root", 58 | "version": 7 59 | } 60 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { flake-utils.url = "github:numtide/flake-utils"; }; 3 | 4 | outputs = { nixpkgs, flake-utils, ... }: 5 | let 6 | outputsWithoutSystem = { }; 7 | outputsWithSystem = flake-utils.lib.eachDefaultSystem (system: 8 | let 9 | pkgs = import nixpkgs { inherit system; }; 10 | #lib = pkgs.lib; 11 | in { 12 | devShells = { 13 | default = pkgs.mkShell { 14 | buildInputs = with pkgs; [ go gopls gotools shellcheck ]; 15 | }; 16 | }; 17 | }); 18 | in outputsWithSystem // outputsWithoutSystem; 19 | } 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/negrel/assert 2 | 3 | go 1.20 4 | 5 | require github.com/davecgh/go-spew v1.1.1 6 | 7 | require github.com/pmezard/go-difflib v1.0.0 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | -------------------------------------------------------------------------------- /http_assertions.go: -------------------------------------------------------------------------------- 1 | //go:build assert 2 | 3 | package assert 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | "net/http/httptest" 9 | "net/url" 10 | "strings" 11 | ) 12 | 13 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 14 | // an error if building a new request fails. 15 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { 16 | w := httptest.NewRecorder() 17 | req, err := http.NewRequest(method, url, http.NoBody) 18 | if err != nil { 19 | return -1, err 20 | } 21 | req.URL.RawQuery = values.Encode() 22 | handler(w, req) 23 | return w.Code, nil 24 | } 25 | 26 | // HTTPSuccess asserts that a specified handler returns a success status code. 27 | // 28 | // assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) 29 | // 30 | // Returns whether the assertion was successful (true) or not (false). 31 | func HTTPSuccess(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 32 | code, err := httpCode(handler, method, url, values) 33 | if err != nil { 34 | Fail(fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 35 | } 36 | 37 | isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent 38 | if !isSuccessCode { 39 | Fail(fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 40 | } 41 | 42 | return isSuccessCode 43 | } 44 | 45 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 46 | // 47 | // assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 48 | // 49 | // Returns whether the assertion was successful (true) or not (false). 50 | func HTTPRedirect(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 51 | code, err := httpCode(handler, method, url, values) 52 | if err != nil { 53 | Fail(fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 54 | } 55 | 56 | isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 57 | if !isRedirectCode { 58 | Fail(fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 59 | } 60 | 61 | return isRedirectCode 62 | } 63 | 64 | // HTTPError asserts that a specified handler returns an error status code. 65 | // 66 | // assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 67 | // 68 | // Returns whether the assertion was successful (true) or not (false). 69 | func HTTPError(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 70 | code, err := httpCode(handler, method, url, values) 71 | if err != nil { 72 | Fail(fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 73 | } 74 | 75 | isErrorCode := code >= http.StatusBadRequest 76 | if !isErrorCode { 77 | Fail(fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 78 | } 79 | 80 | return isErrorCode 81 | } 82 | 83 | // HTTPStatusCode asserts that a specified handler returns a specified status code. 84 | // 85 | // assert.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) 86 | // 87 | // Returns whether the assertion was successful (true) or not (false). 88 | func HTTPStatusCode(handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { 89 | code, err := httpCode(handler, method, url, values) 90 | if err != nil { 91 | Fail(fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 92 | } 93 | 94 | successful := code == statuscode 95 | if !successful { 96 | Fail(fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...) 97 | } 98 | 99 | return successful 100 | } 101 | 102 | // HTTPBody is a helper that returns HTTP body of the response. It returns 103 | // empty string if building a new request fails. 104 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 105 | w := httptest.NewRecorder() 106 | if len(values) > 0 { 107 | url += "?" + values.Encode() 108 | } 109 | req, err := http.NewRequest(method, url, http.NoBody) 110 | if err != nil { 111 | return "" 112 | } 113 | handler(w, req) 114 | return w.Body.String() 115 | } 116 | 117 | // HTTPBodyContains asserts that a specified handler returns a 118 | // body that contains a string. 119 | // 120 | // assert.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 121 | // 122 | // Returns whether the assertion was successful (true) or not (false). 123 | func HTTPBodyContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 124 | body := HTTPBody(handler, method, url, values) 125 | 126 | contains := strings.Contains(body, fmt.Sprint(str)) 127 | if !contains { 128 | Fail(fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) 129 | } 130 | 131 | return contains 132 | } 133 | 134 | // HTTPBodyNotContains asserts that a specified handler returns a 135 | // body that does not contain a string. 136 | // 137 | // assert.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 138 | // 139 | // Returns whether the assertion was successful (true) or not (false). 140 | func HTTPBodyNotContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 141 | body := HTTPBody(handler, method, url, values) 142 | 143 | contains := strings.Contains(body, fmt.Sprint(str)) 144 | if contains { 145 | Fail(fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) 146 | } 147 | 148 | return !contains 149 | } 150 | -------------------------------------------------------------------------------- /prod_assertion_compare.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | import ( 6 | "reflect" 7 | "time" 8 | ) 9 | 10 | // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it. 11 | type CompareType = compareResult 12 | 13 | type compareResult int 14 | 15 | const ( 16 | compareLess compareResult = iota - 1 17 | compareEqual 18 | compareGreater 19 | ) 20 | 21 | var ( 22 | intType = reflect.TypeOf(int(1)) 23 | int8Type = reflect.TypeOf(int8(1)) 24 | int16Type = reflect.TypeOf(int16(1)) 25 | int32Type = reflect.TypeOf(int32(1)) 26 | int64Type = reflect.TypeOf(int64(1)) 27 | 28 | uintType = reflect.TypeOf(uint(1)) 29 | uint8Type = reflect.TypeOf(uint8(1)) 30 | uint16Type = reflect.TypeOf(uint16(1)) 31 | uint32Type = reflect.TypeOf(uint32(1)) 32 | uint64Type = reflect.TypeOf(uint64(1)) 33 | 34 | uintptrType = reflect.TypeOf(uintptr(1)) 35 | 36 | float32Type = reflect.TypeOf(float32(1)) 37 | float64Type = reflect.TypeOf(float64(1)) 38 | 39 | stringType = reflect.TypeOf("") 40 | 41 | timeType = reflect.TypeOf(time.Time{}) 42 | bytesType = reflect.TypeOf([]byte{}) 43 | ) 44 | 45 | func compare(obj1, obj2 interface{}, kind reflect.Kind) {} 46 | 47 | // Greater asserts that the first element is greater than the second 48 | // 49 | // assert.Greater(2, 1) 50 | // assert.Greater(float64(2), float64(1)) 51 | // assert.Greater("b", "a") 52 | func Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {} 53 | 54 | // GreaterOrEqual asserts that the first element is greater than or equal to the second 55 | // 56 | // assert.GreaterOrEqual(2, 1) 57 | // assert.GreaterOrEqual(2, 2) 58 | // assert.GreaterOrEqual("b", "a") 59 | // assert.GreaterOrEqual("b", "b") 60 | func GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {} 61 | 62 | // Less asserts that the first element is less than the second 63 | // 64 | // assert.Less(1, 2) 65 | // assert.Less(float64(1), float64(2)) 66 | // assert.Less("a", "b") 67 | func Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {} 68 | 69 | // LessOrEqual asserts that the first element is less than or equal to the second 70 | // 71 | // assert.LessOrEqual(1, 2) 72 | // assert.LessOrEqual(2, 2) 73 | // assert.LessOrEqual("a", "b") 74 | // assert.LessOrEqual("b", "b") 75 | func LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {} 76 | 77 | // Positive asserts that the specified element is positive 78 | // 79 | // assert.Positive(1) 80 | // assert.Positive(1.23) 81 | func Positive(e interface{}, msgAndArgs ...interface{}) {} 82 | 83 | // Negative asserts that the specified element is negative 84 | // 85 | // assert.Negative(-1) 86 | // assert.Negative(-1.23) 87 | func Negative(e interface{}, msgAndArgs ...interface{}) {} 88 | 89 | func compareTwoValues(e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) { 90 | } 91 | 92 | func containsValue(values []compareResult, value compareResult) {} 93 | -------------------------------------------------------------------------------- /prod_assertion_format.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. 4 | 5 | package assert 6 | 7 | import ( 8 | http "net/http" 9 | url "net/url" 10 | time "time" 11 | ) 12 | 13 | // Conditionf uses a Comparison to assert a complex condition. 14 | func Conditionf(comp Comparison, msg string, args ...interface{}) {} 15 | 16 | // Containsf asserts that the specified string, list(array, slice...) or map contains the 17 | // specified substring or element. 18 | // 19 | // assert.Containsf("Hello World", "World", "error message %s", "formatted") 20 | // assert.Containsf(["Hello", "World"], "World", "error message %s", "formatted") 21 | // assert.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") 22 | func Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {} 23 | 24 | // DirExistsf checks whether a directory exists in the given path. It also fails 25 | // if the path is a file rather a directory or there is an error checking whether it exists. 26 | func DirExistsf(path string, msg string, args ...interface{}) {} 27 | 28 | // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified 29 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 30 | // the number of appearances of each of them in both lists should match. 31 | // 32 | // assert.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") 33 | func ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {} 34 | 35 | // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either 36 | // a slice or a channel with len == 0. 37 | // 38 | // assert.Emptyf(obj, "error message %s", "formatted") 39 | func Emptyf(object interface{}, msg string, args ...interface{}) {} 40 | 41 | // Equalf asserts that two objects are equal. 42 | // 43 | // assert.Equalf(123, 123, "error message %s", "formatted") 44 | // 45 | // Pointer variable equality is determined based on the equality of the 46 | // referenced values (as opposed to the memory addresses). Function equality 47 | // cannot be determined and will always fail. 48 | func Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 49 | 50 | // EqualErrorf asserts that a function returned an error (i.e. not `nil`) 51 | // and that it is equal to the provided error. 52 | // 53 | // actualObj, err := SomeFunction() 54 | // assert.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") 55 | func EqualErrorf(theError error, errString string, msg string, args ...interface{}) {} 56 | 57 | // EqualExportedValuesf asserts that the types of two objects are equal and their public 58 | // fields are also equal. This is useful for comparing structs that have private fields 59 | // that could potentially differ. 60 | // 61 | // type S struct { 62 | // Exported int 63 | // notExported int 64 | // } 65 | // assert.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true 66 | // assert.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false 67 | func EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { 68 | } 69 | 70 | // EqualValuesf asserts that two objects are equal or convertible to the larger 71 | // type and equal. 72 | // 73 | // assert.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") 74 | func EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 75 | 76 | // Errorf asserts that a function returned an error (i.e. not `nil`). 77 | // 78 | // actualObj, err := SomeFunction() 79 | // if assert.Errorf(err, "error message %s", "formatted") { 80 | // assert.Equal(expectedErrorf, err) 81 | // } 82 | func Errorf(err error, msg string, args ...interface{}) {} 83 | 84 | // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. 85 | // This is a wrapper for errors.As. 86 | func ErrorAsf(err error, target interface{}, msg string, args ...interface{}) {} 87 | 88 | // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) 89 | // and that the error contains the specified substring. 90 | // 91 | // actualObj, err := SomeFunction() 92 | // assert.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") 93 | func ErrorContainsf(theError error, contains string, msg string, args ...interface{}) {} 94 | 95 | // ErrorIsf asserts that at least one of the errors in err's chain matches target. 96 | // This is a wrapper for errors.Is. 97 | func ErrorIsf(err error, target error, msg string, args ...interface{}) {} 98 | 99 | // Eventuallyf asserts that given condition will be met in waitFor time, 100 | // periodically checking target function each tick. 101 | // 102 | // assert.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") 103 | func Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { 104 | } 105 | 106 | // EventuallyWithTf asserts that given condition will be met in waitFor time, 107 | // periodically checking target function each tick. In contrast to Eventually, 108 | // it supplies a CollectT to the condition function, so that the condition 109 | // function can use the CollectT to call other assertions. 110 | // The condition is considered "met" if no errors are raised in a tick. 111 | // The supplied CollectT collects all errors from one tick (if there are any). 112 | // If the condition is not met before waitFor, the collected errors of 113 | // the last tick are copied to t. 114 | // 115 | // externalValue := false 116 | // go func() {} 117 | 118 | // Exactlyf asserts that two objects are equal in value and type. 119 | // 120 | // assert.Exactlyf(int32(123), int64(123), "error message %s", "formatted") 121 | func Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 122 | 123 | // Failf reports a failure through 124 | func Failf(failureMessage string, msg string, args ...interface{}) {} 125 | 126 | // FailNowf fails test 127 | func FailNowf(failureMessage string, msg string, args ...interface{}) {} 128 | 129 | // Falsef asserts that the specified value is false. 130 | // 131 | // assert.Falsef(myBool, "error message %s", "formatted") 132 | func Falsef(value bool, msg string, args ...interface{}) {} 133 | 134 | // FileExistsf checks whether a file exists in the given path. It also fails if 135 | // the path points to a directory or there is an error when trying to check the file. 136 | func FileExistsf(path string, msg string, args ...interface{}) {} 137 | 138 | // Greaterf asserts that the first element is greater than the second 139 | // 140 | // assert.Greaterf(2, 1, "error message %s", "formatted") 141 | // assert.Greaterf(float64(2), float64(1), "error message %s", "formatted") 142 | // assert.Greaterf("b", "a", "error message %s", "formatted") 143 | func Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {} 144 | 145 | // GreaterOrEqualf asserts that the first element is greater than or equal to the second 146 | // 147 | // assert.GreaterOrEqualf(2, 1, "error message %s", "formatted") 148 | // assert.GreaterOrEqualf(2, 2, "error message %s", "formatted") 149 | // assert.GreaterOrEqualf("b", "a", "error message %s", "formatted") 150 | // assert.GreaterOrEqualf("b", "b", "error message %s", "formatted") 151 | func GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {} 152 | 153 | // HTTPBodyContainsf asserts that a specified handler returns a 154 | // body that contains a string. 155 | // 156 | // assert.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") 157 | // 158 | // Returns whether the assertion was successful (true) or not (false). 159 | func HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { 160 | } 161 | 162 | // HTTPBodyNotContainsf asserts that a specified handler returns a 163 | // body that does not contain a string. 164 | // 165 | // assert.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") 166 | // 167 | // Returns whether the assertion was successful (true) or not (false). 168 | func HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { 169 | } 170 | 171 | // HTTPErrorf asserts that a specified handler returns an error status code. 172 | // 173 | // assert.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 174 | // 175 | // Returns whether the assertion was successful (true) or not (false). 176 | func HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { 177 | } 178 | 179 | // HTTPRedirectf asserts that a specified handler returns a redirect status code. 180 | // 181 | // assert.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 182 | // 183 | // Returns whether the assertion was successful (true) or not (false). 184 | func HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { 185 | } 186 | 187 | // HTTPStatusCodef asserts that a specified handler returns a specified status code. 188 | // 189 | // assert.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") 190 | // 191 | // Returns whether the assertion was successful (true) or not (false). 192 | func HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { 193 | } 194 | 195 | // HTTPSuccessf asserts that a specified handler returns a success status code. 196 | // 197 | // assert.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") 198 | // 199 | // Returns whether the assertion was successful (true) or not (false). 200 | func HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { 201 | } 202 | 203 | // Implementsf asserts that an object is implemented by the specified interface. 204 | // 205 | // assert.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") 206 | func Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {} 207 | 208 | // InDeltaf asserts that the two numerals are within delta of each other. 209 | // 210 | // assert.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") 211 | func InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { 212 | } 213 | 214 | // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. 215 | func InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { 216 | } 217 | 218 | // InDeltaSlicef is the same as InDelta, except it compares two slices. 219 | func InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { 220 | } 221 | 222 | // InEpsilonf asserts that expected and actual have a relative error less than epsilon 223 | func InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { 224 | } 225 | 226 | // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. 227 | func InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { 228 | } 229 | 230 | // IsDecreasingf asserts that the collection is decreasing 231 | // 232 | // assert.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") 233 | // assert.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") 234 | // assert.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") 235 | func IsDecreasingf(object interface{}, msg string, args ...interface{}) {} 236 | 237 | // IsIncreasingf asserts that the collection is increasing 238 | // 239 | // assert.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") 240 | // assert.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") 241 | // assert.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") 242 | func IsIncreasingf(object interface{}, msg string, args ...interface{}) {} 243 | 244 | // IsNonDecreasingf asserts that the collection is not decreasing 245 | // 246 | // assert.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") 247 | // assert.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") 248 | // assert.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") 249 | func IsNonDecreasingf(object interface{}, msg string, args ...interface{}) {} 250 | 251 | // IsNonIncreasingf asserts that the collection is not increasing 252 | // 253 | // assert.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") 254 | // assert.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") 255 | // assert.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") 256 | func IsNonIncreasingf(object interface{}, msg string, args ...interface{}) {} 257 | 258 | // IsTypef asserts that the specified objects are of the same type. 259 | func IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {} 260 | 261 | // JSONEqf asserts that two JSON strings are equivalent. 262 | // 263 | // assert.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") 264 | func JSONEqf(expected string, actual string, msg string, args ...interface{}) {} 265 | 266 | // Lenf asserts that the specified object has specific length. 267 | // Lenf also fails if the object has a type that len() not accept. 268 | // 269 | // assert.Lenf(mySlice, 3, "error message %s", "formatted") 270 | func Lenf(object interface{}, length int, msg string, args ...interface{}) {} 271 | 272 | // Lessf asserts that the first element is less than the second 273 | // 274 | // assert.Lessf(1, 2, "error message %s", "formatted") 275 | // assert.Lessf(float64(1), float64(2), "error message %s", "formatted") 276 | // assert.Lessf("a", "b", "error message %s", "formatted") 277 | func Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {} 278 | 279 | // LessOrEqualf asserts that the first element is less than or equal to the second 280 | // 281 | // assert.LessOrEqualf(1, 2, "error message %s", "formatted") 282 | // assert.LessOrEqualf(2, 2, "error message %s", "formatted") 283 | // assert.LessOrEqualf("a", "b", "error message %s", "formatted") 284 | // assert.LessOrEqualf("b", "b", "error message %s", "formatted") 285 | func LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {} 286 | 287 | // Negativef asserts that the specified element is negative 288 | // 289 | // assert.Negativef(-1, "error message %s", "formatted") 290 | // assert.Negativef(-1.23, "error message %s", "formatted") 291 | func Negativef(e interface{}, msg string, args ...interface{}) {} 292 | 293 | // Neverf asserts that the given condition doesn't satisfy in waitFor time, 294 | // periodically checking the target function each tick. 295 | // 296 | // assert.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") 297 | func Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { 298 | } 299 | 300 | // Nilf asserts that the specified object is nil. 301 | // 302 | // assert.Nilf(err, "error message %s", "formatted") 303 | func Nilf(object interface{}, msg string, args ...interface{}) {} 304 | 305 | // NoDirExistsf checks whether a directory does not exist in the given path. 306 | // It fails if the path points to an existing _directory_ only. 307 | func NoDirExistsf(path string, msg string, args ...interface{}) {} 308 | 309 | // NoErrorf asserts that a function returned no error (i.e. `nil`). 310 | // 311 | // actualObj, err := SomeFunction() 312 | // if assert.NoErrorf(err, "error message %s", "formatted") { 313 | // assert.Equal(expectedObj, actualObj) 314 | // } 315 | func NoErrorf(err error, msg string, args ...interface{}) {} 316 | 317 | // NoFileExistsf checks whether a file does not exist in a given path. It fails 318 | // if the path points to an existing _file_ only. 319 | func NoFileExistsf(path string, msg string, args ...interface{}) {} 320 | 321 | // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the 322 | // specified substring or element. 323 | // 324 | // assert.NotContainsf("Hello World", "Earth", "error message %s", "formatted") 325 | // assert.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") 326 | // assert.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") 327 | func NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {} 328 | 329 | // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified 330 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 331 | // the number of appearances of each of them in both lists should not match. 332 | // This is an inverse of ElementsMatch. 333 | // 334 | // assert.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false 335 | // 336 | // assert.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true 337 | // 338 | // assert.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true 339 | func NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {} 340 | 341 | // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either 342 | // a slice or a channel with len == 0. 343 | // 344 | // if assert.NotEmptyf(obj, "error message %s", "formatted") { 345 | // assert.Equal("two", obj[1]) 346 | // } 347 | func NotEmptyf(object interface{}, msg string, args ...interface{}) {} 348 | 349 | // NotEqualf asserts that the specified values are NOT equal. 350 | // 351 | // assert.NotEqualf(obj1, obj2, "error message %s", "formatted") 352 | // 353 | // Pointer variable equality is determined based on the equality of the 354 | // referenced values (as opposed to the memory addresses). 355 | func NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 356 | 357 | // NotEqualValuesf asserts that two objects are not equal even when converted to the same type 358 | // 359 | // assert.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") 360 | func NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 361 | 362 | // NotErrorAsf asserts that none of the errors in err's chain matches target, 363 | // but if so, sets target to that error value. 364 | func NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) {} 365 | 366 | // NotErrorIsf asserts that none of the errors in err's chain matches target. 367 | // This is a wrapper for errors.Is. 368 | func NotErrorIsf(err error, target error, msg string, args ...interface{}) {} 369 | 370 | // NotImplementsf asserts that an object does not implement the specified interface. 371 | // 372 | // assert.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") 373 | func NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { 374 | } 375 | 376 | // NotNilf asserts that the specified object is not nil. 377 | // 378 | // assert.NotNilf(err, "error message %s", "formatted") 379 | func NotNilf(object interface{}, msg string, args ...interface{}) {} 380 | 381 | // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. 382 | // 383 | // assert.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") 384 | func NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) {} 385 | 386 | // NotRegexpf asserts that a specified regexp does not match a string. 387 | // 388 | // assert.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") 389 | // assert.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") 390 | func NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {} 391 | 392 | // NotSamef asserts that two pointers do not reference the same object. 393 | // 394 | // assert.NotSamef(ptr1, ptr2, "error message %s", "formatted") 395 | // 396 | // Both arguments must be pointer variables. Pointer variable sameness is 397 | // determined based on the equality of both type and value. 398 | func NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 399 | 400 | // NotSubsetf asserts that the specified list(array, slice...) or map does NOT 401 | // contain all elements given in the specified subset list(array, slice...) or 402 | // map. 403 | // 404 | // assert.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") 405 | // assert.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") 406 | func NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {} 407 | 408 | // NotZerof asserts that i is not the zero value for its type. 409 | func NotZerof(i interface{}, msg string, args ...interface{}) {} 410 | 411 | // Panicsf asserts that the code inside the specified PanicTestFunc panics. 412 | // 413 | // assert.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") 414 | func Panicsf(f PanicTestFunc, msg string, args ...interface{}) {} 415 | 416 | // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc 417 | // panics, and that the recovered panic value is an error that satisfies the 418 | // EqualError comparison. 419 | // 420 | // assert.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") 421 | func PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) {} 422 | 423 | // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that 424 | // the recovered panic value equals the expected panic value. 425 | // 426 | // assert.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") 427 | func PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) {} 428 | 429 | // Positivef asserts that the specified element is positive 430 | // 431 | // assert.Positivef(1, "error message %s", "formatted") 432 | // assert.Positivef(1.23, "error message %s", "formatted") 433 | func Positivef(e interface{}, msg string, args ...interface{}) {} 434 | 435 | // Regexpf asserts that a specified regexp matches a string. 436 | // 437 | // assert.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") 438 | // assert.Regexpf("start...$", "it's not starting", "error message %s", "formatted") 439 | func Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {} 440 | 441 | // Samef asserts that two pointers reference the same object. 442 | // 443 | // assert.Samef(ptr1, ptr2, "error message %s", "formatted") 444 | // 445 | // Both arguments must be pointer variables. Pointer variable sameness is 446 | // determined based on the equality of both type and value. 447 | func Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {} 448 | 449 | // Subsetf asserts that the specified list(array, slice...) or map contains all 450 | // elements given in the specified subset list(array, slice...) or map. 451 | // 452 | // assert.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") 453 | // assert.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") 454 | func Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {} 455 | 456 | // Truef asserts that the specified value is true. 457 | // 458 | // assert.Truef(myBool, "error message %s", "formatted") 459 | func Truef(value bool, msg string, args ...interface{}) {} 460 | 461 | // WithinDurationf asserts that the two times are within duration delta of each other. 462 | // 463 | // assert.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") 464 | func WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { 465 | } 466 | 467 | // WithinRangef asserts that a time is within a time range (inclusive). 468 | // 469 | // assert.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") 470 | func WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { 471 | } 472 | 473 | // YAMLEqf asserts that two YAML strings are equivalent. 474 | 475 | // Zerof asserts that i is the zero value for its type. 476 | func Zerof(i interface{}, msg string, args ...interface{}) {} 477 | -------------------------------------------------------------------------------- /prod_assertion_order.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | // isOrdered checks that collection contains orderable elements. 6 | func isOrdered(object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) { 7 | } 8 | 9 | // IsIncreasing asserts that the collection is increasing 10 | // 11 | // assert.IsIncreasing([]int{1, 2, 3}) 12 | // assert.IsIncreasing([]float{1, 2}) 13 | // assert.IsIncreasing([]string{"a", "b"}) 14 | func IsIncreasing(object interface{}, msgAndArgs ...interface{}) {} 15 | 16 | // IsNonIncreasing asserts that the collection is not increasing 17 | // 18 | // assert.IsNonIncreasing([]int{2, 1, 1}) 19 | // assert.IsNonIncreasing([]float{2, 1}) 20 | // assert.IsNonIncreasing([]string{"b", "a"}) 21 | func IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) {} 22 | 23 | // IsDecreasing asserts that the collection is decreasing 24 | // 25 | // assert.IsDecreasing([]int{2, 1, 0}) 26 | // assert.IsDecreasing([]float{2, 1}) 27 | // assert.IsDecreasing([]string{"b", "a"}) 28 | func IsDecreasing(object interface{}, msgAndArgs ...interface{}) {} 29 | 30 | // IsNonDecreasing asserts that the collection is not decreasing 31 | // 32 | // assert.IsNonDecreasing([]int{1, 1, 2}) 33 | // assert.IsNonDecreasing([]float{1, 2}) 34 | // assert.IsNonDecreasing([]string{"a", "b"}) 35 | func IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) {} 36 | -------------------------------------------------------------------------------- /prod_assertions.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | import ( 6 | "reflect" 7 | "time" 8 | 9 | "github.com/davecgh/go-spew/spew" 10 | // Wrapper around gopkg.in/yaml.v3 11 | ) 12 | 13 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" 14 | 15 | // TestingT is an interface wrapper around *testing.T 16 | type TestingT interface { 17 | Errorf(format string, args ...interface{}) 18 | } 19 | 20 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 21 | // for table driven tests. 22 | type ComparisonAssertionFunc func(interface{}, interface{}, ...interface{}) bool 23 | 24 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 25 | // for table driven tests. 26 | type ValueAssertionFunc func(interface{}, ...interface{}) bool 27 | 28 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 29 | // for table driven tests. 30 | type BoolAssertionFunc func(bool, ...interface{}) bool 31 | 32 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 33 | // for table driven tests. 34 | type ErrorAssertionFunc func(error, ...interface{}) bool 35 | 36 | // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful 37 | // for table driven tests. 38 | type PanicAssertionFunc = func(f PanicTestFunc, msgAndArgs ...interface{}) bool 39 | 40 | // Comparison is a custom function that returns true on success and false on failure 41 | type Comparison func() (success bool) 42 | 43 | /* 44 | Helper functions 45 | */ 46 | 47 | // ObjectsAreEqual determines if two objects are considered equal. 48 | // 49 | // This function does no assertion of any kind. 50 | func ObjectsAreEqual(expected, actual interface{}) {} 51 | 52 | // copyExportedFields iterates downward through nested data structures and creates a copy 53 | // that only contains the exported struct fields. 54 | func copyExportedFields(expected interface{}) {} 55 | 56 | // ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are 57 | // considered equal. This comparison of only exported fields is applied recursively to nested data 58 | // structures. 59 | // 60 | // This function does no assertion of any kind. 61 | // 62 | // Deprecated: Use [EqualExportedValues] instead. 63 | func ObjectsExportedFieldsAreEqual(expected, actual interface{}) {} 64 | 65 | // ObjectsAreEqualValues gets whether two objects are equal, or if their 66 | // values are equal. 67 | func ObjectsAreEqualValues(expected, actual interface{}) {} 68 | 69 | // isNumericType returns true if the type is one of: 70 | // int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, 71 | // float32, float64, complex64, complex128 72 | func isNumericType(t reflect.Type) {} 73 | 74 | /* CallerInfo is necessary because the assert functions use the testing object 75 | internally, causing it to print the file:line of the assert method, rather than where 76 | the problem actually occurred in calling code.*/ 77 | 78 | // CallerInfo returns an array of strings containing the file and line number 79 | // of each stack frame leading from the current test to the assert call that 80 | // failed. 81 | func CallerInfo() {} 82 | 83 | // Stolen from the `go test` tool. 84 | // isTest tells whether name looks like a test (or benchmark, according to prefix). 85 | // It is a Test (say) if there is a character after Test that is not a lower-case letter. 86 | // We don't want TesticularCancer. 87 | func isTest(name, prefix string) {} 88 | 89 | func messageFromMsgAndArgs(msgAndArgs ...interface{}) {} 90 | 91 | // Aligns the provided message so that all lines after the first line start at the same location as the first line. 92 | // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). 93 | // The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the 94 | // basis on which the alignment occurs). 95 | func indentMessageLines(message string, longestLabelLen int) {} 96 | 97 | type failNower interface { 98 | FailNow() 99 | } 100 | 101 | // FailNow fails test 102 | func FailNow(failureMessage string, msgAndArgs ...interface{}) {} 103 | 104 | // Fail reports a failure through 105 | func Fail(failureMessage string, msgAndArgs ...interface{}) {} 106 | 107 | type labeledContent struct { 108 | label string 109 | content string 110 | } 111 | 112 | // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: 113 | // 114 | // \t{{label}}:{{align_spaces}}\t{{content}}\n 115 | // 116 | // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. 117 | // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this 118 | // alignment is achieved, "\t{{content}}\n" is added for the output. 119 | // 120 | // If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. 121 | func labeledOutput(content ...labeledContent) {} 122 | 123 | // Implements asserts that an object is implemented by the specified interface. 124 | // 125 | // assert.Implements((*MyInterface)(nil), new(MyObject)) 126 | func Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {} 127 | 128 | // NotImplements asserts that an object does not implement the specified interface. 129 | // 130 | // assert.NotImplements((*MyInterface)(nil), new(MyObject)) 131 | func NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {} 132 | 133 | // IsType asserts that the specified objects are of the same type. 134 | func IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {} 135 | 136 | // Equal asserts that two objects are equal. 137 | // 138 | // assert.Equal(123, 123) 139 | // 140 | // Pointer variable equality is determined based on the equality of the 141 | // referenced values (as opposed to the memory addresses). Function equality 142 | // cannot be determined and will always fail. 143 | func Equal(expected, actual interface{}, msgAndArgs ...interface{}) {} 144 | 145 | // validateEqualArgs checks whether provided arguments can be safely used in the 146 | // Equal/NotEqual functions. 147 | func validateEqualArgs(expected, actual interface{}) {} 148 | 149 | // Same asserts that two pointers reference the same object. 150 | // 151 | // assert.Same(ptr1, ptr2) 152 | // 153 | // Both arguments must be pointer variables. Pointer variable sameness is 154 | // determined based on the equality of both type and value. 155 | func Same(expected, actual interface{}, msgAndArgs ...interface{}) {} 156 | 157 | // NotSame asserts that two pointers do not reference the same object. 158 | // 159 | // assert.NotSame(ptr1, ptr2) 160 | // 161 | // Both arguments must be pointer variables. Pointer variable sameness is 162 | // determined based on the equality of both type and value. 163 | func NotSame(expected, actual interface{}, msgAndArgs ...interface{}) {} 164 | 165 | // samePointers checks if two generic interface objects are pointers of the same 166 | // type pointing to the same object. It returns two values: same indicating if 167 | // they are the same type and point to the same object, and ok indicating that 168 | // both inputs are pointers. 169 | func samePointers(first, second interface{}) {} 170 | 171 | // formatUnequalValues takes two values of arbitrary types and returns string 172 | // representations appropriate to be presented to the user. 173 | // 174 | // If the values are not of like type, the returned strings will be prefixed 175 | // with the type name, and the value will be enclosed in parentheses similar 176 | // to a type conversion in the Go grammar. 177 | func formatUnequalValues(expected, actual interface{}) {} 178 | 179 | // truncatingFormat formats the data and truncates it if it's too long. 180 | // 181 | // This helps keep formatted error messages lines from exceeding the 182 | // bufio.MaxScanTokenSize max line length that the go testing framework imposes. 183 | func truncatingFormat(data interface{}) {} 184 | 185 | // EqualValues asserts that two objects are equal or convertible to the larger 186 | // type and equal. 187 | // 188 | // assert.EqualValues(uint32(123), int32(123)) 189 | func EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) {} 190 | 191 | // EqualExportedValues asserts that the types of two objects are equal and their public 192 | // fields are also equal. This is useful for comparing structs that have private fields 193 | // that could potentially differ. 194 | // 195 | // type S struct { 196 | // Exported int 197 | // notExported int 198 | // } 199 | // assert.EqualExportedValues(S{1, 2}, S{1, 3}) => true 200 | // assert.EqualExportedValues(S{1, 2}, S{2, 3}) => false 201 | func EqualExportedValues(expected, actual interface{}, msgAndArgs ...interface{}) {} 202 | 203 | // Exactly asserts that two objects are equal in value and type. 204 | // 205 | // assert.Exactly(int32(123), int64(123)) 206 | func Exactly(expected, actual interface{}, msgAndArgs ...interface{}) {} 207 | 208 | // NotNil asserts that the specified object is not nil. 209 | // 210 | // assert.NotNil(err) 211 | func NotNil(object interface{}, msgAndArgs ...interface{}) {} 212 | 213 | // isNil checks if a specified object is nil or not, without Failing. 214 | func isNil(object interface{}) {} 215 | 216 | // Nil asserts that the specified object is nil. 217 | // 218 | // assert.Nil(err) 219 | func Nil(object interface{}, msgAndArgs ...interface{}) {} 220 | 221 | // isEmpty gets whether the specified object is considered empty or not. 222 | func isEmpty(object interface{}) {} 223 | 224 | // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either 225 | // a slice or a channel with len == 0. 226 | // 227 | // assert.Empty(obj) 228 | func Empty(object interface{}, msgAndArgs ...interface{}) {} 229 | 230 | // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either 231 | // a slice or a channel with len == 0. 232 | // 233 | // if assert.NotEmpty(obj) { 234 | // assert.Equal("two", obj[1]) 235 | // } 236 | func NotEmpty(object interface{}, msgAndArgs ...interface{}) {} 237 | 238 | // getLen tries to get the length of an object. 239 | // It returns (0, false) if impossible. 240 | func getLen(x interface{}) {} 241 | 242 | // Len asserts that the specified object has specific length. 243 | // Len also fails if the object has a type that len() not accept. 244 | // 245 | // assert.Len(mySlice, 3) 246 | func Len(object interface{}, length int, msgAndArgs ...interface{}) {} 247 | 248 | // True asserts that the specified value is true. 249 | // 250 | // assert.True(myBool) 251 | func True(value bool, msgAndArgs ...interface{}) {} 252 | 253 | // False asserts that the specified value is false. 254 | // 255 | // assert.False(myBool) 256 | func False(value bool, msgAndArgs ...interface{}) {} 257 | 258 | // NotEqual asserts that the specified values are NOT equal. 259 | // 260 | // assert.NotEqual(obj1, obj2) 261 | // 262 | // Pointer variable equality is determined based on the equality of the 263 | // referenced values (as opposed to the memory addresses). 264 | func NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {} 265 | 266 | // NotEqualValues asserts that two objects are not equal even when converted to the same type 267 | // 268 | // assert.NotEqualValues(obj1, obj2) 269 | func NotEqualValues(expected, actual interface{}, msgAndArgs ...interface{}) {} 270 | 271 | // containsElement try loop over the list check if the list includes the element. 272 | // return (false, false) if impossible. 273 | // return (true, false) if element was not found. 274 | // return (true, true) if element was found. 275 | func containsElement(list interface{}, element interface{}) {} 276 | 277 | // Contains asserts that the specified string, list(array, slice...) or map contains the 278 | // specified substring or element. 279 | // 280 | // assert.Contains("Hello World", "World") 281 | // assert.Contains(["Hello", "World"], "World") 282 | // assert.Contains({"Hello": "World"}, "Hello") 283 | func Contains(s, contains interface{}, msgAndArgs ...interface{}) {} 284 | 285 | // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the 286 | // specified substring or element. 287 | // 288 | // assert.NotContains("Hello World", "Earth") 289 | // assert.NotContains(["Hello", "World"], "Earth") 290 | // assert.NotContains({"Hello": "World"}, "Earth") 291 | func NotContains(s, contains interface{}, msgAndArgs ...interface{}) {} 292 | 293 | // Subset asserts that the specified list(array, slice...) or map contains all 294 | // elements given in the specified subset list(array, slice...) or map. 295 | // 296 | // assert.Subset([1, 2, 3], [1, 2]) 297 | // assert.Subset({"x": 1, "y": 2}, {"x": 1}) 298 | func Subset(list, subset interface{}, msgAndArgs ...interface{}) {} 299 | 300 | // NotSubset asserts that the specified list(array, slice...) or map does NOT 301 | // contain all elements given in the specified subset list(array, slice...) or 302 | // map. 303 | // 304 | // assert.NotSubset([1, 3, 4], [1, 2]) 305 | // assert.NotSubset({"x": 1, "y": 2}, {"z": 3}) 306 | func NotSubset(list, subset interface{}, msgAndArgs ...interface{}) {} 307 | 308 | // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified 309 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 310 | // the number of appearances of each of them in both lists should match. 311 | // 312 | // assert.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) 313 | func ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{}) {} 314 | 315 | // isList checks that the provided value is array or slice. 316 | func isList(list interface{}, msgAndArgs ...interface{}) {} 317 | 318 | // diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. 319 | // If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and 320 | // 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. 321 | func diffLists(listA, listB interface{}) {} 322 | 323 | func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) {} 324 | 325 | // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified 326 | // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, 327 | // the number of appearances of each of them in both lists should not match. 328 | // This is an inverse of ElementsMatch. 329 | // 330 | // assert.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false 331 | // 332 | // assert.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true 333 | // 334 | // assert.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true 335 | func NotElementsMatch(listA, listB interface{}, msgAndArgs ...interface{}) {} 336 | 337 | // Condition uses a Comparison to assert a complex condition. 338 | func Condition(comp Comparison, msgAndArgs ...interface{}) {} 339 | 340 | // PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics 341 | // methods, and represents a simple func that takes no arguments, and returns nothing. 342 | type PanicTestFunc func() 343 | 344 | // didPanic returns true if the function passed to it panics. Otherwise, it returns false. 345 | func didPanic(f PanicTestFunc) {} 346 | 347 | // Panics asserts that the code inside the specified PanicTestFunc panics. 348 | // 349 | // assert.Panics(func(){ GoCrazy() }) 350 | func Panics(f PanicTestFunc, msgAndArgs ...interface{}) {} 351 | 352 | // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that 353 | // the recovered panic value equals the expected panic value. 354 | // 355 | // assert.PanicsWithValue("crazy error", func(){ GoCrazy() }) 356 | func PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) {} 357 | 358 | // PanicsWithError asserts that the code inside the specified PanicTestFunc 359 | // panics, and that the recovered panic value is an error that satisfies the 360 | // EqualError comparison. 361 | // 362 | // assert.PanicsWithError("crazy error", func(){ GoCrazy() }) 363 | func PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) {} 364 | 365 | // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. 366 | // 367 | // assert.NotPanics(func(){ RemainCalm() }) 368 | func NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) {} 369 | 370 | // WithinDuration asserts that the two times are within duration delta of each other. 371 | // 372 | // assert.WithinDuration(time.Now(), time.Now(), 10*time.Second) 373 | func WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {} 374 | 375 | // WithinRange asserts that a time is within a time range (inclusive). 376 | // 377 | // assert.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) 378 | func WithinRange(actual, start, end time.Time, msgAndArgs ...interface{}) {} 379 | 380 | func toFloat(x interface{}) {} 381 | 382 | // InDelta asserts that the two numerals are within delta of each other. 383 | // 384 | // assert.InDelta(math.Pi, 22/7.0, 0.01) 385 | func InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {} 386 | 387 | // InDeltaSlice is the same as InDelta, except it compares two slices. 388 | func InDeltaSlice(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {} 389 | 390 | // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. 391 | func InDeltaMapValues(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {} 392 | 393 | func calcRelativeError(expected, actual interface{}) {} 394 | 395 | // InEpsilon asserts that expected and actual have a relative error less than epsilon 396 | func InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {} 397 | 398 | // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. 399 | func InEpsilonSlice(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {} 400 | 401 | /* 402 | Errors 403 | */ 404 | 405 | // NoError asserts that a function returned no error (i.e. `nil`). 406 | // 407 | // actualObj, err := SomeFunction() 408 | // if assert.NoError(err) { 409 | // assert.Equal(expectedObj, actualObj) 410 | // } 411 | func NoError(err error, msgAndArgs ...interface{}) {} 412 | 413 | // Error asserts that a function returned an error (i.e. not `nil`). 414 | // 415 | // actualObj, err := SomeFunction() 416 | // if assert.Error(err) { 417 | // assert.Equal(expectedError, err) 418 | // } 419 | func Error(err error, msgAndArgs ...interface{}) {} 420 | 421 | // EqualError asserts that a function returned an error (i.e. not `nil`) 422 | // and that it is equal to the provided error. 423 | // 424 | // actualObj, err := SomeFunction() 425 | // assert.EqualError(err, expectedErrorString) 426 | func EqualError(theError error, errString string, msgAndArgs ...interface{}) {} 427 | 428 | // ErrorContains asserts that a function returned an error (i.e. not `nil`) 429 | // and that the error contains the specified substring. 430 | // 431 | // actualObj, err := SomeFunction() 432 | // assert.ErrorContains(err, expectedErrorSubString) 433 | func ErrorContains(theError error, contains string, msgAndArgs ...interface{}) {} 434 | 435 | // matchRegexp return true if a specified regexp matches a string. 436 | func matchRegexp(rx interface{}, str interface{}) {} 437 | 438 | // Regexp asserts that a specified regexp matches a string. 439 | // 440 | // assert.Regexp(regexp.MustCompile("start"), "it's starting") 441 | // assert.Regexp("start...$", "it's not starting") 442 | func Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {} 443 | 444 | // NotRegexp asserts that a specified regexp does not match a string. 445 | // 446 | // assert.NotRegexp(regexp.MustCompile("starts"), "it's starting") 447 | // assert.NotRegexp("^start", "it's not starting") 448 | func NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {} 449 | 450 | // Zero asserts that i is the zero value for its type. 451 | func Zero(i interface{}, msgAndArgs ...interface{}) {} 452 | 453 | // NotZero asserts that i is not the zero value for its type. 454 | func NotZero(i interface{}, msgAndArgs ...interface{}) {} 455 | 456 | // FileExists checks whether a file exists in the given path. It also fails if 457 | // the path points to a directory or there is an error when trying to check the file. 458 | func FileExists(path string, msgAndArgs ...interface{}) {} 459 | 460 | // NoFileExists checks whether a file does not exist in a given path. It fails 461 | // if the path points to an existing _file_ only. 462 | func NoFileExists(path string, msgAndArgs ...interface{}) {} 463 | 464 | // DirExists checks whether a directory exists in the given path. It also fails 465 | // if the path is a file rather a directory or there is an error checking whether it exists. 466 | func DirExists(path string, msgAndArgs ...interface{}) {} 467 | 468 | // NoDirExists checks whether a directory does not exist in the given path. 469 | // It fails if the path points to an existing _directory_ only. 470 | func NoDirExists(path string, msgAndArgs ...interface{}) {} 471 | 472 | // JSONEq asserts that two JSON strings are equivalent. 473 | // 474 | // assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) 475 | func JSONEq(expected string, actual string, msgAndArgs ...interface{}) {} 476 | 477 | // YAMLEq asserts that two YAML strings are equivalent. 478 | 479 | func typeAndKind(v interface{}) {} 480 | 481 | // diff returns a diff of both values as long as both are of the same type and 482 | // are a struct, map, slice, array or string. Otherwise it returns an empty string. 483 | func diff(expected interface{}, actual interface{}) {} 484 | 485 | func isFunction(arg interface{}) {} 486 | 487 | var spewConfig = spew.ConfigState{ 488 | Indent: " ", 489 | DisablePointerAddresses: true, 490 | DisableCapacities: true, 491 | SortKeys: true, 492 | DisableMethods: true, 493 | MaxDepth: 10, 494 | } 495 | 496 | var spewConfigStringerEnabled = spew.ConfigState{ 497 | Indent: " ", 498 | DisablePointerAddresses: true, 499 | DisableCapacities: true, 500 | SortKeys: true, 501 | MaxDepth: 10, 502 | } 503 | 504 | type tHelper = interface { 505 | Helper() 506 | } 507 | 508 | // Eventually asserts that given condition will be met in waitFor time, 509 | // periodically checking target function each tick. 510 | // 511 | // assert.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) 512 | func Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { 513 | } 514 | 515 | // CollectT implements the TestingT interface and collects all errors. 516 | type CollectT struct { 517 | // A slice of errors. Non-nil slice denotes a failure. 518 | // If it's non-nil but len(c.errors) == 0, this is also a failure 519 | // obtained by direct c.FailNow() call. 520 | errors []error 521 | } 522 | 523 | // Errorf collects the error. 524 | func (c *CollectT) Errorf(format string, args ...interface{}) {} 525 | 526 | // FailNow stops execution by calling runtime.Goexit. 527 | func (c *CollectT) FailNow() {} 528 | 529 | // Deprecated: That was a method for internal usage that should not have been published. Now just panics. 530 | func (*CollectT) Reset() {} 531 | 532 | // Deprecated: That was a method for internal usage that should not have been published. Now just panics. 533 | func (*CollectT) Copy(TestingT) {} 534 | 535 | func (c *CollectT) fail() {} 536 | 537 | func (c *CollectT) failed() {} 538 | 539 | // EventuallyWithT asserts that given condition will be met in waitFor time, 540 | // periodically checking target function each tick. In contrast to Eventually, 541 | // it supplies a CollectT to the condition function, so that the condition 542 | // function can use the CollectT to call other assertions. 543 | // The condition is considered "met" if no errors are raised in a tick. 544 | // The supplied CollectT collects all errors from one tick (if there are any). 545 | // If the condition is not met before waitFor, the collected errors of 546 | // the last tick are copied to t. 547 | // 548 | // externalValue := false 549 | // go func() {} 550 | 551 | // Never asserts that the given condition doesn't satisfy in waitFor time, 552 | // periodically checking the target function each tick. 553 | // 554 | // assert.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) 555 | func Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { 556 | } 557 | 558 | // ErrorIs asserts that at least one of the errors in err's chain matches target. 559 | // This is a wrapper for errors.Is. 560 | func ErrorIs(err, target error, msgAndArgs ...interface{}) {} 561 | 562 | // NotErrorIs asserts that none of the errors in err's chain matches target. 563 | // This is a wrapper for errors.Is. 564 | func NotErrorIs(err, target error, msgAndArgs ...interface{}) {} 565 | 566 | // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. 567 | // This is a wrapper for errors.As. 568 | func ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {} 569 | 570 | // NotErrorAs asserts that none of the errors in err's chain matches target, 571 | // but if so, sets target to that error value. 572 | func NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {} 573 | 574 | func buildErrorChainString(err error) {} 575 | -------------------------------------------------------------------------------- /prod_errors.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | import ( 6 | "errors" 7 | ) 8 | 9 | // AnError is an error instance useful for testing. If the code does not care 10 | // about error specifics, and only needs to return the error for example, this 11 | // error should be used to make the test code more readable. 12 | var AnError = errors.New("assert.AnError general error for testing") 13 | -------------------------------------------------------------------------------- /prod_extra.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | import "sync" 6 | 7 | // A TryLocker represents an object that can attempt to acquire a lock and report 8 | // whether it succeeded. 9 | // 10 | // [sync.Mutex] and [sync.RWMutex] implements this interface. 11 | type TryLocker interface { 12 | sync.Locker 13 | TryLock() bool 14 | } 15 | 16 | // Locked asserts that the [TryLocker] is already locked. 17 | // 18 | // assert.IsDecreasing([]int{2, 1, 0}) 19 | // assert.IsDecreasing([]float{2, 1}) 20 | // assert.IsDecreasing([]string{"b", "a"}) 21 | func Locked(locker TryLocker, msgAndArgs ...any) {} 22 | 23 | // Lockedf asserts that the [TryLocker] is already locked. 24 | // 25 | // assert.IsDecreasing([]int{2, 1, 0}) 26 | // assert.IsDecreasing([]float{2, 1}) 27 | // assert.IsDecreasing([]string{"b", "a"}) 28 | func Lockedf(locker TryLocker, msg string, args ...any) {} 29 | 30 | // Unlocked asserts that the [TryLocker] is unlocked. 31 | // 32 | // assert.IsDecreasing([]int{2, 1, 0}) 33 | // assert.IsDecreasing([]float{2, 1}) 34 | // assert.IsDecreasing([]string{"b", "a"}) 35 | func Unlocked(locker TryLocker, msgAndArgs ...any) {} 36 | 37 | // UnLockedf asserts that the [TryLocker] is unlocked. 38 | // 39 | // assert.IsDecreasing([]int{2, 1, 0}) 40 | // assert.IsDecreasing([]float{2, 1}) 41 | // assert.IsDecreasing([]string{"b", "a"}) 42 | func Unlockedf(locker TryLocker, msg string, args ...any) {} 43 | -------------------------------------------------------------------------------- /prod_http_assertions.go: -------------------------------------------------------------------------------- 1 | //go:build !assert 2 | 3 | package assert 4 | 5 | import ( 6 | "net/http" 7 | "net/url" 8 | ) 9 | 10 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 11 | // an error if building a new request fails. 12 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) {} 13 | 14 | // HTTPSuccess asserts that a specified handler returns a success status code. 15 | // 16 | // assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) 17 | // 18 | // Returns whether the assertion was successful (true) or not (false). 19 | func HTTPSuccess(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) { 20 | } 21 | 22 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 23 | // 24 | // assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 25 | // 26 | // Returns whether the assertion was successful (true) or not (false). 27 | func HTTPRedirect(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) { 28 | } 29 | 30 | // HTTPError asserts that a specified handler returns an error status code. 31 | // 32 | // assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 33 | // 34 | // Returns whether the assertion was successful (true) or not (false). 35 | func HTTPError(handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) { 36 | } 37 | 38 | // HTTPStatusCode asserts that a specified handler returns a specified status code. 39 | // 40 | // assert.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) 41 | // 42 | // Returns whether the assertion was successful (true) or not (false). 43 | func HTTPStatusCode(handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { 44 | } 45 | 46 | // HTTPBody is a helper that returns HTTP body of the response. It returns 47 | // empty string if building a new request fails. 48 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) {} 49 | 50 | // HTTPBodyContains asserts that a specified handler returns a 51 | // body that contains a string. 52 | // 53 | // assert.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 54 | // 55 | // Returns whether the assertion was successful (true) or not (false). 56 | func HTTPBodyContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { 57 | } 58 | 59 | // HTTPBodyNotContains asserts that a specified handler returns a 60 | // body that does not contain a string. 61 | // 62 | // assert.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 63 | // 64 | // Returns whether the assertion was successful (true) or not (false). 65 | func HTTPBodyNotContains(handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { 66 | } 67 | -------------------------------------------------------------------------------- /tests/assertions_test.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "regexp" 7 | "sync" 8 | "testing" 9 | 10 | "github.com/negrel/assert" 11 | ) 12 | 13 | type TestingT interface { 14 | Errorf(format string, args ...interface{}) 15 | FailNow() 16 | } 17 | 18 | func requirePanics(t *testing.T, cb func()) { 19 | defer func() { 20 | if err := recover(); err == nil { 21 | t.Fatal("no panics") 22 | } 23 | }() 24 | 25 | cb() 26 | } 27 | 28 | func BenchmarkSliceIndexWithoutBoundCheckAssertions(b *testing.B) { 29 | get := func(slice []string, index int) string { 30 | return slice[index] 31 | } 32 | days := []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} 33 | 34 | for i := 0; i < b.N; i++ { 35 | _ = get(days, i%len(days)) 36 | } 37 | } 38 | 39 | func BenchmarkSliceIndexWithBoundCheckAssertions(b *testing.B) { 40 | get := func(slice []string, index int) string { 41 | assert.GreaterOrEqual(index, 0) 42 | assert.Less(index, len(slice)) 43 | return slice[index] 44 | } 45 | days := []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} 46 | 47 | for i := 0; i < b.N; i++ { 48 | _ = get(days, i%len(days)) 49 | } 50 | } 51 | 52 | func TestAssertCondition(t *testing.T) { 53 | t.Run("ReturnsTrueOk", func(t *testing.T) { 54 | assert.Condition(func() bool { 55 | return true 56 | }) 57 | }) 58 | 59 | t.Run("ReturnsFalsePanics", func(t *testing.T) { 60 | requirePanics(t, func() { 61 | assert.Condition(func() bool { 62 | return false 63 | }) 64 | }) 65 | }) 66 | } 67 | 68 | func TestAssertContains(t *testing.T) { 69 | t.Run("Substring", func(t *testing.T) { 70 | t.Run("PresentOk", func(t *testing.T) { 71 | assert.Contains("Hello World", "World") 72 | }) 73 | t.Run("AbsentPanics", func(t *testing.T) { 74 | requirePanics(t, func() { 75 | assert.Contains("Hello World", "bye") 76 | }) 77 | }) 78 | }) 79 | 80 | t.Run("SliceElement", func(t *testing.T) { 81 | t.Run("PresentOk", func(t *testing.T) { 82 | assert.Contains([]string{"Hello", "World"}, "World") 83 | }) 84 | t.Run("AbsentPanics", func(t *testing.T) { 85 | requirePanics(t, func() { 86 | assert.Contains([]string{"Hello", "World"}, "bye") 87 | }) 88 | }) 89 | }) 90 | 91 | t.Run("MapKey", func(t *testing.T) { 92 | t.Run("PresentOk", func(t *testing.T) { 93 | assert.Contains(map[string]string{"Hello": "World"}, "Hello") 94 | }) 95 | t.Run("AbsentPanics", func(t *testing.T) { 96 | requirePanics(t, func() { 97 | assert.Contains(map[string]string{"Hello": "World"}, "bye") 98 | }) 99 | }) 100 | }) 101 | } 102 | 103 | func TestAssertDirExists(t *testing.T) { 104 | t.Run("ExistOk", func(t *testing.T) { 105 | assert.DirExists(".") 106 | }) 107 | 108 | t.Run("DoesNotExistPanics", func(t *testing.T) { 109 | requirePanics(t, func() { 110 | assert.DirExists("./nonexistentdir") 111 | }) 112 | }) 113 | } 114 | 115 | func TestAssertElementsMatch(t *testing.T) { 116 | t.Run("Array", func(t *testing.T) { 117 | t.Run("MatchOk", func(t *testing.T) { 118 | assert.ElementsMatch([3]int{1, 2, 3}, [3]int{3, 2, 1}) 119 | }) 120 | t.Run("NoMatchPanics", func(t *testing.T) { 121 | requirePanics(t, func() { 122 | assert.ElementsMatch([3]int{4, 5, 6}, [3]int{3, 2, 1}) 123 | }) 124 | }) 125 | }) 126 | 127 | t.Run("Slice", func(t *testing.T) { 128 | t.Run("MatchOk", func(t *testing.T) { 129 | assert.ElementsMatch([]int{1, 2, 3}, []int{3, 2, 1}) 130 | }) 131 | t.Run("NoMatchPanics", func(t *testing.T) { 132 | requirePanics(t, func() { 133 | assert.ElementsMatch([]int{4, 5, 6}, []int{3, 2, 1}) 134 | }) 135 | }) 136 | }) 137 | } 138 | 139 | func TestAssertEmpty(t *testing.T) { 140 | t.Run("Slice", func(t *testing.T) { 141 | t.Run("EmptyOk", func(t *testing.T) { 142 | assert.Empty([]string{}) 143 | }) 144 | t.Run("NotEmptyPanics", func(t *testing.T) { 145 | requirePanics(t, func() { 146 | assert.Empty([]string{""}) 147 | }) 148 | }) 149 | }) 150 | 151 | t.Run("Ptr", func(t *testing.T) { 152 | t.Run("EmptyOk", func(t *testing.T) { 153 | assert.Empty(nil) 154 | }) 155 | t.Run("NotEmptyPanics", func(t *testing.T) { 156 | requirePanics(t, func() { 157 | assert.Empty(t) 158 | }) 159 | }) 160 | }) 161 | 162 | t.Run("String", func(t *testing.T) { 163 | t.Run("EmptyOk", func(t *testing.T) { 164 | assert.Empty("") 165 | }) 166 | t.Run("NotEmptyPanics", func(t *testing.T) { 167 | requirePanics(t, func() { 168 | assert.Empty("Hello world") 169 | }) 170 | }) 171 | }) 172 | 173 | t.Run("Bool", func(t *testing.T) { 174 | t.Run("EmptyOk", func(t *testing.T) { 175 | assert.Empty(false) 176 | }) 177 | t.Run("NotEmptyPanics", func(t *testing.T) { 178 | requirePanics(t, func() { 179 | assert.Empty(true) 180 | }) 181 | }) 182 | }) 183 | } 184 | 185 | func TestAssertEqual(t *testing.T) { 186 | t.Run("Int", func(t *testing.T) { 187 | t.Run("EqualOk", func(t *testing.T) { 188 | assert.Equal(123, 123) 189 | }) 190 | t.Run("NotEqualPanics", func(t *testing.T) { 191 | requirePanics(t, func() { 192 | assert.Equal(123, 456) 193 | }) 194 | }) 195 | }) 196 | 197 | t.Run("Bool", func(t *testing.T) { 198 | t.Run("EqualOk", func(t *testing.T) { 199 | assert.Equal(false, false) 200 | }) 201 | t.Run("NotEqualPanics", func(t *testing.T) { 202 | requirePanics(t, func() { 203 | assert.Equal(true, false) 204 | }) 205 | }) 206 | }) 207 | } 208 | 209 | func TestAssertEqualError(t *testing.T) { 210 | t.Run("EqualOk", func(t *testing.T) { 211 | assert.EqualError(errors.New("foo"), "foo") 212 | }) 213 | t.Run("NotEqualPanics", func(t *testing.T) { 214 | requirePanics(t, func() { 215 | assert.EqualError(errors.New("foo"), "bar") 216 | }) 217 | }) 218 | } 219 | 220 | func TestAssertEqualExportedValue(t *testing.T) { 221 | type S struct { 222 | private int 223 | Public bool 224 | } 225 | 226 | t.Run("EqualOk", func(t *testing.T) { 227 | expected := S{-1, true} 228 | actual := S{-3, true} 229 | assert.EqualExportedValues(expected, actual) 230 | }) 231 | t.Run("NotEqualPanics", func(t *testing.T) { 232 | requirePanics(t, func() { 233 | expected := S{-1, true} 234 | actual := S{-1, false} 235 | assert.EqualExportedValues(expected, actual) 236 | }) 237 | }) 238 | } 239 | 240 | func TestAssertEqualValues(t *testing.T) { 241 | t.Run("EqualOk", func(t *testing.T) { 242 | assert.EqualValues(uint32(123), uint64(123)) 243 | }) 244 | t.Run("NotEqualPanics", func(t *testing.T) { 245 | requirePanics(t, func() { 246 | assert.EqualValues(uint32(123), uint32(456)) 247 | }) 248 | }) 249 | } 250 | 251 | func TestAssertError(t *testing.T) { 252 | t.Run("ErrorOk", func(t *testing.T) { 253 | assert.Error(errors.New("foo")) 254 | }) 255 | t.Run("NoErrorPanics", func(t *testing.T) { 256 | requirePanics(t, func() { 257 | assert.Error(nil) 258 | }) 259 | }) 260 | } 261 | 262 | func TestAssertErrorAs(t *testing.T) { 263 | t.Run("MatchOk", func(t *testing.T) { 264 | assert.ErrorAs(errors.Join(errors.New("foo"), io.EOF), &io.EOF) 265 | }) 266 | t.Run("NoMatchOk", func(t *testing.T) { 267 | // ErrorAs never panics 268 | // requirePanics(t, func() { 269 | assert.ErrorAs(errors.Join(errors.New("foo"), errors.New("bar")), &io.EOF) 270 | // }) 271 | }) 272 | } 273 | 274 | func TestAssertErrorContains(t *testing.T) { 275 | t.Run("ContainsOk", func(t *testing.T) { 276 | assert.ErrorContains(errors.New("foobarqux"), "qux") 277 | }) 278 | t.Run("DoesNotContainPanics", func(t *testing.T) { 279 | requirePanics(t, func() { 280 | assert.ErrorContains(errors.New("foobarqux"), "baz") 281 | }) 282 | }) 283 | } 284 | 285 | func TestAssertErrorIs(t *testing.T) { 286 | t.Run("MatchOk", func(t *testing.T) { 287 | assert.ErrorIs(errors.Join(errors.New("foo"), io.EOF), io.EOF) 288 | }) 289 | t.Run("DoesNotMatchPanics", func(t *testing.T) { 290 | requirePanics(t, func() { 291 | assert.ErrorIs(errors.Join(errors.New("foo"), errors.New("bar")), io.EOF) 292 | }) 293 | }) 294 | } 295 | 296 | func TestAssertExactly(t *testing.T) { 297 | t.Run("EqualOk", func(t *testing.T) { 298 | assert.Exactly(uint32(123), uint32(123)) 299 | }) 300 | t.Run("NotEqualPanics", func(t *testing.T) { 301 | requirePanics(t, func() { 302 | assert.Exactly(uint32(123), uint64(123)) 303 | }) 304 | }) 305 | } 306 | 307 | func TestAssertFalse(t *testing.T) { 308 | t.Run("TrueValuePanic", func(t *testing.T) { 309 | requirePanics(t, func() { 310 | assert.False(true) 311 | }) 312 | }) 313 | 314 | t.Run("FalseValueOk", func(t *testing.T) { 315 | assert.False(false) 316 | }) 317 | } 318 | 319 | func TestAssertFileExists(t *testing.T) { 320 | t.Run("ExistsOk", func(t *testing.T) { 321 | assert.FileExists("assertions_test.go") 322 | }) 323 | 324 | t.Run("DoesNotExistPanics", func(t *testing.T) { 325 | requirePanics(t, func() { 326 | assert.FileExists("nonexistentfile") 327 | }) 328 | }) 329 | } 330 | 331 | func TestAssertGreater(t *testing.T) { 332 | t.Run("GreaterOk", func(t *testing.T) { 333 | assert.Greater(2, 1) 334 | }) 335 | 336 | t.Run("EqualPanics", func(t *testing.T) { 337 | requirePanics(t, func() { 338 | assert.Greater(2, 2) 339 | }) 340 | }) 341 | 342 | t.Run("LessPanics", func(t *testing.T) { 343 | requirePanics(t, func() { 344 | assert.Greater(1, 2) 345 | }) 346 | }) 347 | } 348 | 349 | func TestAssertGreaterOrEqual(t *testing.T) { 350 | t.Run("GreaterOk", func(t *testing.T) { 351 | assert.GreaterOrEqual(2, 1) 352 | }) 353 | 354 | t.Run("EqualOk", func(t *testing.T) { 355 | assert.GreaterOrEqual(2, 2) 356 | }) 357 | 358 | t.Run("LessPanics", func(t *testing.T) { 359 | requirePanics(t, func() { 360 | assert.GreaterOrEqual(1, 2) 361 | }) 362 | }) 363 | } 364 | 365 | func TestAssertImplements(t *testing.T) { 366 | t.Run("ImplementsOk", func(t *testing.T) { 367 | assert.Implements((*TestingT)(nil), t) 368 | }) 369 | 370 | t.Run("DoesNotImplementPanics", func(t *testing.T) { 371 | requirePanics(t, func() { 372 | assert.Implements((interface{ abc() })(nil), t) 373 | }) 374 | }) 375 | } 376 | 377 | func TestAssertInDelta(t *testing.T) { 378 | t.Run("WithinOk", func(t *testing.T) { 379 | assert.InDelta(1, 3, 2) 380 | }) 381 | 382 | t.Run("NotWithinPanics", func(t *testing.T) { 383 | requirePanics(t, func() { 384 | assert.InDelta(1, 3, 0) 385 | }) 386 | }) 387 | } 388 | 389 | func TestAssertIsDecreasing(t *testing.T) { 390 | t.Run("DecreasingOk", func(t *testing.T) { 391 | assert.IsDecreasing([]int{3, 2, 1}) 392 | }) 393 | 394 | t.Run("NotDecreasingPanics", func(t *testing.T) { 395 | requirePanics(t, func() { 396 | assert.IsDecreasing([]int{3, 2, 3}) 397 | }) 398 | }) 399 | } 400 | 401 | func TestAssertIsIncreasing(t *testing.T) { 402 | t.Run("IncreasingOk", func(t *testing.T) { 403 | assert.IsIncreasing([]int{1, 2, 3}) 404 | }) 405 | 406 | t.Run("NotIncreasingPanics", func(t *testing.T) { 407 | requirePanics(t, func() { 408 | assert.IsIncreasing([]int{1, 2, 1}) 409 | }) 410 | }) 411 | } 412 | 413 | func TestAssertIsNonDecreasing(t *testing.T) { 414 | t.Run("NotDecreasingOk", func(t *testing.T) { 415 | assert.IsNonDecreasing([]int{1, 2, 3}) 416 | }) 417 | 418 | t.Run("DecreasingPanics", func(t *testing.T) { 419 | requirePanics(t, func() { 420 | assert.IsNonDecreasing([]int{1, 2, 1}) 421 | }) 422 | }) 423 | } 424 | 425 | func TestAssertIsNonIncreasing(t *testing.T) { 426 | t.Run("NonIncreasingOk", func(t *testing.T) { 427 | assert.IsNonIncreasing([]int{3, 2, 1}) 428 | }) 429 | 430 | t.Run("DecreasingPanics", func(t *testing.T) { 431 | requirePanics(t, func() { 432 | assert.IsNonIncreasing([]int{3, 2, 3}) 433 | }) 434 | }) 435 | } 436 | 437 | func TestAssertIsType(t *testing.T) { 438 | t.Run("MatchOk", func(t *testing.T) { 439 | assert.IsType(int32(0), int32(0)) 440 | }) 441 | 442 | t.Run("NotMatchPanics", func(t *testing.T) { 443 | requirePanics(t, func() { 444 | assert.IsType(uint32(0), int32(0)) 445 | }) 446 | }) 447 | } 448 | 449 | func TestAssertJSONEq(t *testing.T) { 450 | t.Run("EqualOk", func(t *testing.T) { 451 | assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) 452 | }) 453 | 454 | t.Run("NotMatchPanics", func(t *testing.T) { 455 | requirePanics(t, func() { 456 | assert.JSONEq(`{"bye": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) 457 | }) 458 | }) 459 | } 460 | 461 | func TestAssertLen(t *testing.T) { 462 | t.Run("MatchOk", func(t *testing.T) { 463 | assert.Len([]int{1, 2, 3}, 3) 464 | }) 465 | 466 | t.Run("NotMatchPanics", func(t *testing.T) { 467 | requirePanics(t, func() { 468 | assert.Len([]int{1, 2, 3}, 0) 469 | }) 470 | }) 471 | } 472 | 473 | func TestAssertLess(t *testing.T) { 474 | t.Run("LessOk", func(t *testing.T) { 475 | assert.Less(1, 2) 476 | }) 477 | 478 | t.Run("EqualPanics", func(t *testing.T) { 479 | requirePanics(t, func() { 480 | assert.Less(2, 2) 481 | }) 482 | }) 483 | 484 | t.Run("GreaterPanics", func(t *testing.T) { 485 | requirePanics(t, func() { 486 | assert.Less(2, 1) 487 | }) 488 | }) 489 | } 490 | 491 | func TestAssertLessOrEqual(t *testing.T) { 492 | t.Run("LessOk", func(t *testing.T) { 493 | assert.LessOrEqual(1, 2) 494 | }) 495 | 496 | t.Run("EqualOk", func(t *testing.T) { 497 | assert.LessOrEqual(2, 2) 498 | }) 499 | 500 | t.Run("GreaterPanics", func(t *testing.T) { 501 | requirePanics(t, func() { 502 | assert.LessOrEqual(2, 1) 503 | }) 504 | }) 505 | } 506 | 507 | func TestAssertNegative(t *testing.T) { 508 | t.Run("NegativeOk", func(t *testing.T) { 509 | assert.Negative(-1) 510 | }) 511 | 512 | t.Run("PositivePanics", func(t *testing.T) { 513 | requirePanics(t, func() { 514 | assert.Negative(2) 515 | }) 516 | }) 517 | } 518 | 519 | func TestAssertNil(t *testing.T) { 520 | t.Run("NilOk", func(t *testing.T) { 521 | assert.Nil(nil) 522 | }) 523 | 524 | t.Run("NotNilPanics", func(t *testing.T) { 525 | requirePanics(t, func() { 526 | assert.Nil(t) 527 | }) 528 | }) 529 | } 530 | 531 | func TestAssertNoDirExists(t *testing.T) { 532 | t.Run("ExistPanics", func(t *testing.T) { 533 | requirePanics(t, func() { 534 | assert.NoDirExists(".") 535 | }) 536 | }) 537 | 538 | t.Run("DoesNotExistOk", func(t *testing.T) { 539 | assert.NoDirExists("./nonexistentdir") 540 | }) 541 | } 542 | 543 | func TestAssertNoError(t *testing.T) { 544 | t.Run("NoErrorOk", func(t *testing.T) { 545 | requirePanics(t, func() { 546 | assert.NoError(errors.New("foo")) 547 | }) 548 | }) 549 | 550 | t.Run("ErrorPanics", func(t *testing.T) { 551 | assert.NoError(nil) 552 | }) 553 | } 554 | 555 | func TestAssertNoFileExists(t *testing.T) { 556 | t.Run("ExistsPanics", func(t *testing.T) { 557 | requirePanics(t, func() { 558 | assert.NoFileExists("assertions_test.go") 559 | }) 560 | }) 561 | 562 | t.Run("DoesNotExistOk", func(t *testing.T) { 563 | assert.NoFileExists("nonexistentfile") 564 | }) 565 | } 566 | 567 | func TestAssertNotContains(t *testing.T) { 568 | t.Run("Substring", func(t *testing.T) { 569 | t.Run("PresentPanics", func(t *testing.T) { 570 | requirePanics(t, func() { 571 | assert.NotContains("Hello World", "World") 572 | }) 573 | }) 574 | t.Run("AbsentOk", func(t *testing.T) { 575 | assert.NotContains("Hello World", "bye") 576 | }) 577 | }) 578 | 579 | t.Run("SliceElement", func(t *testing.T) { 580 | t.Run("PresentPanics", func(t *testing.T) { 581 | requirePanics(t, func() { 582 | assert.NotContains([]string{"Hello", "World"}, "World") 583 | }) 584 | }) 585 | t.Run("AbsentOk", func(t *testing.T) { 586 | assert.NotContains([]string{"Hello", "World"}, "bye") 587 | }) 588 | }) 589 | 590 | t.Run("MapKey", func(t *testing.T) { 591 | t.Run("PresentPanics", func(t *testing.T) { 592 | requirePanics(t, func() { 593 | assert.NotContains(map[string]string{"Hello": "World"}, "Hello") 594 | }) 595 | }) 596 | t.Run("AbsentOk", func(t *testing.T) { 597 | assert.NotContains(map[string]string{"Hello": "World"}, "bye") 598 | }) 599 | }) 600 | } 601 | 602 | func TestAssertNotEmpty(t *testing.T) { 603 | t.Run("Slice", func(t *testing.T) { 604 | t.Run("EmptyPanics", func(t *testing.T) { 605 | requirePanics(t, func() { 606 | assert.NotEmpty([]string{}) 607 | }) 608 | }) 609 | t.Run("NotEmptyOk", func(t *testing.T) { 610 | assert.NotEmpty([]string{""}) 611 | }) 612 | }) 613 | 614 | t.Run("Ptr", func(t *testing.T) { 615 | t.Run("EmptyPanics", func(t *testing.T) { 616 | requirePanics(t, func() { 617 | assert.NotEmpty(nil) 618 | }) 619 | }) 620 | t.Run("NotEmptyOk", func(t *testing.T) { 621 | assert.NotEmpty(t) 622 | }) 623 | }) 624 | 625 | t.Run("String", func(t *testing.T) { 626 | t.Run("EmptyPanics", func(t *testing.T) { 627 | requirePanics(t, func() { 628 | assert.NotEmpty("") 629 | }) 630 | }) 631 | t.Run("NotEmptyOk", func(t *testing.T) { 632 | assert.NotEmpty("Hello world") 633 | }) 634 | }) 635 | 636 | t.Run("Bool", func(t *testing.T) { 637 | t.Run("EmptyPanics", func(t *testing.T) { 638 | requirePanics(t, func() { 639 | assert.NotEmpty(false) 640 | }) 641 | }) 642 | t.Run("NotEmptyOk", func(t *testing.T) { 643 | assert.NotEmpty(true) 644 | }) 645 | }) 646 | } 647 | 648 | func TestAssertNotEqual(t *testing.T) { 649 | t.Run("Int", func(t *testing.T) { 650 | t.Run("EqualPanics", func(t *testing.T) { 651 | requirePanics(t, func() { 652 | assert.NotEqual(123, 123) 653 | }) 654 | }) 655 | t.Run("NotEqualOk", func(t *testing.T) { 656 | assert.NotEqual(123, 456) 657 | }) 658 | }) 659 | 660 | t.Run("Bool", func(t *testing.T) { 661 | t.Run("EqualPanics", func(t *testing.T) { 662 | requirePanics(t, func() { 663 | assert.NotEqual(false, false) 664 | }) 665 | }) 666 | t.Run("NotEqualOk", func(t *testing.T) { 667 | assert.NotEqual(true, false) 668 | }) 669 | }) 670 | } 671 | 672 | func TestAssertNotEqualValues(t *testing.T) { 673 | t.Run("EqualPanics", func(t *testing.T) { 674 | requirePanics(t, func() { 675 | assert.NotEqualValues(uint32(123), uint64(123)) 676 | }) 677 | }) 678 | t.Run("NotEqualOk", func(t *testing.T) { 679 | assert.NotEqualValues(uint32(123), uint32(456)) 680 | }) 681 | } 682 | 683 | func TestAssertNotErrorIs(t *testing.T) { 684 | t.Run("MatchPanics", func(t *testing.T) { 685 | requirePanics(t, func() { 686 | assert.NotErrorIs(errors.Join(errors.New("foo"), io.EOF), io.EOF) 687 | }) 688 | }) 689 | t.Run("DoesNotMatchOk", func(t *testing.T) { 690 | assert.NotErrorIs(errors.Join(errors.New("foo"), errors.New("bar")), io.EOF) 691 | }) 692 | } 693 | 694 | func TestAssertNotNil(t *testing.T) { 695 | t.Run("NilPanics", func(t *testing.T) { 696 | requirePanics(t, func() { 697 | assert.NotNil(nil) 698 | }) 699 | }) 700 | 701 | t.Run("NotNilOk", func(t *testing.T) { 702 | assert.NotNil(t) 703 | }) 704 | } 705 | 706 | func TestAssertNotSame(t *testing.T) { 707 | t.Run("SamePanics", func(t *testing.T) { 708 | requirePanics(t, func() { 709 | assert.NotSame(t, t) 710 | }) 711 | }) 712 | 713 | t.Run("NotSameOk", func(t *testing.T) { 714 | var f *TestingT 715 | assert.NotSame(t, f) 716 | }) 717 | } 718 | 719 | func TestAssertNotSubset(t *testing.T) { 720 | t.Run("SubsetPanics", func(t *testing.T) { 721 | requirePanics(t, func() { 722 | assert.NotSubset([]int{1, 3, 4}, []int{1, 3}) 723 | }) 724 | }) 725 | 726 | t.Run("NotSubsetOk", func(t *testing.T) { 727 | assert.NotSubset([]int{1, 3, 4}, []int{1, 2}) 728 | }) 729 | } 730 | 731 | func TestAssertNotZero(t *testing.T) { 732 | t.Run("ZeroPanics", func(t *testing.T) { 733 | requirePanics(t, func() { 734 | assert.NotZero(false) 735 | }) 736 | }) 737 | 738 | t.Run("NotZeroOk", func(t *testing.T) { 739 | assert.NotZero(true) 740 | }) 741 | } 742 | 743 | func TestAssertPositive(t *testing.T) { 744 | t.Run("PositiveOk", func(t *testing.T) { 745 | assert.Positive(1) 746 | }) 747 | 748 | t.Run("NegativePanics", func(t *testing.T) { 749 | requirePanics(t, func() { 750 | assert.Positive(-2) 751 | }) 752 | }) 753 | } 754 | 755 | func TestAssertRegexp(t *testing.T) { 756 | t.Run("MatchOk", func(t *testing.T) { 757 | assert.Regexp(regexp.MustCompile(`\d+`), "123") 758 | }) 759 | 760 | t.Run("NoMatchPanics", func(t *testing.T) { 761 | requirePanics(t, func() { 762 | assert.Regexp(regexp.MustCompile(`\d+`), "abc") 763 | }) 764 | }) 765 | } 766 | 767 | func TestAssertSame(t *testing.T) { 768 | t.Run("SameOk", func(t *testing.T) { 769 | assert.Same(t, t) 770 | }) 771 | 772 | t.Run("NotSamePanics", func(t *testing.T) { 773 | requirePanics(t, func() { 774 | assert.Same(t, nil) 775 | }) 776 | }) 777 | } 778 | 779 | func TestAssertSubset(t *testing.T) { 780 | t.Run("SubsetOk", func(t *testing.T) { 781 | assert.Subset([]int{1, 3, 4}, []int{1, 3}) 782 | }) 783 | 784 | t.Run("NotSubsetPanics", func(t *testing.T) { 785 | requirePanics(t, func() { 786 | assert.Subset([]int{1, 3, 4}, []int{1, 2}) 787 | }) 788 | }) 789 | } 790 | 791 | func TestAssertTrue(t *testing.T) { 792 | t.Run("FalseValuePanic", func(t *testing.T) { 793 | requirePanics(t, func() { 794 | assert.True(false) 795 | }) 796 | }) 797 | 798 | t.Run("TrueValueOk", func(t *testing.T) { 799 | assert.True(true) 800 | }) 801 | } 802 | 803 | func TestAssertZero(t *testing.T) { 804 | t.Run("ZeroOk", func(t *testing.T) { 805 | assert.Zero(false) 806 | }) 807 | 808 | t.Run("NotZeroOk", func(t *testing.T) { 809 | requirePanics(t, func() { 810 | assert.Zero(true) 811 | }) 812 | }) 813 | } 814 | 815 | func TestAssertLocked(t *testing.T) { 816 | t.Run("Locked", func(t *testing.T) { 817 | var mu sync.Mutex 818 | mu.Lock() 819 | assert.Locked(&mu) 820 | }) 821 | 822 | t.Run("Unlocked", func(t *testing.T) { 823 | var mu sync.Mutex 824 | requirePanics(t, func() { 825 | assert.Locked(&mu) 826 | }) 827 | }) 828 | } 829 | 830 | func TestAssertUnlocked(t *testing.T) { 831 | t.Run("Unlocked", func(t *testing.T) { 832 | var mu sync.Mutex 833 | assert.Unlocked(&mu) 834 | }) 835 | 836 | t.Run("Locked", func(t *testing.T) { 837 | var mu sync.Mutex 838 | mu.Lock() 839 | requirePanics(t, func() { 840 | assert.Unlocked(&mu) 841 | }) 842 | }) 843 | } 844 | --------------------------------------------------------------------------------