Repository: stretchr/testify Branch: master Commit: 5f80e4aef7be Files: 86 Total size: 884.8 KB Directory structure: gitextract_0dnewmdf/ ├── .ci.gofmt.sh ├── .ci.gogenerate.sh ├── .ci.govet.sh ├── .ci.readme.fmt.sh ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── dependabot.yml │ ├── pull_request_template.md │ └── workflows/ │ ├── main.yml │ └── release.yml ├── .gitignore ├── .mdsf.json ├── CONTRIBUTING.md ├── EMERITUS.md ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── assert/ │ ├── assertion_compare.go │ ├── assertion_compare_test.go │ ├── assertion_format.go │ ├── assertion_format.go.tmpl │ ├── assertion_forward.go │ ├── assertion_forward.go.tmpl │ ├── assertion_order.go │ ├── assertion_order_test.go │ ├── assertions.go │ ├── assertions_test.go │ ├── doc.go │ ├── errors.go │ ├── forward_assertions.go │ ├── forward_assertions_test.go │ ├── http_assertions.go │ ├── http_assertions_test.go │ ├── internal/ │ │ └── unsafetests/ │ │ ├── doc.go │ │ └── unsafetests_test.go │ └── yaml/ │ ├── yaml_custom.go │ ├── yaml_default.go │ └── yaml_fail.go ├── doc.go ├── go.mod ├── go.sum ├── http/ │ ├── doc.go │ ├── test_response_writer.go │ └── test_round_tripper.go ├── internal/ │ ├── difflib/ │ │ ├── LICENSE │ │ ├── difflib.go │ │ └── difflib_test.go │ └── spew/ │ ├── LICENSE │ ├── README.md │ ├── bypass.go │ ├── bypasssafe.go │ ├── common.go │ ├── common_test.go │ ├── config.go │ ├── doc.go │ ├── dump.go │ ├── dump_test.go │ ├── dumpcgo_test.go │ ├── dumpnocgo_test.go │ ├── format.go │ ├── format_test.go │ ├── internal_test.go │ ├── internalunsafe_test.go │ ├── spew.go │ ├── spew_test.go │ └── testdata/ │ └── dumpcgo.go ├── mock/ │ ├── doc.go │ ├── mock.go │ └── mock_test.go ├── package_test.go ├── require/ │ ├── doc.go │ ├── forward_requirements.go │ ├── forward_requirements_test.go │ ├── require.go │ ├── require.go.tmpl │ ├── require_forward.go │ ├── require_forward.go.tmpl │ ├── requirements.go │ └── requirements_test.go └── suite/ ├── doc.go ├── interfaces.go ├── stats.go ├── stats_test.go ├── suite.go └── suite_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .ci.gofmt.sh ================================================ #!/usr/bin/env bash if [ -n "$(gofmt -l .)" ]; then echo "Go code is not formatted:" gofmt -d . exit 1 fi go generate ./... if [ -n "$(git status -s -uno)" ]; then echo "Go generate output does not match commit." echo "Did you forget to run go generate ./... ?" exit 1 fi ================================================ FILE: .ci.gogenerate.sh ================================================ #!/usr/bin/env bash # If GOMOD is defined we are running with Go Modules enabled, either # automatically or via the GO111MODULE=on environment variable. Codegen only # works with modules, so skip generation if modules is not in use. if [[ -z "$(go env GOMOD)" ]]; then echo "Skipping go generate because modules not enabled and required" exit 0 fi go generate ./... if [ -n "$(git diff)" ]; then echo "Go generate had not been run" git diff exit 1 fi ================================================ FILE: .ci.govet.sh ================================================ #!/usr/bin/env bash set -e go vet ./... ================================================ FILE: .ci.readme.fmt.sh ================================================ #!/usr/bin/env bash # Verify that the code snippets in README.md are formatted. # The tool https://github.com/hougesen/mdsf is used. if [ -n "$(mdsf verify --config .mdsf.json --log-level error README.md 2>&1)" ]; then echo "Go code in the README.md is not formatted." echo "Did you forget to run 'mdsf format --config .mdsf.json README.md'?" mdsf format --config .mdsf.json README.md git diff exit 1 fi ================================================ FILE: .gitattributes ================================================ # This file is used to configure Git attributes for the repository. # It is particularly useful for managing how generated code is treated in pull requests. # For more information, see: # https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github # Code for assertions and requirements is generated automatically by _codegen. # This also updates code comments and code examples in the documentation. # These comments and examples must be reviewed when they change, # since updates to the generated code comments may not always be correct. assert/*.go linguist-generated=false require/*.go linguist-generated=false ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Format to report a bug title: '' labels: bug assignees: '' --- ## Description ## Step To Reproduce ## Expected behavior ## Actual behavior ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Propose a new feature title: '' labels: enhancement assignees: '' --- ## Description ## Proposed solution ## Use case ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: gomod directory: / schedule: interval: daily - package-ecosystem: github-actions directory: / schedule: interval: daily ================================================ FILE: .github/pull_request_template.md ================================================ ## Summary ## Changes ## Motivation ## Related issues ================================================ FILE: .github/workflows/main.yml ================================================ name: All builds on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy: matrix: go_version: - stable - oldstable steps: - uses: actions/checkout@v5 - name: Setup Go uses: actions/setup-go@v6 with: go-version: ${{ matrix.go_version }} - run: npm install -g mdsf-cli - run: ./.ci.gogenerate.sh - run: ./.ci.gofmt.sh - run: ./.ci.readme.fmt.sh - run: ./.ci.govet.sh - run: go test -v -race ./... test: runs-on: ubuntu-latest strategy: matrix: go_version: - "1.17" - "1.18" - "1.19" - "1.20" - "1.21" - "1.22" - "1.23" - "1.24" steps: - uses: actions/checkout@v5 - name: Setup Go uses: actions/setup-go@v6 with: go-version: ${{ matrix.go_version }} - run: go test -v -race ./... ================================================ FILE: .github/workflows/release.yml ================================================ name: Create release from new tag # this flow will be run only when new tags are pushed that match our pattern on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" jobs: build: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v5 - name: Create GitHub release from tag uses: softprops/action-gh-release@v2 with: generate_release_notes: true ================================================ FILE: .gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe .DS_Store # Output of "go test -c" /assert/assert.test /require/require.test /suite/suite.test /mock/mock.test ================================================ FILE: .mdsf.json ================================================ { "$schema": "https://raw.githubusercontent.com/hougesen/mdsf/main/schemas/v0.8.2/mdsf.schema.json", "format_finished_document": false, "languages": { "go": [ [ "gofmt", "goimports" ] ] } } ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Testify So you'd like to contribute to Testify? First of all, thank you! Testify is widely used, so each contribution has a significant impact within the Golang community! Below you'll find everything you need to know to get up to speed on the project. ## Philosophy The Testify maintainers generally attempt to follow widely accepted practices within the Golang community. That being said, the first priority is always to make sure that the package is useful to the community. A few general guidelines are listed here: *Keep it simple (whenever practical)* - Try not to expand the API unless the new surface area provides meaningful benefits. For example, don't add functions because they might be useful to someone, someday. Add what is useful to specific users, today. *Ease of use is paramount* - This means good documentation and package organization. It also means that we should try hard to use meaningful, descriptive function names, avoid breaking the API unnecessarily, and try not to surprise the user. *Quality isn't an afterthought* - Testify is a testing library, so it seems reasonable that we should have a decent test suite. This is doubly important because a bug in Testify doesn't just mean a bug in our users' code, it means a bug in our users' tests, which means a potentially unnoticed and hard-to-find bug in our users' code. ## Pull Requests We welcome pull requests! Please include the following in the description: * Motivation, why your change is important or helpful * Example usage (if applicable) * Whether you intend to add / change behavior or fix a bug Please be aware that the maintainers may ask for changes. This isn't a commentary on the quality of your idea or your code. Testify is the result of many contributions from many individuals, so we need to enforce certain practices and patterns to keep the package easy for others to understand. Essentially, we recognize that there are often many good ways to do a given thing, but we have to pick one and stick with it. See `MAINTAINERS.md` for a list of users who can approve / merge your changes. ## Issues If you find a bug or think of a useful feature you'd like to see added to Testify, the best thing you can do is make the necessary changes and open a pull request (see above). If that isn't an option, or if you'd like to discuss your change before you write the code, open an issue! Please provide enough context in the issue description that other members of the community can easily understand what it is that you'd like to see. ================================================ FILE: EMERITUS.md ================================================ # Emeritus We would like to acknowledge previous testify maintainers and their huge contributions to our collective success: * @tylerb * @matryer * @glesica * @ernesto-jimenez * @mvdkleijn * @georgelesica-wf * @bencampbell-wf We thank these members for their service to this community. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MAINTAINERS.md ================================================ # Testify Maintainers The individuals listed below are active in the project and have the ability to approve and merge pull requests. * @boyan-soubachov * @dolmen * @MovieStoreGuy * @brackendawson * @ccoVeille ## Approvers The individuals listed below are active in the project and have the ability to approve pull requests. * @arjunmahishi ================================================ FILE: README.md ================================================ Testify - Thou Shalt Write Tests ================================ > [!NOTE] > Testify is being maintained at v1, no breaking changes will be accepted in this repo. > [See discussion about v2](https://github.com/stretchr/testify/discussions/1560). [![Build Status](https://github.com/stretchr/testify/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/stretchr/testify/actions/workflows/main.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/testify)](https://goreportcard.com/report/github.com/stretchr/testify) [![PkgGoDev](https://pkg.go.dev/badge/github.com/stretchr/testify)](https://pkg.go.dev/github.com/stretchr/testify) Go code (golang) set of packages that provide many tools for testifying that your code will behave as you intend. Features include: * [Easy assertions](#assert-package) * [Mocking](#mock-package) * [Testing suite interfaces and functions](#suite-package) Get started: * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date) * For an introduction to writing test code in Go, see https://go.dev/doc/code#Testing * Check out the API Documentation https://pkg.go.dev/github.com/stretchr/testify * Use [testifylint](https://github.com/Antonboom/testifylint) (via [golangci-lint](https://golangci-lint.run/)) to avoid common mistakes * A little about [Test-Driven Development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development) [`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package ------------------------------------------------------------------------------------------- The `assert` package provides some helpful methods that allow you to write better test code in Go. * Prints friendly, easy to read failure descriptions * Allows for very readable code * Optionally annotate each assertion with a message See it in action: ```go package yours import ( "testing" "github.com/stretchr/testify/assert" ) func TestSomething(t *testing.T) { // assert equality assert.Equal(t, 123, 123, "they should be equal") // assert inequality assert.NotEqual(t, 123, 456, "they should not be equal") // assert for nil (good for errors) assert.Nil(t, object) // assert for not nil (good when you expect something) if assert.NotNil(t, object) { // now we know that object isn't nil, we are safe to make // further assertions without causing any errors assert.Equal(t, "Something", object.Value) } } ``` * Every assert func takes the `testing.T` object as the first argument. This is how it writes the errors out through the normal `go test` capabilities. * Every assert func returns a bool indicating whether the assertion was successful or not, this is useful for if you want to go on making further assertions under certain conditions. if you assert many times, use the below: ```go package yours import ( "testing" "github.com/stretchr/testify/assert" ) func TestSomething(t *testing.T) { assert := assert.New(t) // assert equality assert.Equal(123, 123, "they should be equal") // assert inequality assert.NotEqual(123, 456, "they should not be equal") // assert for nil (good for errors) assert.Nil(object) // assert for not nil (good when you expect something) if assert.NotNil(object) { // now we know that object isn't nil, we are safe to make // further assertions without causing any errors assert.Equal("Something", object.Value) } } ``` [`require`](https://pkg.go.dev/github.com/stretchr/testify/require "API documentation") package --------------------------------------------------------------------------------------------- The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test. These functions must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test. Otherwise race conditions may occur. See [t.FailNow](https://pkg.go.dev/testing#T.FailNow) for details. [`mock`](https://pkg.go.dev/github.com/stretchr/testify/mock "API documentation") package ---------------------------------------------------------------------------------------- The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code. An example test function that tests a piece of code that relies on an external object `testObj`, can set up expectations (testify) and assert that they indeed happened: ```go package yours import ( "testing" "github.com/stretchr/testify/mock" ) /* Test objects */ // MyMockedObject is a mocked object that implements an interface // that describes an object that the code I am testing relies on. type MyMockedObject struct { mock.Mock } // DoSomething is a method on MyMockedObject that implements some interface // and just records the activity, and returns what the Mock object tells it to. // // In the real object, this method would do something useful, but since this // is a mocked object - we're just going to stub it out. // // NOTE: This method is not being tested here, code that uses this object is. func (m *MyMockedObject) DoSomething(number int) (bool, error) { args := m.Called(number) return args.Bool(0), args.Error(1) } /* Actual test functions */ // TestSomething is an example of how to use our test object to // make assertions about some target code we are testing. func TestSomething(t *testing.T) { // create an instance of our test object testObj := new(MyMockedObject) // set up expectations testObj.On("DoSomething", 123).Return(true, nil) // call the code we are testing targetFuncThatDoesSomethingWithObj(testObj) // assert that the expectations were met testObj.AssertExpectations(t) } // TestSomethingWithPlaceholder is a second example of how to use our test object to // make assertions about some target code we are testing. // This time using a placeholder. Placeholders might be used when the // data being passed in is normally dynamically generated and cannot be // predicted beforehand (eg. containing hashes that are time sensitive) func TestSomethingWithPlaceholder(t *testing.T) { // create an instance of our test object testObj := new(MyMockedObject) // set up expectations with a placeholder in the argument list testObj.On("DoSomething", mock.Anything).Return(true, nil) // call the code we are testing targetFuncThatDoesSomethingWithObj(testObj) // assert that the expectations were met testObj.AssertExpectations(t) } // TestSomethingElse2 is a third example that shows how you can use // the Unset method to cleanup handlers and then add new ones. func TestSomethingElse2(t *testing.T) { // create an instance of our test object testObj := new(MyMockedObject) // set up expectations with a placeholder in the argument list mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil) // call the code we are testing targetFuncThatDoesSomethingWithObj(testObj) // assert that the expectations were met testObj.AssertExpectations(t) // remove the handler now so we can add another one that takes precedence mockCall.Unset() // return false now instead of true testObj.On("DoSomething", mock.Anything).Return(false, nil) testObj.AssertExpectations(t) } ``` For more information on how to write mock code, check out the [API documentation for the `mock` package](https://pkg.go.dev/github.com/stretchr/testify/mock). You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to autogenerate the mock code against an interface as well, making using mocks much quicker. [`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package ----------------------------------------------------------------------------------------- > [!WARNING] > The suite package does not support parallel tests. See [#934](https://github.com/stretchr/testify/issues/934). The `suite` package provides functionality that you might be used to from more common object-oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal. An example suite is shown below: ```go // Basic imports import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) // Define the suite, and absorb the built-in basic suite // functionality from testify - including a T() method which // returns the current testing context type ExampleTestSuite struct { suite.Suite VariableThatShouldStartAtFive int } // Make sure that VariableThatShouldStartAtFive is set to five // before each test func (suite *ExampleTestSuite) SetupTest() { suite.VariableThatShouldStartAtFive = 5 } // All methods that begin with "Test" are run as tests within a // suite. func (suite *ExampleTestSuite) TestExample() { assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) } // In order for 'go test' to run this suite, we need to create // a normal test function and pass our suite to suite.Run func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(ExampleTestSuite)) } ``` For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go) For more information on writing suites, check out the [API documentation for the `suite` package](https://pkg.go.dev/github.com/stretchr/testify/suite). `Suite` object has assertion methods: ```go // Basic imports import ( "testing" "github.com/stretchr/testify/suite" ) // Define the suite, and absorb the built-in basic suite // functionality from testify - including assertion methods. type ExampleTestSuite struct { suite.Suite VariableThatShouldStartAtFive int } // Make sure that VariableThatShouldStartAtFive is set to five // before each test func (suite *ExampleTestSuite) SetupTest() { suite.VariableThatShouldStartAtFive = 5 } // All methods that begin with "Test" are run as tests within a // suite. func (suite *ExampleTestSuite) TestExample() { suite.Equal(suite.VariableThatShouldStartAtFive, 5) } // In order for 'go test' to run this suite, we need to create // a normal test function and pass our suite to suite.Run func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(ExampleTestSuite)) } ``` ------ Installation ============ To install Testify, use `go get`: go get github.com/stretchr/testify This will then make the following packages available to you: github.com/stretchr/testify/assert github.com/stretchr/testify/require github.com/stretchr/testify/mock github.com/stretchr/testify/suite github.com/stretchr/testify/http (deprecated) Import the `testify/assert` package into your code using this template: ```go package yours import ( "testing" "github.com/stretchr/testify/assert" ) func TestSomething(t *testing.T) { assert.True(t, true, "True is true!") } ``` ------ Staying up to date ================== To update Testify to the latest version, use `go get -u github.com/stretchr/testify`. ------ Supported go versions ================== We currently support the most recent major Go versions from 1.19 onward. ------ Contributing ============ Please feel free to submit issues, fork the repository and send pull requests! When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it. Code generation is used. [Look for `Code generated with`](https://github.com/search?q=repo%3Astretchr%2Ftestify%20%22Code%20generated%20with%22&type=code) at the top of some files. Run `go generate ./...` to update generated files. We also chat on the [Gophers Slack](https://gophers.slack.com) group in the `#testify` and `#testify-dev` channels. ------ License ======= This project is licensed under the terms of the MIT license. ================================================ FILE: assert/assertion_compare.go ================================================ package assert import ( "bytes" "fmt" "reflect" "time" ) // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it. type CompareType = compareResult type compareResult int const ( compareLess compareResult = iota - 1 compareEqual compareGreater ) var ( intType = reflect.TypeOf(int(1)) int8Type = reflect.TypeOf(int8(1)) int16Type = reflect.TypeOf(int16(1)) int32Type = reflect.TypeOf(int32(1)) int64Type = reflect.TypeOf(int64(1)) uintType = reflect.TypeOf(uint(1)) uint8Type = reflect.TypeOf(uint8(1)) uint16Type = reflect.TypeOf(uint16(1)) uint32Type = reflect.TypeOf(uint32(1)) uint64Type = reflect.TypeOf(uint64(1)) uintptrType = reflect.TypeOf(uintptr(1)) float32Type = reflect.TypeOf(float32(1)) float64Type = reflect.TypeOf(float64(1)) stringType = reflect.TypeOf("") timeType = reflect.TypeOf(time.Time{}) bytesType = reflect.TypeOf([]byte{}) ) func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) { obj1Value := reflect.ValueOf(obj1) obj2Value := reflect.ValueOf(obj2) // throughout this switch we try and avoid calling .Convert() if possible, // as this has a pretty big performance impact switch kind { case reflect.Int: { intobj1, ok := obj1.(int) if !ok { intobj1 = obj1Value.Convert(intType).Interface().(int) } intobj2, ok := obj2.(int) if !ok { intobj2 = obj2Value.Convert(intType).Interface().(int) } if intobj1 > intobj2 { return compareGreater, true } if intobj1 == intobj2 { return compareEqual, true } if intobj1 < intobj2 { return compareLess, true } } case reflect.Int8: { int8obj1, ok := obj1.(int8) if !ok { int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) } int8obj2, ok := obj2.(int8) if !ok { int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) } if int8obj1 > int8obj2 { return compareGreater, true } if int8obj1 == int8obj2 { return compareEqual, true } if int8obj1 < int8obj2 { return compareLess, true } } case reflect.Int16: { int16obj1, ok := obj1.(int16) if !ok { int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) } int16obj2, ok := obj2.(int16) if !ok { int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) } if int16obj1 > int16obj2 { return compareGreater, true } if int16obj1 == int16obj2 { return compareEqual, true } if int16obj1 < int16obj2 { return compareLess, true } } case reflect.Int32: { int32obj1, ok := obj1.(int32) if !ok { int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) } int32obj2, ok := obj2.(int32) if !ok { int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) } if int32obj1 > int32obj2 { return compareGreater, true } if int32obj1 == int32obj2 { return compareEqual, true } if int32obj1 < int32obj2 { return compareLess, true } } case reflect.Int64: { int64obj1, ok := obj1.(int64) if !ok { int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) } int64obj2, ok := obj2.(int64) if !ok { int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) } if int64obj1 > int64obj2 { return compareGreater, true } if int64obj1 == int64obj2 { return compareEqual, true } if int64obj1 < int64obj2 { return compareLess, true } } case reflect.Uint: { uintobj1, ok := obj1.(uint) if !ok { uintobj1 = obj1Value.Convert(uintType).Interface().(uint) } uintobj2, ok := obj2.(uint) if !ok { uintobj2 = obj2Value.Convert(uintType).Interface().(uint) } if uintobj1 > uintobj2 { return compareGreater, true } if uintobj1 == uintobj2 { return compareEqual, true } if uintobj1 < uintobj2 { return compareLess, true } } case reflect.Uint8: { uint8obj1, ok := obj1.(uint8) if !ok { uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) } uint8obj2, ok := obj2.(uint8) if !ok { uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) } if uint8obj1 > uint8obj2 { return compareGreater, true } if uint8obj1 == uint8obj2 { return compareEqual, true } if uint8obj1 < uint8obj2 { return compareLess, true } } case reflect.Uint16: { uint16obj1, ok := obj1.(uint16) if !ok { uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) } uint16obj2, ok := obj2.(uint16) if !ok { uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) } if uint16obj1 > uint16obj2 { return compareGreater, true } if uint16obj1 == uint16obj2 { return compareEqual, true } if uint16obj1 < uint16obj2 { return compareLess, true } } case reflect.Uint32: { uint32obj1, ok := obj1.(uint32) if !ok { uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) } uint32obj2, ok := obj2.(uint32) if !ok { uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) } if uint32obj1 > uint32obj2 { return compareGreater, true } if uint32obj1 == uint32obj2 { return compareEqual, true } if uint32obj1 < uint32obj2 { return compareLess, true } } case reflect.Uint64: { uint64obj1, ok := obj1.(uint64) if !ok { uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) } uint64obj2, ok := obj2.(uint64) if !ok { uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) } if uint64obj1 > uint64obj2 { return compareGreater, true } if uint64obj1 == uint64obj2 { return compareEqual, true } if uint64obj1 < uint64obj2 { return compareLess, true } } case reflect.Float32: { float32obj1, ok := obj1.(float32) if !ok { float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) } float32obj2, ok := obj2.(float32) if !ok { float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) } if float32obj1 > float32obj2 { return compareGreater, true } if float32obj1 == float32obj2 { return compareEqual, true } if float32obj1 < float32obj2 { return compareLess, true } } case reflect.Float64: { float64obj1, ok := obj1.(float64) if !ok { float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) } float64obj2, ok := obj2.(float64) if !ok { float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) } if float64obj1 > float64obj2 { return compareGreater, true } if float64obj1 == float64obj2 { return compareEqual, true } if float64obj1 < float64obj2 { return compareLess, true } } case reflect.String: { stringobj1, ok := obj1.(string) if !ok { stringobj1 = obj1Value.Convert(stringType).Interface().(string) } stringobj2, ok := obj2.(string) if !ok { stringobj2 = obj2Value.Convert(stringType).Interface().(string) } if stringobj1 > stringobj2 { return compareGreater, true } if stringobj1 == stringobj2 { return compareEqual, true } if stringobj1 < stringobj2 { return compareLess, true } } // Check for known struct types we can check for compare results. case reflect.Struct: { // All structs enter here. We're not interested in most types. if !obj1Value.CanConvert(timeType) { break } // time.Time can be compared! timeObj1, ok := obj1.(time.Time) if !ok { timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) } timeObj2, ok := obj2.(time.Time) if !ok { timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) } if timeObj1.Before(timeObj2) { return compareLess, true } if timeObj1.Equal(timeObj2) { return compareEqual, true } return compareGreater, true } case reflect.Slice: { // We only care about the []byte type. if !obj1Value.CanConvert(bytesType) { break } // []byte can be compared! bytesObj1, ok := obj1.([]byte) if !ok { bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte) } bytesObj2, ok := obj2.([]byte) if !ok { bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) } return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true } case reflect.Uintptr: { uintptrObj1, ok := obj1.(uintptr) if !ok { uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr) } uintptrObj2, ok := obj2.(uintptr) if !ok { uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr) } if uintptrObj1 > uintptrObj2 { return compareGreater, true } if uintptrObj1 == uintptrObj2 { return compareEqual, true } if uintptrObj1 < uintptrObj2 { return compareLess, true } } } return compareEqual, false } // Greater asserts that the first element is greater than the second // // assert.Greater(t, 2, 1) // assert.Greater(t, float64(2), float64(1)) // assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } failMessage := fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2) return compareTwoValues(t, e1, e2, []compareResult{compareGreater}, failMessage, msgAndArgs...) } // GreaterOrEqual asserts that the first element is greater than or equal to the second // // assert.GreaterOrEqual(t, 2, 1) // assert.GreaterOrEqual(t, 2, 2) // assert.GreaterOrEqual(t, "b", "a") // assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } failMessage := fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2) return compareTwoValues(t, e1, e2, []compareResult{compareGreater, compareEqual}, failMessage, msgAndArgs...) } // Less asserts that the first element is less than the second // // assert.Less(t, 1, 2) // assert.Less(t, float64(1), float64(2)) // assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } failMessage := fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2) return compareTwoValues(t, e1, e2, []compareResult{compareLess}, failMessage, msgAndArgs...) } // LessOrEqual asserts that the first element is less than or equal to the second // // assert.LessOrEqual(t, 1, 2) // assert.LessOrEqual(t, 2, 2) // assert.LessOrEqual(t, "a", "b") // assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } failMessage := fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2) return compareTwoValues(t, e1, e2, []compareResult{compareLess, compareEqual}, failMessage, msgAndArgs...) } // Positive asserts that the specified element is positive // // assert.Positive(t, 1) // assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } zero := reflect.Zero(reflect.TypeOf(e)) failMessage := fmt.Sprintf("\"%v\" is not positive", e) return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...) } // Negative asserts that the specified element is negative // // assert.Negative(t, -1) // assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } zero := reflect.Zero(reflect.TypeOf(e)) failMessage := fmt.Sprintf("\"%v\" is not negative", e) return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...) } func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } e1Kind := reflect.ValueOf(e1).Kind() e2Kind := reflect.ValueOf(e2).Kind() if e1Kind != e2Kind { return Fail(t, "Elements should be the same type", msgAndArgs...) } compareResult, isComparable := compare(e1, e2, e1Kind) if !isComparable { return Fail(t, fmt.Sprintf(`Can not compare type "%T"`, e1), msgAndArgs...) } if !containsValue(allowedComparesResults, compareResult) { return Fail(t, failMessage, msgAndArgs...) } return true } func containsValue(values []compareResult, value compareResult) bool { for _, v := range values { if v == value { return true } } return false } ================================================ FILE: assert/assertion_compare_test.go ================================================ package assert import ( "bytes" "fmt" "reflect" "runtime" "testing" "time" ) func TestCompare(t *testing.T) { t.Parallel() type customString string type customInt int type customInt8 int8 type customInt16 int16 type customInt32 int32 type customInt64 int64 type customUInt uint type customUInt8 uint8 type customUInt16 uint16 type customUInt32 uint32 type customUInt64 uint64 type customFloat32 float32 type customFloat64 float64 type customUintptr uintptr type customTime time.Time type customBytes []byte for _, currCase := range []struct { less interface{} greater interface{} cType string }{ {less: customString("a"), greater: customString("b"), cType: "string"}, {less: "a", greater: "b", cType: "string"}, {less: customInt(1), greater: customInt(2), cType: "int"}, {less: int(1), greater: int(2), cType: "int"}, {less: customInt8(1), greater: customInt8(2), cType: "int8"}, {less: int8(1), greater: int8(2), cType: "int8"}, {less: customInt16(1), greater: customInt16(2), cType: "int16"}, {less: int16(1), greater: int16(2), cType: "int16"}, {less: customInt32(1), greater: customInt32(2), cType: "int32"}, {less: int32(1), greater: int32(2), cType: "int32"}, {less: customInt64(1), greater: customInt64(2), cType: "int64"}, {less: int64(1), greater: int64(2), cType: "int64"}, {less: customUInt(1), greater: customUInt(2), cType: "uint"}, {less: uint8(1), greater: uint8(2), cType: "uint8"}, {less: customUInt8(1), greater: customUInt8(2), cType: "uint8"}, {less: uint16(1), greater: uint16(2), cType: "uint16"}, {less: customUInt16(1), greater: customUInt16(2), cType: "uint16"}, {less: uint32(1), greater: uint32(2), cType: "uint32"}, {less: customUInt32(1), greater: customUInt32(2), cType: "uint32"}, {less: uint64(1), greater: uint64(2), cType: "uint64"}, {less: customUInt64(1), greater: customUInt64(2), cType: "uint64"}, {less: float32(1.23), greater: float32(2.34), cType: "float32"}, {less: customFloat32(1.23), greater: customFloat32(2.23), cType: "float32"}, {less: float64(1.23), greater: float64(2.34), cType: "float64"}, {less: customFloat64(1.23), greater: customFloat64(2.34), cType: "float64"}, {less: uintptr(1), greater: uintptr(2), cType: "uintptr"}, {less: customUintptr(1), greater: customUintptr(2), cType: "uint64"}, {less: time.Now(), greater: time.Now().Add(time.Hour), cType: "time.Time"}, {less: time.Date(2024, 0, 0, 0, 0, 0, 0, time.Local), greater: time.Date(2263, 0, 0, 0, 0, 0, 0, time.Local), cType: "time.Time"}, {less: customTime(time.Now()), greater: customTime(time.Now().Add(time.Hour)), cType: "time.Time"}, {less: []byte{1, 1}, greater: []byte{1, 2}, cType: "[]byte"}, {less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"}, } { resLess, isComparable := compare(currCase.less, currCase.greater, reflect.ValueOf(currCase.less).Kind()) if !isComparable { t.Error("object should be comparable for type " + currCase.cType) } if resLess != compareLess { t.Errorf("object less (%v) should be less than greater (%v) for type "+currCase.cType, currCase.less, currCase.greater) } resGreater, isComparable := compare(currCase.greater, currCase.less, reflect.ValueOf(currCase.less).Kind()) if !isComparable { t.Error("object are comparable for type " + currCase.cType) } if resGreater != compareGreater { t.Errorf("object greater should be greater than less for type " + currCase.cType) } resEqual, isComparable := compare(currCase.less, currCase.less, reflect.ValueOf(currCase.less).Kind()) if !isComparable { t.Error("object are comparable for type " + currCase.cType) } if resEqual != 0 { t.Errorf("objects should be equal for type " + currCase.cType) } } } type outputT struct { buf *bytes.Buffer helpers map[string]struct{} } // Implements TestingT func (t *outputT) Errorf(format string, args ...interface{}) { s := fmt.Sprintf(format, args...) t.buf.WriteString(s) } func (t *outputT) Helper() { if t.helpers == nil { t.helpers = make(map[string]struct{}) } t.helpers[callerName(1)] = struct{}{} } // callerName gives the function name (qualified with a package path) // for the caller after skip frames (where 0 means the current function). func callerName(skip int) string { // Make room for the skip PC. var pc [1]uintptr n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName if n == 0 { panic("testing: zero callers found") } frames := runtime.CallersFrames(pc[:n]) frame, _ := frames.Next() return frame.Function } func TestGreater(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Greater(mockT, 2, 1) { t.Error("Greater should return true") } if Greater(mockT, 1, 1) { t.Error("Greater should return false") } if Greater(mockT, 1, 2) { t.Error("Greater should return false") } // Check error report for _, currCase := range []struct { less interface{} greater interface{} msg string }{ {less: "a", greater: "b", msg: `"a" is not greater than "b"`}, {less: int(1), greater: int(2), msg: `"1" is not greater than "2"`}, {less: int8(1), greater: int8(2), msg: `"1" is not greater than "2"`}, {less: int16(1), greater: int16(2), msg: `"1" is not greater than "2"`}, {less: int32(1), greater: int32(2), msg: `"1" is not greater than "2"`}, {less: int64(1), greater: int64(2), msg: `"1" is not greater than "2"`}, {less: uint8(1), greater: uint8(2), msg: `"1" is not greater than "2"`}, {less: uint16(1), greater: uint16(2), msg: `"1" is not greater than "2"`}, {less: uint32(1), greater: uint32(2), msg: `"1" is not greater than "2"`}, {less: uint64(1), greater: uint64(2), msg: `"1" is not greater than "2"`}, {less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than "2.34"`}, {less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than "2.34"`}, {less: uintptr(1), greater: uintptr(2), msg: `"1" is not greater than "2"`}, {less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than "0001-01-01 01:00:00 +0000 UTC"`}, {less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than "[1 2]"`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, Greater(out, currCase.less, currCase.greater)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.Greater") } } func TestGreaterOrEqual(t *testing.T) { t.Parallel() mockT := new(testing.T) if !GreaterOrEqual(mockT, 2, 1) { t.Error("GreaterOrEqual should return true") } if !GreaterOrEqual(mockT, 1, 1) { t.Error("GreaterOrEqual should return true") } if GreaterOrEqual(mockT, 1, 2) { t.Error("GreaterOrEqual should return false") } // Check error report for _, currCase := range []struct { less interface{} greater interface{} msg string }{ {less: "a", greater: "b", msg: `"a" is not greater than or equal to "b"`}, {less: int(1), greater: int(2), msg: `"1" is not greater than or equal to "2"`}, {less: int8(1), greater: int8(2), msg: `"1" is not greater than or equal to "2"`}, {less: int16(1), greater: int16(2), msg: `"1" is not greater than or equal to "2"`}, {less: int32(1), greater: int32(2), msg: `"1" is not greater than or equal to "2"`}, {less: int64(1), greater: int64(2), msg: `"1" is not greater than or equal to "2"`}, {less: uint8(1), greater: uint8(2), msg: `"1" is not greater than or equal to "2"`}, {less: uint16(1), greater: uint16(2), msg: `"1" is not greater than or equal to "2"`}, {less: uint32(1), greater: uint32(2), msg: `"1" is not greater than or equal to "2"`}, {less: uint64(1), greater: uint64(2), msg: `"1" is not greater than or equal to "2"`}, {less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than or equal to "2.34"`}, {less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than or equal to "2.34"`}, {less: uintptr(1), greater: uintptr(2), msg: `"1" is not greater than or equal to "2"`}, {less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than or equal to "0001-01-01 01:00:00 +0000 UTC"`}, {less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than or equal to "[1 2]"`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, GreaterOrEqual(out, currCase.less, currCase.greater)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.GreaterOrEqual") } } func TestLess(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Less(mockT, 1, 2) { t.Error("Less should return true") } if Less(mockT, 1, 1) { t.Error("Less should return false") } if Less(mockT, 2, 1) { t.Error("Less should return false") } // Check error report for _, currCase := range []struct { less interface{} greater interface{} msg string }{ {less: "a", greater: "b", msg: `"b" is not less than "a"`}, {less: int(1), greater: int(2), msg: `"2" is not less than "1"`}, {less: int8(1), greater: int8(2), msg: `"2" is not less than "1"`}, {less: int16(1), greater: int16(2), msg: `"2" is not less than "1"`}, {less: int32(1), greater: int32(2), msg: `"2" is not less than "1"`}, {less: int64(1), greater: int64(2), msg: `"2" is not less than "1"`}, {less: uint8(1), greater: uint8(2), msg: `"2" is not less than "1"`}, {less: uint16(1), greater: uint16(2), msg: `"2" is not less than "1"`}, {less: uint32(1), greater: uint32(2), msg: `"2" is not less than "1"`}, {less: uint64(1), greater: uint64(2), msg: `"2" is not less than "1"`}, {less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than "1.23"`}, {less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than "1.23"`}, {less: uintptr(1), greater: uintptr(2), msg: `"2" is not less than "1"`}, {less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than "0001-01-01 00:00:00 +0000 UTC"`}, {less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than "[1 1]"`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, Less(out, currCase.greater, currCase.less)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.Less") } } func TestLessOrEqual(t *testing.T) { t.Parallel() mockT := new(testing.T) if !LessOrEqual(mockT, 1, 2) { t.Error("LessOrEqual should return true") } if !LessOrEqual(mockT, 1, 1) { t.Error("LessOrEqual should return true") } if LessOrEqual(mockT, 2, 1) { t.Error("LessOrEqual should return false") } // Check error report for _, currCase := range []struct { less interface{} greater interface{} msg string }{ {less: "a", greater: "b", msg: `"b" is not less than or equal to "a"`}, {less: int(1), greater: int(2), msg: `"2" is not less than or equal to "1"`}, {less: int8(1), greater: int8(2), msg: `"2" is not less than or equal to "1"`}, {less: int16(1), greater: int16(2), msg: `"2" is not less than or equal to "1"`}, {less: int32(1), greater: int32(2), msg: `"2" is not less than or equal to "1"`}, {less: int64(1), greater: int64(2), msg: `"2" is not less than or equal to "1"`}, {less: uint8(1), greater: uint8(2), msg: `"2" is not less than or equal to "1"`}, {less: uint16(1), greater: uint16(2), msg: `"2" is not less than or equal to "1"`}, {less: uint32(1), greater: uint32(2), msg: `"2" is not less than or equal to "1"`}, {less: uint64(1), greater: uint64(2), msg: `"2" is not less than or equal to "1"`}, {less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than or equal to "1.23"`}, {less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than or equal to "1.23"`}, {less: uintptr(1), greater: uintptr(2), msg: `"2" is not less than or equal to "1"`}, {less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than or equal to "0001-01-01 00:00:00 +0000 UTC"`}, {less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than or equal to "[1 1]"`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, LessOrEqual(out, currCase.greater, currCase.less)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.LessOrEqual") } } func TestPositive(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Positive(mockT, 1) { t.Error("Positive should return true") } if !Positive(mockT, 1.23) { t.Error("Positive should return true") } if Positive(mockT, -1) { t.Error("Positive should return false") } if Positive(mockT, -1.23) { t.Error("Positive should return false") } // Check error report for _, currCase := range []struct { e interface{} msg string }{ {e: int(-1), msg: `"-1" is not positive`}, {e: int8(-1), msg: `"-1" is not positive`}, {e: int16(-1), msg: `"-1" is not positive`}, {e: int32(-1), msg: `"-1" is not positive`}, {e: int64(-1), msg: `"-1" is not positive`}, {e: float32(-1.23), msg: `"-1.23" is not positive`}, {e: float64(-1.23), msg: `"-1.23" is not positive`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, Positive(out, currCase.e)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.Positive") } } func TestNegative(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Negative(mockT, -1) { t.Error("Negative should return true") } if !Negative(mockT, -1.23) { t.Error("Negative should return true") } if Negative(mockT, 1) { t.Error("Negative should return false") } if Negative(mockT, 1.23) { t.Error("Negative should return false") } // Check error report for _, currCase := range []struct { e interface{} msg string }{ {e: int(1), msg: `"1" is not negative`}, {e: int8(1), msg: `"1" is not negative`}, {e: int16(1), msg: `"1" is not negative`}, {e: int32(1), msg: `"1" is not negative`}, {e: int64(1), msg: `"1" is not negative`}, {e: float32(1.23), msg: `"1.23" is not negative`}, {e: float64(1.23), msg: `"1.23" is not negative`}, } { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, Negative(out, currCase.e)) Contains(t, out.buf.String(), currCase.msg) Contains(t, out.helpers, "github.com/stretchr/testify/assert.Negative") } } func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) { t.Parallel() mockT := new(testing.T) for _, currCase := range []struct { v1 interface{} v2 interface{} compareResult bool }{ {v1: 123, v2: "abc"}, {v1: "abc", v2: 123456}, {v1: float64(12), v2: "123"}, {v1: "float(12)", v2: float64(1)}, } { result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage") False(t, result) } } func Test_compareTwoValuesNotComparableValues(t *testing.T) { t.Parallel() mockT := new(testing.T) type CompareStruct struct { } for _, currCase := range []struct { v1 interface{} v2 interface{} }{ {v1: CompareStruct{}, v2: CompareStruct{}}, {v1: map[string]int{}, v2: map[string]int{}}, {v1: make([]int, 5), v2: make([]int, 5)}, } { result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage") False(t, result) } } func Test_compareTwoValuesCorrectCompareResult(t *testing.T) { t.Parallel() mockT := new(testing.T) for _, currCase := range []struct { v1 interface{} v2 interface{} allowedResults []compareResult }{ {v1: 1, v2: 2, allowedResults: []compareResult{compareLess}}, {v1: 1, v2: 2, allowedResults: []compareResult{compareLess, compareEqual}}, {v1: 2, v2: 2, allowedResults: []compareResult{compareGreater, compareEqual}}, {v1: 2, v2: 2, allowedResults: []compareResult{compareEqual}}, {v1: 2, v2: 1, allowedResults: []compareResult{compareEqual, compareGreater}}, {v1: 2, v2: 1, allowedResults: []compareResult{compareGreater}}, } { result := compareTwoValues(mockT, currCase.v1, currCase.v2, currCase.allowedResults, "testFailMessage") True(t, result) } } func Test_containsValue(t *testing.T) { t.Parallel() for _, currCase := range []struct { values []compareResult value compareResult result bool }{ {values: []compareResult{compareGreater}, value: compareGreater, result: true}, {values: []compareResult{compareGreater, compareLess}, value: compareGreater, result: true}, {values: []compareResult{compareGreater, compareLess}, value: compareLess, result: true}, {values: []compareResult{compareGreater, compareLess}, value: compareEqual, result: false}, } { result := containsValue(currCase.values, currCase.value) Equal(t, currCase.result, result) } } func TestComparingMsgAndArgsForwarding(t *testing.T) { msgAndArgs := []interface{}{"format %s %x", "this", 0xc001} expectedOutput := "format this c001\n" funcs := []func(t TestingT){ func(t TestingT) { Greater(t, 1, 2, msgAndArgs...) }, func(t TestingT) { GreaterOrEqual(t, 1, 2, msgAndArgs...) }, func(t TestingT) { Less(t, 2, 1, msgAndArgs...) }, func(t TestingT) { LessOrEqual(t, 2, 1, msgAndArgs...) }, func(t TestingT) { Positive(t, 0, msgAndArgs...) }, func(t TestingT) { Negative(t, 0, msgAndArgs...) }, } for _, f := range funcs { out := &outputT{buf: bytes.NewBuffer(nil)} f(out) Contains(t, out.buf.String(), expectedOutput) } } ================================================ FILE: assert/assertion_format.go ================================================ // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package assert import ( http "net/http" url "net/url" time "time" ) // Conditionf uses a Comparison to assert a complex condition. func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Condition(t, comp, append([]interface{}{msg}, args...)...) } // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") // assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") // assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Contains(t, s, contains, append([]interface{}{msg}, args...)...) } // DirExistsf checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return DirExists(t, path, append([]interface{}{msg}, args...)...) } // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...) } // Emptyf asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // assert.Emptyf(t, obj, "error message %s", "formatted") // // [Zero values]: https://go.dev/ref/spec#The_zero_value func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Empty(t, object, append([]interface{}{msg}, args...)...) } // Equalf asserts that two objects are equal. // // assert.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) } // EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) } // EqualExportedValuesf asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true // assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...) } // EqualValuesf asserts that two objects are equal or convertible to the larger // type and equal. // // assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } // Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Errorf(t, err, "error message %s", "formatted") func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Error(t, err, append([]interface{}{msg}, args...)...) } // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } // ErrorContainsf asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...) } // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...) } // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) } // EventuallyWithTf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // assert.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) } // Exactlyf asserts that two objects are equal in value and type. // // assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...) } // Failf reports a failure through func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, failureMessage, append([]interface{}{msg}, args...)...) } // FailNowf fails test func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...) } // Falsef asserts that the specified value is false. // // assert.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return False(t, value, append([]interface{}{msg}, args...)...) } // FileExistsf checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return FileExists(t, path, append([]interface{}{msg}, args...)...) } // Greaterf asserts that the first element is greater than the second // // assert.Greaterf(t, 2, 1, "error message %s", "formatted") // assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") // assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Greater(t, e1, e2, append([]interface{}{msg}, args...)...) } // GreaterOrEqualf asserts that the first element is greater than or equal to the second // // assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") // assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") // assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") // assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) } // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // // assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) } // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // // assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) } // HTTPErrorf asserts that a specified handler returns an error status code. // // assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...) } // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...) } // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...) } // HTTPSuccessf asserts that a specified handler returns a success status code. // // assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...) } // Implementsf asserts that an object is implemented by the specified interface. // // assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) } // InDeltaf asserts that the two numerals are within delta of each other. // // assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } // InDeltaSlicef is the same as InDelta, except it compares two slices. func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } // InEpsilonf asserts that expected and actual have a relative error less than epsilon func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) } // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) } // IsDecreasingf asserts that the collection is decreasing // // assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") // assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") // assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsDecreasing(t, object, append([]interface{}{msg}, args...)...) } // IsIncreasingf asserts that the collection is increasing // // assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") // assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") // assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsIncreasing(t, object, append([]interface{}{msg}, args...)...) } // IsNonDecreasingf asserts that the collection is not decreasing // // assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") // assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") // assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...) } // IsNonIncreasingf asserts that the collection is not increasing // // assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") // assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") // assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...) } // IsNotTypef asserts that the specified objects are not of the same type. // // assert.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted") func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsNotType(t, theType, object, append([]interface{}{msg}, args...)...) } // IsTypef asserts that the specified objects are of the same type. // // assert.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted") func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...) } // JSONEqf asserts that two JSON strings are equivalent. // // assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) } // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // // assert.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Len(t, object, length, append([]interface{}{msg}, args...)...) } // Lessf asserts that the first element is less than the second // // assert.Lessf(t, 1, 2, "error message %s", "formatted") // assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") // assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Less(t, e1, e2, append([]interface{}{msg}, args...)...) } // LessOrEqualf asserts that the first element is less than or equal to the second // // assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") // assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") // assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") // assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) } // Negativef asserts that the specified element is negative // // assert.Negativef(t, -1, "error message %s", "formatted") // assert.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Negative(t, e, append([]interface{}{msg}, args...)...) } // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) } // Nilf asserts that the specified object is nil. // // assert.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Nil(t, object, append([]interface{}{msg}, args...)...) } // NoDirExistsf checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NoDirExists(t, path, append([]interface{}{msg}, args...)...) } // NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoErrorf(t, err, "error message %s", "formatted") { // assert.Equal(t, expectedObj, actualObj) // } func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NoError(t, err, append([]interface{}{msg}, args...)...) } // NoFileExistsf checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NoFileExists(t, path, append([]interface{}{msg}, args...)...) } // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") // assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") // assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotContains(t, s, contains, append([]interface{}{msg}, args...)...) } // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false // // assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true // // assert.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...) } // NotEmptyf asserts that the specified object is NOT [Empty]. // // if assert.NotEmptyf(t, obj, "error message %s", "formatted") { // assert.Equal(t, "two", obj[1]) // } func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotEmpty(t, object, append([]interface{}{msg}, args...)...) } // NotEqualf asserts that the specified values are NOT equal. // // assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...) } // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // // assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } // NotErrorAsf asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } // NotErrorIsf asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) } // NotImplementsf asserts that an object does not implement the specified interface. // // assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) } // NotNilf asserts that the specified object is not nil. // // assert.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotNil(t, object, append([]interface{}{msg}, args...)...) } // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // // assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotPanics(t, f, append([]interface{}{msg}, args...)...) } // NotRegexpf asserts that a specified regexp does not match a string. // // assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...) } // NotSamef asserts that two pointers do not reference the same object. // // assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) } // NotSubsetf asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") // assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") // assert.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted") // assert.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...) } // NotZerof asserts that i is not the zero value for its type. func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return NotZero(t, i, append([]interface{}{msg}, args...)...) } // Panicsf asserts that the code inside the specified PanicTestFunc panics. // // assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Panics(t, f, append([]interface{}{msg}, args...)...) } // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...) } // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) } // Positivef asserts that the specified element is positive // // assert.Positivef(t, 1, "error message %s", "formatted") // assert.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Positive(t, e, append([]interface{}{msg}, args...)...) } // Regexpf asserts that a specified regexp matches a string. // // assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Regexp(t, rx, str, append([]interface{}{msg}, args...)...) } // Samef asserts that two pointers reference the same object. // // assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Same(t, expected, actual, append([]interface{}{msg}, args...)...) } // Subsetf asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") // assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") // assert.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted") // assert.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Subset(t, list, subset, append([]interface{}{msg}, args...)...) } // Truef asserts that the specified value is true. // // assert.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return True(t, value, append([]interface{}{msg}, args...)...) } // WithinDurationf asserts that the two times are within duration delta of each other. // // assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } // WithinRangef asserts that a time is within a time range (inclusive). // // assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...) } // YAMLEqf asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // assert.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) } // Zerof asserts that i is the zero value for its type. func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return Zero(t, i, append([]interface{}{msg}, args...)...) } ================================================ FILE: assert/assertion_format.go.tmpl ================================================ {{.CommentFormat}} func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) } ================================================ FILE: assert/assertion_forward.go ================================================ // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package assert import ( http "net/http" url "net/url" time "time" ) // Condition uses a Comparison to assert a complex condition. func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Condition(a.t, comp, msgAndArgs...) } // Conditionf uses a Comparison to assert a complex condition. func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Conditionf(a.t, comp, msg, args...) } // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // a.Contains("Hello World", "World") // a.Contains(["Hello", "World"], "World") // a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Contains(a.t, s, contains, msgAndArgs...) } // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // a.Containsf("Hello World", "World", "error message %s", "formatted") // a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") // a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Containsf(a.t, s, contains, msg, args...) } // DirExists checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return DirExists(a.t, path, msgAndArgs...) } // DirExistsf checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return DirExistsf(a.t, path, msg, args...) } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ElementsMatch(a.t, listA, listB, msgAndArgs...) } // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ElementsMatchf(a.t, listA, listB, msg, args...) } // Empty asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // a.Empty(obj) // // [Zero values]: https://go.dev/ref/spec#The_zero_value func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Empty(a.t, object, msgAndArgs...) } // Emptyf asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // a.Emptyf(obj, "error message %s", "formatted") // // [Zero values]: https://go.dev/ref/spec#The_zero_value func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Emptyf(a.t, object, msg, args...) } // Equal asserts that two objects are equal. // // a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Equal(a.t, expected, actual, msgAndArgs...) } // EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualError(a.t, theError, errString, msgAndArgs...) } // EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualErrorf(a.t, theError, errString, msg, args...) } // EqualExportedValues asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // a.EqualExportedValues(S{1, 2}, S{1, 3}) => true // a.EqualExportedValues(S{1, 2}, S{2, 3}) => false func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualExportedValues(a.t, expected, actual, msgAndArgs...) } // EqualExportedValuesf asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true // a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualExportedValuesf(a.t, expected, actual, msg, args...) } // EqualValues asserts that two objects are equal or convertible to the larger // type and equal. // // a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualValues(a.t, expected, actual, msgAndArgs...) } // EqualValuesf asserts that two objects are equal or convertible to the larger // type and equal. // // a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EqualValuesf(a.t, expected, actual, msg, args...) } // Equalf asserts that two objects are equal. // // a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Equalf(a.t, expected, actual, msg, args...) } // Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Error(a.t, err, msgAndArgs...) } // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorAs(a.t, err, target, msgAndArgs...) } // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorAsf(a.t, err, target, msg, args...) } // ErrorContains asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorContains(a.t, theError, contains, msgAndArgs...) } // ErrorContainsf asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorContainsf(a.t, theError, contains, msg, args...) } // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorIs(a.t, err, target, msgAndArgs...) } // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return ErrorIsf(a.t, err, target, msg, args...) } // Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Errorf(a.t, err, msg, args...) } // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } // EventuallyWithT asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // a.EventuallyWithT(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) } // EventuallyWithTf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) } // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Eventuallyf(a.t, condition, waitFor, tick, msg, args...) } // Exactly asserts that two objects are equal in value and type. // // a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Exactly(a.t, expected, actual, msgAndArgs...) } // Exactlyf asserts that two objects are equal in value and type. // // a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Exactlyf(a.t, expected, actual, msg, args...) } // Fail reports a failure through func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Fail(a.t, failureMessage, msgAndArgs...) } // FailNow fails test func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return FailNow(a.t, failureMessage, msgAndArgs...) } // FailNowf fails test func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return FailNowf(a.t, failureMessage, msg, args...) } // Failf reports a failure through func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Failf(a.t, failureMessage, msg, args...) } // False asserts that the specified value is false. // // a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return False(a.t, value, msgAndArgs...) } // Falsef asserts that the specified value is false. // // a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Falsef(a.t, value, msg, args...) } // FileExists checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return FileExists(a.t, path, msgAndArgs...) } // FileExistsf checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return FileExistsf(a.t, path, msg, args...) } // Greater asserts that the first element is greater than the second // // a.Greater(2, 1) // a.Greater(float64(2), float64(1)) // a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Greater(a.t, e1, e2, msgAndArgs...) } // GreaterOrEqual asserts that the first element is greater than or equal to the second // // a.GreaterOrEqual(2, 1) // a.GreaterOrEqual(2, 2) // a.GreaterOrEqual("b", "a") // a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return GreaterOrEqual(a.t, e1, e2, msgAndArgs...) } // GreaterOrEqualf asserts that the first element is greater than or equal to the second // // a.GreaterOrEqualf(2, 1, "error message %s", "formatted") // a.GreaterOrEqualf(2, 2, "error message %s", "formatted") // a.GreaterOrEqualf("b", "a", "error message %s", "formatted") // a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return GreaterOrEqualf(a.t, e1, e2, msg, args...) } // Greaterf asserts that the first element is greater than the second // // a.Greaterf(2, 1, "error message %s", "formatted") // a.Greaterf(float64(2), float64(1), "error message %s", "formatted") // a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Greaterf(a.t, e1, e2, msg, args...) } // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) } // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) } // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) } // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) } // HTTPError asserts that a specified handler returns an error status code. // // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPError(a.t, handler, method, url, values, msgAndArgs...) } // HTTPErrorf asserts that a specified handler returns an error status code. // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPErrorf(a.t, handler, method, url, values, msg, args...) } // HTTPRedirect asserts that a specified handler returns a redirect status code. // // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) } // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPRedirectf(a.t, handler, method, url, values, msg, args...) } // HTTPStatusCode asserts that a specified handler returns a specified status code. // // a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) } // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) } // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) } // HTTPSuccessf asserts that a specified handler returns a success status code. // // a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return HTTPSuccessf(a.t, handler, method, url, values, msg, args...) } // Implements asserts that an object is implemented by the specified interface. // // a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Implements(a.t, interfaceObject, object, msgAndArgs...) } // Implementsf asserts that an object is implemented by the specified interface. // // a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Implementsf(a.t, interfaceObject, object, msg, args...) } // InDelta asserts that the two numerals are within delta of each other. // // a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDelta(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) } // InDeltaSlice is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaSlicef is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDeltaSlicef(a.t, expected, actual, delta, msg, args...) } // InDeltaf asserts that the two numerals are within delta of each other. // // a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InDeltaf(a.t, expected, actual, delta, msg, args...) } // InEpsilon asserts that expected and actual have a relative error less than epsilon func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) } // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) } // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) } // InEpsilonf asserts that expected and actual have a relative error less than epsilon func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } // IsDecreasing asserts that the collection is decreasing // // a.IsDecreasing([]int{2, 1, 0}) // a.IsDecreasing([]float{2, 1}) // a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsDecreasing(a.t, object, msgAndArgs...) } // IsDecreasingf asserts that the collection is decreasing // // a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") // a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") // a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsDecreasingf(a.t, object, msg, args...) } // IsIncreasing asserts that the collection is increasing // // a.IsIncreasing([]int{1, 2, 3}) // a.IsIncreasing([]float{1, 2}) // a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsIncreasing(a.t, object, msgAndArgs...) } // IsIncreasingf asserts that the collection is increasing // // a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") // a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") // a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsIncreasingf(a.t, object, msg, args...) } // IsNonDecreasing asserts that the collection is not decreasing // // a.IsNonDecreasing([]int{1, 1, 2}) // a.IsNonDecreasing([]float{1, 2}) // a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNonDecreasing(a.t, object, msgAndArgs...) } // IsNonDecreasingf asserts that the collection is not decreasing // // a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") // a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") // a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNonDecreasingf(a.t, object, msg, args...) } // IsNonIncreasing asserts that the collection is not increasing // // a.IsNonIncreasing([]int{2, 1, 1}) // a.IsNonIncreasing([]float{2, 1}) // a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNonIncreasing(a.t, object, msgAndArgs...) } // IsNonIncreasingf asserts that the collection is not increasing // // a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") // a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") // a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNonIncreasingf(a.t, object, msg, args...) } // IsNotType asserts that the specified objects are not of the same type. // // a.IsNotType(&NotMyStruct{}, &MyStruct{}) func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNotType(a.t, theType, object, msgAndArgs...) } // IsNotTypef asserts that the specified objects are not of the same type. // // a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted") func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsNotTypef(a.t, theType, object, msg, args...) } // IsType asserts that the specified objects are of the same type. // // a.IsType(&MyStruct{}, &MyStruct{}) func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsType(a.t, expectedType, object, msgAndArgs...) } // IsTypef asserts that the specified objects are of the same type. // // a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted") func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return IsTypef(a.t, expectedType, object, msg, args...) } // JSONEq asserts that two JSON strings are equivalent. // // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return JSONEq(a.t, expected, actual, msgAndArgs...) } // JSONEqf asserts that two JSON strings are equivalent. // // a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return JSONEqf(a.t, expected, actual, msg, args...) } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // // a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Len(a.t, object, length, msgAndArgs...) } // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // // a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Lenf(a.t, object, length, msg, args...) } // Less asserts that the first element is less than the second // // a.Less(1, 2) // a.Less(float64(1), float64(2)) // a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Less(a.t, e1, e2, msgAndArgs...) } // LessOrEqual asserts that the first element is less than or equal to the second // // a.LessOrEqual(1, 2) // a.LessOrEqual(2, 2) // a.LessOrEqual("a", "b") // a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return LessOrEqual(a.t, e1, e2, msgAndArgs...) } // LessOrEqualf asserts that the first element is less than or equal to the second // // a.LessOrEqualf(1, 2, "error message %s", "formatted") // a.LessOrEqualf(2, 2, "error message %s", "formatted") // a.LessOrEqualf("a", "b", "error message %s", "formatted") // a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return LessOrEqualf(a.t, e1, e2, msg, args...) } // Lessf asserts that the first element is less than the second // // a.Lessf(1, 2, "error message %s", "formatted") // a.Lessf(float64(1), float64(2), "error message %s", "formatted") // a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Lessf(a.t, e1, e2, msg, args...) } // Negative asserts that the specified element is negative // // a.Negative(-1) // a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Negative(a.t, e, msgAndArgs...) } // Negativef asserts that the specified element is negative // // a.Negativef(-1, "error message %s", "formatted") // a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Negativef(a.t, e, msg, args...) } // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Never(a.t, condition, waitFor, tick, msgAndArgs...) } // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Neverf(a.t, condition, waitFor, tick, msg, args...) } // Nil asserts that the specified object is nil. // // a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Nil(a.t, object, msgAndArgs...) } // Nilf asserts that the specified object is nil. // // a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Nilf(a.t, object, msg, args...) } // NoDirExists checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoDirExists(a.t, path, msgAndArgs...) } // NoDirExistsf checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoDirExistsf(a.t, path, msg, args...) } // NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoError(err) { // assert.Equal(t, expectedObj, actualObj) // } func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoError(a.t, err, msgAndArgs...) } // NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoErrorf(err, "error message %s", "formatted") { // assert.Equal(t, expectedObj, actualObj) // } func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoErrorf(a.t, err, msg, args...) } // NoFileExists checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoFileExists(a.t, path, msgAndArgs...) } // NoFileExistsf checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NoFileExistsf(a.t, path, msg, args...) } // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // a.NotContains("Hello World", "Earth") // a.NotContains(["Hello", "World"], "Earth") // a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotContains(a.t, s, contains, msgAndArgs...) } // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") // a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") // a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotContainsf(a.t, s, contains, msg, args...) } // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false // // a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true // // a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotElementsMatch(a.t, listA, listB, msgAndArgs...) } // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false // // a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true // // a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotElementsMatchf(a.t, listA, listB, msg, args...) } // NotEmpty asserts that the specified object is NOT [Empty]. // // if a.NotEmpty(obj) { // assert.Equal(t, "two", obj[1]) // } func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEmpty(a.t, object, msgAndArgs...) } // NotEmptyf asserts that the specified object is NOT [Empty]. // // if a.NotEmptyf(obj, "error message %s", "formatted") { // assert.Equal(t, "two", obj[1]) // } func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEmptyf(a.t, object, msg, args...) } // NotEqual asserts that the specified values are NOT equal. // // a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEqual(a.t, expected, actual, msgAndArgs...) } // NotEqualValues asserts that two objects are not equal even when converted to the same type // // a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEqualValues(a.t, expected, actual, msgAndArgs...) } // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // // a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEqualValuesf(a.t, expected, actual, msg, args...) } // NotEqualf asserts that the specified values are NOT equal. // // a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotEqualf(a.t, expected, actual, msg, args...) } // NotErrorAs asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotErrorAs(a.t, err, target, msgAndArgs...) } // NotErrorAsf asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotErrorAsf(a.t, err, target, msg, args...) } // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotErrorIs(a.t, err, target, msgAndArgs...) } // NotErrorIsf asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotErrorIsf(a.t, err, target, msg, args...) } // NotImplements asserts that an object does not implement the specified interface. // // a.NotImplements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotImplements(a.t, interfaceObject, object, msgAndArgs...) } // NotImplementsf asserts that an object does not implement the specified interface. // // a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotImplementsf(a.t, interfaceObject, object, msg, args...) } // NotNil asserts that the specified object is not nil. // // a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotNil(a.t, object, msgAndArgs...) } // NotNilf asserts that the specified object is not nil. // // a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotNilf(a.t, object, msg, args...) } // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // // a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotPanics(a.t, f, msgAndArgs...) } // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // // a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotPanicsf(a.t, f, msg, args...) } // NotRegexp asserts that a specified regexp does not match a string. // // a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotRegexp(a.t, rx, str, msgAndArgs...) } // NotRegexpf asserts that a specified regexp does not match a string. // // a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotRegexpf(a.t, rx, str, msg, args...) } // NotSame asserts that two pointers do not reference the same object. // // a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotSame(a.t, expected, actual, msgAndArgs...) } // NotSamef asserts that two pointers do not reference the same object. // // a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotSamef(a.t, expected, actual, msg, args...) } // NotSubset asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.NotSubset([1, 3, 4], [1, 2]) // a.NotSubset({"x": 1, "y": 2}, {"z": 3}) // a.NotSubset([1, 3, 4], {1: "one", 2: "two"}) // a.NotSubset({"x": 1, "y": 2}, ["z"]) func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotSubset(a.t, list, subset, msgAndArgs...) } // NotSubsetf asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") // a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") // a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted") // a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotSubsetf(a.t, list, subset, msg, args...) } // NotZero asserts that i is not the zero value for its type. func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotZero(a.t, i, msgAndArgs...) } // NotZerof asserts that i is not the zero value for its type. func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return NotZerof(a.t, i, msg, args...) } // Panics asserts that the code inside the specified PanicTestFunc panics. // // a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Panics(a.t, f, msgAndArgs...) } // PanicsWithError asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return PanicsWithError(a.t, errString, f, msgAndArgs...) } // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return PanicsWithErrorf(a.t, errString, f, msg, args...) } // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return PanicsWithValue(a.t, expected, f, msgAndArgs...) } // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return PanicsWithValuef(a.t, expected, f, msg, args...) } // Panicsf asserts that the code inside the specified PanicTestFunc panics. // // a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Panicsf(a.t, f, msg, args...) } // Positive asserts that the specified element is positive // // a.Positive(1) // a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Positive(a.t, e, msgAndArgs...) } // Positivef asserts that the specified element is positive // // a.Positivef(1, "error message %s", "formatted") // a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Positivef(a.t, e, msg, args...) } // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Regexp(a.t, rx, str, msgAndArgs...) } // Regexpf asserts that a specified regexp matches a string. // // a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Regexpf(a.t, rx, str, msg, args...) } // Same asserts that two pointers reference the same object. // // a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Same(a.t, expected, actual, msgAndArgs...) } // Samef asserts that two pointers reference the same object. // // a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Samef(a.t, expected, actual, msg, args...) } // Subset asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.Subset([1, 2, 3], [1, 2]) // a.Subset({"x": 1, "y": 2}, {"x": 1}) // a.Subset([1, 2, 3], {1: "one", 2: "two"}) // a.Subset({"x": 1, "y": 2}, ["x"]) func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Subset(a.t, list, subset, msgAndArgs...) } // Subsetf asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") // a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") // a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted") // a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Subsetf(a.t, list, subset, msg, args...) } // True asserts that the specified value is true. // // a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return True(a.t, value, msgAndArgs...) } // Truef asserts that the specified value is true. // // a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Truef(a.t, value, msg, args...) } // WithinDuration asserts that the two times are within duration delta of each other. // // a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) } // WithinDurationf asserts that the two times are within duration delta of each other. // // a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return WithinDurationf(a.t, expected, actual, delta, msg, args...) } // WithinRange asserts that a time is within a time range (inclusive). // // a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return WithinRange(a.t, actual, start, end, msgAndArgs...) } // WithinRangef asserts that a time is within a time range (inclusive). // // a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return WithinRangef(a.t, actual, start, end, msg, args...) } // YAMLEq asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return YAMLEq(a.t, expected, actual, msgAndArgs...) } // YAMLEqf asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return YAMLEqf(a.t, expected, actual, msg, args...) } // Zero asserts that i is the zero value for its type. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Zero(a.t, i, msgAndArgs...) } // Zerof asserts that i is the zero value for its type. func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return Zerof(a.t, i, msg, args...) } ================================================ FILE: assert/assertion_forward.go.tmpl ================================================ {{.CommentWithoutT "a"}} func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() } return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) } ================================================ FILE: assert/assertion_order.go ================================================ package assert import ( "fmt" "reflect" ) // isOrdered checks that collection contains orderable elements. func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { objKind := reflect.TypeOf(object).Kind() if objKind != reflect.Slice && objKind != reflect.Array { return Fail(t, fmt.Sprintf("object %T is not an ordered collection", object), msgAndArgs...) } objValue := reflect.ValueOf(object) objLen := objValue.Len() if objLen <= 1 { return true } value := objValue.Index(0) valueInterface := value.Interface() firstValueKind := value.Kind() for i := 1; i < objLen; i++ { prevValue := value prevValueInterface := valueInterface value = objValue.Index(i) valueInterface = value.Interface() compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) if !isComparable { return Fail(t, fmt.Sprintf(`Can not compare type "%T" and "%T"`, value, prevValue), msgAndArgs...) } if !containsValue(allowedComparesResults, compareResult) { return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) } } return true } // IsIncreasing asserts that the collection is increasing // // assert.IsIncreasing(t, []int{1, 2, 3}) // assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // IsNonIncreasing asserts that the collection is not increasing // // assert.IsNonIncreasing(t, []int{2, 1, 1}) // assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // IsDecreasing asserts that the collection is decreasing // // assert.IsDecreasing(t, []int{2, 1, 0}) // assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // IsNonDecreasing asserts that the collection is not decreasing // // assert.IsNonDecreasing(t, []int{1, 1, 2}) // assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } ================================================ FILE: assert/assertion_order_test.go ================================================ package assert import ( "bytes" "fmt" "testing" ) func TestIsIncreasing(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsIncreasing(mockT, []int{1, 2}) { t.Error("IsIncreasing should return true") } if !IsIncreasing(mockT, []int{1, 2, 3, 4, 5}) { t.Error("IsIncreasing should return true") } if IsIncreasing(mockT, []int{1, 1}) { t.Error("IsIncreasing should return false") } if IsIncreasing(mockT, []int{2, 1}) { t.Error("IsIncreasing should return false") } // Check error report for _, currCase := range []struct { collection interface{} msg string }{ {collection: []string{"b", "a"}, msg: `"b" is not less than "a"`}, {collection: []int{2, 1}, msg: `"2" is not less than "1"`}, {collection: []int{2, 1, 3, 4, 5, 6, 7}, msg: `"2" is not less than "1"`}, {collection: []int{-1, 0, 2, 1}, msg: `"2" is not less than "1"`}, {collection: []int8{2, 1}, msg: `"2" is not less than "1"`}, {collection: []int16{2, 1}, msg: `"2" is not less than "1"`}, {collection: []int32{2, 1}, msg: `"2" is not less than "1"`}, {collection: []int64{2, 1}, msg: `"2" is not less than "1"`}, {collection: []uint8{2, 1}, msg: `"2" is not less than "1"`}, {collection: []uint16{2, 1}, msg: `"2" is not less than "1"`}, {collection: []uint32{2, 1}, msg: `"2" is not less than "1"`}, {collection: []uint64{2, 1}, msg: `"2" is not less than "1"`}, {collection: []float32{2.34, 1.23}, msg: `"2.34" is not less than "1.23"`}, {collection: []float64{2.34, 1.23}, msg: `"2.34" is not less than "1.23"`}, {collection: struct{}{}, msg: `object struct {} is not an ordered collection`}, } { t.Run(fmt.Sprintf("%#v", currCase.collection), func(t *testing.T) { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, IsIncreasing(out, currCase.collection)) Contains(t, out.buf.String(), currCase.msg) }) } } func TestIsNonIncreasing(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsNonIncreasing(mockT, []int{2, 1}) { t.Error("IsNonIncreasing should return true") } if !IsNonIncreasing(mockT, []int{5, 4, 4, 3, 2, 1}) { t.Error("IsNonIncreasing should return true") } if !IsNonIncreasing(mockT, []int{1, 1}) { t.Error("IsNonIncreasing should return true") } if IsNonIncreasing(mockT, []int{1, 2}) { t.Error("IsNonIncreasing should return false") } // Check error report for _, currCase := range []struct { collection interface{} msg string }{ {collection: []string{"a", "b"}, msg: `"a" is not greater than or equal to "b"`}, {collection: []int{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int{1, 2, 7, 6, 5, 4, 3}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int{5, 4, 3, 1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int8{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int16{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int32{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []int64{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []uint8{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []uint16{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []uint32{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []uint64{1, 2}, msg: `"1" is not greater than or equal to "2"`}, {collection: []float32{1.23, 2.34}, msg: `"1.23" is not greater than or equal to "2.34"`}, {collection: []float64{1.23, 2.34}, msg: `"1.23" is not greater than or equal to "2.34"`}, {collection: struct{}{}, msg: `object struct {} is not an ordered collection`}, } { t.Run(fmt.Sprintf("%#v", currCase.collection), func(t *testing.T) { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, IsNonIncreasing(out, currCase.collection)) Contains(t, out.buf.String(), currCase.msg) }) } } func TestIsDecreasing(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsDecreasing(mockT, []int{2, 1}) { t.Error("IsDecreasing should return true") } if !IsDecreasing(mockT, []int{5, 4, 3, 2, 1}) { t.Error("IsDecreasing should return true") } if IsDecreasing(mockT, []int{1, 1}) { t.Error("IsDecreasing should return false") } if IsDecreasing(mockT, []int{1, 2}) { t.Error("IsDecreasing should return false") } // Check error report for _, currCase := range []struct { collection interface{} msg string }{ {collection: []string{"a", "b"}, msg: `"a" is not greater than "b"`}, {collection: []int{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []int{1, 2, 7, 6, 5, 4, 3}, msg: `"1" is not greater than "2"`}, {collection: []int{5, 4, 3, 1, 2}, msg: `"1" is not greater than "2"`}, {collection: []int8{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []int16{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []int32{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []int64{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []uint8{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []uint16{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []uint32{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []uint64{1, 2}, msg: `"1" is not greater than "2"`}, {collection: []float32{1.23, 2.34}, msg: `"1.23" is not greater than "2.34"`}, {collection: []float64{1.23, 2.34}, msg: `"1.23" is not greater than "2.34"`}, {collection: struct{}{}, msg: `object struct {} is not an ordered collection`}, } { t.Run(fmt.Sprintf("%#v", currCase.collection), func(t *testing.T) { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, IsDecreasing(out, currCase.collection)) Contains(t, out.buf.String(), currCase.msg) }) } } func TestIsNonDecreasing(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsNonDecreasing(mockT, []int{1, 2}) { t.Error("IsNonDecreasing should return true") } if !IsNonDecreasing(mockT, []int{1, 1, 2, 3, 4, 5}) { t.Error("IsNonDecreasing should return true") } if !IsNonDecreasing(mockT, []int{1, 1}) { t.Error("IsNonDecreasing should return false") } if IsNonDecreasing(mockT, []int{2, 1}) { t.Error("IsNonDecreasing should return false") } // Check error report for _, currCase := range []struct { collection interface{} msg string }{ {collection: []string{"b", "a"}, msg: `"b" is not less than or equal to "a"`}, {collection: []int{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []int{2, 1, 3, 4, 5, 6, 7}, msg: `"2" is not less than or equal to "1"`}, {collection: []int{-1, 0, 2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []int8{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []int16{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []int32{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []int64{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []uint8{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []uint16{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []uint32{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []uint64{2, 1}, msg: `"2" is not less than or equal to "1"`}, {collection: []float32{2.34, 1.23}, msg: `"2.34" is not less than or equal to "1.23"`}, {collection: []float64{2.34, 1.23}, msg: `"2.34" is not less than or equal to "1.23"`}, {collection: struct{}{}, msg: `object struct {} is not an ordered collection`}, } { t.Run(fmt.Sprintf("%#v", currCase.collection), func(t *testing.T) { out := &outputT{buf: bytes.NewBuffer(nil)} False(t, IsNonDecreasing(out, currCase.collection)) Contains(t, out.buf.String(), currCase.msg) }) } } func TestOrderingMsgAndArgsForwarding(t *testing.T) { t.Parallel() msgAndArgs := []interface{}{"format %s %x", "this", 0xc001} expectedOutput := "format this c001\n" collection := []int{1, 2, 1} funcs := []func(t TestingT){ func(t TestingT) { IsIncreasing(t, collection, msgAndArgs...) }, func(t TestingT) { IsNonIncreasing(t, collection, msgAndArgs...) }, func(t TestingT) { IsDecreasing(t, collection, msgAndArgs...) }, func(t TestingT) { IsNonDecreasing(t, collection, msgAndArgs...) }, } for _, f := range funcs { out := &outputT{buf: bytes.NewBuffer(nil)} f(out) Contains(t, out.buf.String(), expectedOutput) } } ================================================ FILE: assert/assertions.go ================================================ package assert import ( "bufio" "bytes" "encoding/json" "errors" "fmt" "math" "os" "reflect" "regexp" "runtime" "runtime/debug" "strings" "time" "unicode" "unicode/utf8" // Wrapper around gopkg.in/yaml.v3 "github.com/stretchr/testify/assert/yaml" "github.com/stretchr/testify/internal/difflib" "github.com/stretchr/testify/internal/spew" ) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" // TestingT is an interface wrapper around *testing.T type TestingT interface { Errorf(format string, args ...interface{}) } // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful // for table driven tests. type PanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool // Comparison is a custom function that returns true on success and false on failure type Comparison func() (success bool) /* Helper functions */ // ObjectsAreEqual determines if two objects are considered equal. // // This function does no assertion of any kind. func ObjectsAreEqual(expected, actual interface{}) bool { if expected == nil || actual == nil { return expected == actual } exp, ok := expected.([]byte) if !ok { return reflect.DeepEqual(expected, actual) } act, ok := actual.([]byte) if !ok { return false } if exp == nil || act == nil { return exp == nil && act == nil } return bytes.Equal(exp, act) } // copyExportedFields iterates downward through nested data structures and creates a copy // that only contains the exported struct fields. func copyExportedFields(expected interface{}) interface{} { if isNil(expected) { return expected } expectedType := reflect.TypeOf(expected) expectedKind := expectedType.Kind() expectedValue := reflect.ValueOf(expected) switch expectedKind { case reflect.Struct: result := reflect.New(expectedType).Elem() for i := 0; i < expectedType.NumField(); i++ { field := expectedType.Field(i) isExported := field.IsExported() if isExported { fieldValue := expectedValue.Field(i) if isNil(fieldValue) || isNil(fieldValue.Interface()) { continue } newValue := copyExportedFields(fieldValue.Interface()) result.Field(i).Set(reflect.ValueOf(newValue)) } } return result.Interface() case reflect.Ptr: result := reflect.New(expectedType.Elem()) unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface()) result.Elem().Set(reflect.ValueOf(unexportedRemoved)) return result.Interface() case reflect.Array, reflect.Slice: var result reflect.Value if expectedKind == reflect.Array { result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem() } else { result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len()) } for i := 0; i < expectedValue.Len(); i++ { index := expectedValue.Index(i) if isNil(index) { continue } unexportedRemoved := copyExportedFields(index.Interface()) result.Index(i).Set(reflect.ValueOf(unexportedRemoved)) } return result.Interface() case reflect.Map: result := reflect.MakeMap(expectedType) for _, k := range expectedValue.MapKeys() { index := expectedValue.MapIndex(k) unexportedRemoved := copyExportedFields(index.Interface()) result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved)) } return result.Interface() default: return expected } } // ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are // considered equal. This comparison of only exported fields is applied recursively to nested data // structures. // // This function does no assertion of any kind. // // Deprecated: Use [EqualExportedValues] instead. func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool { expectedCleaned := copyExportedFields(expected) actualCleaned := copyExportedFields(actual) return ObjectsAreEqualValues(expectedCleaned, actualCleaned) } // ObjectsAreEqualValues gets whether two objects are equal, or if their // values are equal. func ObjectsAreEqualValues(expected, actual interface{}) bool { if ObjectsAreEqual(expected, actual) { return true } expectedValue := reflect.ValueOf(expected) actualValue := reflect.ValueOf(actual) if !expectedValue.IsValid() || !actualValue.IsValid() { return false } expectedType := expectedValue.Type() actualType := actualValue.Type() if !expectedType.ConvertibleTo(actualType) { return false } if !isNumericType(expectedType) || !isNumericType(actualType) { // Attempt comparison after type conversion return reflect.DeepEqual( expectedValue.Convert(actualType).Interface(), actual, ) } // If BOTH values are numeric, there are chances of false positives due // to overflow or underflow. So, we need to make sure to always convert // the smaller type to a larger type before comparing. if expectedType.Size() >= actualType.Size() { return actualValue.Convert(expectedType).Interface() == expected } return expectedValue.Convert(actualType).Interface() == actual } // isNumericType returns true if the type is one of: // int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, // float32, float64, complex64, complex128 func isNumericType(t reflect.Type) bool { return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128 } /* CallerInfo is necessary because the assert functions use the testing object internally, causing it to print the file:line of the assert method, rather than where the problem actually occurred in calling code.*/ // CallerInfo returns an array of strings containing the file and line number // of each stack frame leading from the current test to the assert call that // failed. func CallerInfo() []string { var pc uintptr var file string var line int var name string const stackFrameBufferSize = 10 pcs := make([]uintptr, stackFrameBufferSize) callers := []string{} offset := 1 for { n := runtime.Callers(offset, pcs) if n == 0 { break } frames := runtime.CallersFrames(pcs[:n]) for { frame, more := frames.Next() pc = frame.PC file = frame.File line = frame.Line // This is a huge edge case, but it will panic if this is the case, see #180 if file == "" { break } f := runtime.FuncForPC(pc) if f == nil { break } name = f.Name() // testing.tRunner is the standard library function that calls // tests. Subtests are called directly by tRunner, without going through // the Test/Benchmark/Example function that contains the t.Run calls, so // with subtests we should break when we hit tRunner, without adding it // to the list of callers. if name == "testing.tRunner" { break } parts := strings.Split(file, "/") if len(parts) > 1 { filename := parts[len(parts)-1] dir := parts[len(parts)-2] if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" { callers = append(callers, fmt.Sprintf("%s:%d", file, line)) } } // Drop the package dotPos := strings.LastIndexByte(name, '.') name = name[dotPos+1:] if isTest(name, "Test") || isTest(name, "Benchmark") || isTest(name, "Example") { break } if !more { break } } // Next batch offset += cap(pcs) } return callers } // Stolen from the `go test` tool. // isTest tells whether name looks like a test (or benchmark, according to prefix). // It is a Test (say) if there is a character after Test that is not a lower-case letter. // We don't want TesticularCancer. func isTest(name, prefix string) bool { if !strings.HasPrefix(name, prefix) { return false } if len(name) == len(prefix) { // "Test" is ok return true } r, _ := utf8.DecodeRuneInString(name[len(prefix):]) return !unicode.IsLower(r) } func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { if len(msgAndArgs) == 0 || msgAndArgs == nil { return "" } if len(msgAndArgs) == 1 { msg := msgAndArgs[0] if msgAsStr, ok := msg.(string); ok { return msgAsStr } return fmt.Sprintf("%+v", msg) } if len(msgAndArgs) > 1 { return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) } return "" } // Aligns the provided message so that all lines after the first line start at the same location as the first line. // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). // The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the // basis on which the alignment occurs). func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) scanner := bufio.NewScanner(strings.NewReader(message)) for firstLine := true; scanner.Scan(); firstLine = false { if !firstLine { fmt.Fprint(outBuf, "\n\t"+strings.Repeat(" ", longestLabelLen+1)+"\t") } fmt.Fprint(outBuf, scanner.Text()) } if err := scanner.Err(); err != nil { return fmt.Sprintf("cannot display message: %s", err) } return outBuf.String() } type failNower interface { FailNow() } // FailNow fails test func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } Fail(t, failureMessage, msgAndArgs...) // We cannot extend TestingT with FailNow() and // maintain backwards compatibility, so we fallback // to panicking when FailNow is not available in // TestingT. // See issue #263 if t, ok := t.(failNower); ok { t.FailNow() } else { panic("test failed and t is missing `FailNow()`") } return false } // Fail reports a failure through func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } content := []labeledContent{ {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, {"Error", failureMessage}, } // Add test name if the Go version supports it if n, ok := t.(interface { Name() string }); ok { content = append(content, labeledContent{"Test", n.Name()}) } message := messageFromMsgAndArgs(msgAndArgs...) if len(message) > 0 { content = append(content, labeledContent{"Messages", message}) } t.Errorf("\n%s", ""+labeledOutput(content...)) return false } type labeledContent struct { label string content string } // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: // // \t{{label}}:{{align_spaces}}\t{{content}}\n // // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this // alignment is achieved, "\t{{content}}\n" is added for the output. // // 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. func labeledOutput(content ...labeledContent) string { longestLabel := 0 for _, v := range content { if len(v.label) > longestLabel { longestLabel = len(v.label) } } var output string for _, v := range content { output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" } return output } // Implements asserts that an object is implemented by the specified interface. // // assert.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } interfaceType := reflect.TypeOf(interfaceObject).Elem() if object == nil { return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...) } if !reflect.TypeOf(object).Implements(interfaceType) { return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) } return true } // NotImplements asserts that an object does not implement the specified interface. // // assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } interfaceType := reflect.TypeOf(interfaceObject).Elem() if object == nil { return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...) } if reflect.TypeOf(object).Implements(interfaceType) { return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...) } return true } func isType(expectedType, object interface{}) bool { return ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) } // IsType asserts that the specified objects are of the same type. // // assert.IsType(t, &MyStruct{}, &MyStruct{}) func IsType(t TestingT, expectedType, object interface{}, msgAndArgs ...interface{}) bool { if isType(expectedType, object) { return true } if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, fmt.Sprintf("Object expected to be of type %T, but was %T", expectedType, object), msgAndArgs...) } // IsNotType asserts that the specified objects are not of the same type. // // assert.IsNotType(t, &NotMyStruct{}, &MyStruct{}) func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...interface{}) bool { if !isType(theType, object) { return true } if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...) } // Equal asserts that two objects are equal. // // assert.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if err := validateEqualArgs(expected, actual); err != nil { return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)", expected, actual, err), msgAndArgs...) } if !ObjectsAreEqual(expected, actual) { diff := diff(expected, actual) expected, actual = formatUnequalValues(expected, actual) return Fail(t, fmt.Sprintf("Not equal: \n"+ "expected: %s\n"+ "actual : %s%s", expected, actual, diff), msgAndArgs...) } return true } // validateEqualArgs checks whether provided arguments can be safely used in the // Equal/NotEqual functions. func validateEqualArgs(expected, actual interface{}) error { if expected == nil && actual == nil { return nil } if isFunction(expected) || isFunction(actual) { return errors.New("cannot take func type as argument") } return nil } // Same asserts that two pointers reference the same object. // // assert.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } same, ok := samePointers(expected, actual) if !ok { return Fail(t, "Both arguments must be pointers", msgAndArgs...) } if !same { // both are pointers but not the same type & pointing to the same address return Fail(t, fmt.Sprintf("Not same: \n"+ "expected: %[2]s (%[1]T)(%[1]p)\n"+ "actual : %[4]s (%[3]T)(%[3]p)", expected, truncatingFormat("%#v", expected), actual, truncatingFormat("%#v", actual)), msgAndArgs...) } return true } // NotSame asserts that two pointers do not reference the same object. // // assert.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } same, ok := samePointers(expected, actual) if !ok { // fails when the arguments are not pointers return !(Fail(t, "Both arguments must be pointers", msgAndArgs...)) } if same { return Fail(t, fmt.Sprintf( "Expected and actual point to the same object: %p %s", expected, truncatingFormat("%#v", expected)), msgAndArgs...) } return true } // samePointers checks if two generic interface objects are pointers of the same // type pointing to the same object. It returns two values: same indicating if // they are the same type and point to the same object, and ok indicating that // both inputs are pointers. func samePointers(first, second interface{}) (same bool, ok bool) { firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { return false, false // not both are pointers } firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) if firstType != secondType { return false, true // both are pointers, but of different types } // compare pointer addresses return first == second, true } // formatUnequalValues takes two values of arbitrary types and returns string // representations appropriate to be presented to the user. // // If the values are not of like type, the returned strings will be prefixed // with the type name, and the value will be enclosed in parentheses similar // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { return fmt.Sprintf("%T(%s)", expected, truncatingFormat("%#v", expected)), fmt.Sprintf("%T(%s)", actual, truncatingFormat("%#v", actual)) } switch expected.(type) { case time.Duration: return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) } return truncatingFormat("%#v", expected), truncatingFormat("%#v", actual) } // truncatingFormat formats the data and truncates it if it's too long. // // This helps keep formatted error messages lines from exceeding the // bufio.MaxScanTokenSize max line length that the go testing framework imposes. func truncatingFormat(format string, data interface{}) string { value := fmt.Sprintf(format, data) // Give us space for two truncated objects and the surrounding sentence. maxMessageSize := bufio.MaxScanTokenSize/2 - 100 if len(value) > maxMessageSize { value = value[0:maxMessageSize] + "<... truncated>" } return value } // EqualValues asserts that two objects are equal or convertible to the larger // type and equal. // // assert.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !ObjectsAreEqualValues(expected, actual) { diff := diff(expected, actual) expected, actual = formatUnequalValues(expected, actual) return Fail(t, fmt.Sprintf("Not equal: \n"+ "expected: %s\n"+ "actual : %s%s", expected, actual, diff), msgAndArgs...) } return true } // EqualExportedValues asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true // assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } aType := reflect.TypeOf(expected) bType := reflect.TypeOf(actual) if aType != bType { return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) } expected = copyExportedFields(expected) actual = copyExportedFields(actual) if !ObjectsAreEqualValues(expected, actual) { diff := diff(expected, actual) expected, actual = formatUnequalValues(expected, actual) return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+ "expected: %s\n"+ "actual : %s%s", expected, actual, diff), msgAndArgs...) } return true } // Exactly asserts that two objects are equal in value and type. // // assert.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } aType := reflect.TypeOf(expected) bType := reflect.TypeOf(actual) if aType != bType { return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) } return Equal(t, expected, actual, msgAndArgs...) } // NotNil asserts that the specified object is not nil. // // assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if !isNil(object) { return true } if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, "Expected value not to be nil.", msgAndArgs...) } // isNil checks if a specified object is nil or not, without Failing. func isNil(object interface{}) bool { if object == nil { return true } value := reflect.ValueOf(object) switch value.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: return value.IsNil() } return false } // Nil asserts that the specified object is nil. // // assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if isNil(object) { return true } if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, fmt.Sprintf("Expected nil, but got: %s", truncatingFormat("%#v", object)), msgAndArgs...) } // isEmpty gets whether the specified object is considered empty or not. func isEmpty(object interface{}) bool { // get nil case out of the way if object == nil { return true } return isEmptyValue(reflect.ValueOf(object)) } // isEmptyValue gets whether the specified reflect.Value is considered empty or not. func isEmptyValue(objValue reflect.Value) bool { if objValue.IsZero() { return true } // Special cases of non-zero values that we consider empty switch objValue.Kind() { // collection types are empty when they have no element // Note: array types are empty when they match their zero-initialized state. case reflect.Chan, reflect.Map, reflect.Slice: return objValue.Len() == 0 // non-nil pointers are empty if the value they point to is empty case reflect.Ptr: return isEmptyValue(objValue.Elem()) } return false } // Empty asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // assert.Empty(t, obj) // // [Zero values]: https://go.dev/ref/spec#The_zero_value func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := isEmpty(object) if !pass { if h, ok := t.(tHelper); ok { h.Helper() } Fail(t, fmt.Sprintf("Should be empty, but was %s", truncatingFormat("%v", object)), msgAndArgs...) } return pass } // NotEmpty asserts that the specified object is NOT [Empty]. // // if assert.NotEmpty(t, obj) { // assert.Equal(t, "two", obj[1]) // } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := !isEmpty(object) if !pass { if h, ok := t.(tHelper); ok { h.Helper() } Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) } return pass } // getLen tries to get the length of an object. // It returns (0, false) if impossible. func getLen(x interface{}) (length int, ok bool) { v := reflect.ValueOf(x) defer func() { ok = recover() == nil }() return v.Len(), true } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // // assert.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } l, ok := getLen(object) if !ok { return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", truncatingFormat("%v", object)), msgAndArgs...) } if l != length { return Fail(t, fmt.Sprintf("%q should have %d item(s), but has %d", truncatingFormat("%v", object), length, l), msgAndArgs...) } return true } // True asserts that the specified value is true. // // assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { if !value { if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, "Should be true", msgAndArgs...) } return true } // False asserts that the specified value is false. // // assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { if value { if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, "Should be false", msgAndArgs...) } return true } // NotEqual asserts that the specified values are NOT equal. // // assert.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if err := validateEqualArgs(expected, actual); err != nil { return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)", expected, actual, err), msgAndArgs...) } if ObjectsAreEqual(expected, actual) { return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true } // NotEqualValues asserts that two objects are not equal even when converted to the same type // // assert.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if ObjectsAreEqualValues(expected, actual) { return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true } // containsElement try loop over the list check if the list includes the element. // return (false, false) if impossible. // return (true, false) if element was not found. // return (true, true) if element was found. func containsElement(list interface{}, element interface{}) (ok, found bool) { listValue := reflect.ValueOf(list) listType := reflect.TypeOf(list) if listType == nil { return false, false } listKind := listType.Kind() defer func() { if e := recover(); e != nil { ok = false found = false } }() if listKind == reflect.String { elementValue := reflect.ValueOf(element) return true, strings.Contains(listValue.String(), elementValue.String()) } if listKind == reflect.Map { mapKeys := listValue.MapKeys() for i := 0; i < len(mapKeys); i++ { if ObjectsAreEqual(mapKeys[i].Interface(), element) { return true, true } } return true, false } for i := 0; i < listValue.Len(); i++ { if ObjectsAreEqual(listValue.Index(i).Interface(), element) { return true, true } } return true, false } // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // assert.Contains(t, "Hello World", "World") // assert.Contains(t, ["Hello", "World"], "World") // assert.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if !found { return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true } // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // assert.NotContains(t, "Hello World", "Earth") // assert.NotContains(t, ["Hello", "World"], "Earth") // assert.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if found { return Fail(t, fmt.Sprintf("%s should not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true } // Subset asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // assert.Subset(t, [1, 2, 3], [1, 2]) // assert.Subset(t, {"x": 1, "y": 2}, {"x": 1}) // assert.Subset(t, [1, 2, 3], {1: "one", 2: "two"}) // assert.Subset(t, {"x": 1, "y": 2}, ["x"]) func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() } if subset == nil { return true // we consider nil to be equal to the nil set } listKind := reflect.TypeOf(list).Kind() if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } if subsetKind == reflect.Map && listKind == reflect.Map { subsetMap := reflect.ValueOf(subset) actualMap := reflect.ValueOf(list) for _, k := range subsetMap.MapKeys() { ev := subsetMap.MapIndex(k) av := actualMap.MapIndex(k) if !av.IsValid() { return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } if !ObjectsAreEqual(ev.Interface(), av.Interface()) { return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } } return true } subsetList := reflect.ValueOf(subset) if subsetKind == reflect.Map { keys := make([]interface{}, subsetList.Len()) for idx, key := range subsetList.MapKeys() { keys[idx] = key.Interface() } subsetList = reflect.ValueOf(keys) } for i := 0; i < subsetList.Len(); i++ { element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...) } } return true } // NotSubset asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // assert.NotSubset(t, [1, 3, 4], [1, 2]) // assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) // assert.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"}) // assert.NotSubset(t, {"x": 1, "y": 2}, ["z"]) func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() } if subset == nil { return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } listKind := reflect.TypeOf(list).Kind() if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } if subsetKind == reflect.Map && listKind == reflect.Map { subsetMap := reflect.ValueOf(subset) actualMap := reflect.ValueOf(list) for _, k := range subsetMap.MapKeys() { ev := subsetMap.MapIndex(k) av := actualMap.MapIndex(k) if !av.IsValid() { return true } if !ObjectsAreEqual(ev.Interface(), av.Interface()) { return true } } return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...) } subsetList := reflect.ValueOf(subset) if subsetKind == reflect.Map { keys := make([]interface{}, subsetList.Len()) for idx, key := range subsetList.MapKeys() { keys[idx] = key.Interface() } subsetList = reflect.ValueOf(keys) } for i := 0; i < subsetList.Len(); i++ { element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...) } if !found { return true } } return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...) } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() } if isEmpty(listA) && isEmpty(listB) { return true } if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) { return false } extraA, extraB := diffLists(listA, listB) if len(extraA) == 0 && len(extraB) == 0 { return true } return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...) } // isList checks that the provided value is array or slice. func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) { kind := reflect.TypeOf(list).Kind() if kind != reflect.Array && kind != reflect.Slice { return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), msgAndArgs...) } return true } // diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. // If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and // 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { aValue := reflect.ValueOf(listA) bValue := reflect.ValueOf(listB) aLen := aValue.Len() bLen := bValue.Len() // Mark indexes in bValue that we already used visited := make([]bool, bLen) for i := 0; i < aLen; i++ { element := aValue.Index(i).Interface() found := false for j := 0; j < bLen; j++ { if visited[j] { continue } if ObjectsAreEqual(bValue.Index(j).Interface(), element) { visited[j] = true found = true break } } if !found { extraA = append(extraA, element) } } for j := 0; j < bLen; j++ { if visited[j] { continue } extraB = append(extraB, bValue.Index(j).Interface()) } return } func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string { var msg bytes.Buffer msg.WriteString("elements differ") if len(extraA) > 0 { msg.WriteString("\n\nextra elements in list A:\n") msg.WriteString(spewConfig.Sdump(extraA)) } if len(extraB) > 0 { msg.WriteString("\n\nextra elements in list B:\n") msg.WriteString(spewConfig.Sdump(extraB)) } msg.WriteString("\n\nlistA:\n") msg.WriteString(spewConfig.Sdump(listA)) msg.WriteString("\n\nlistB:\n") msg.WriteString(spewConfig.Sdump(listB)) return msg.String() } // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false // // assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true // // assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() } if isEmpty(listA) && isEmpty(listB) { return Fail(t, "listA and listB contain the same elements", msgAndArgs) } if !isList(t, listA, msgAndArgs...) { return Fail(t, "listA is not a list type", msgAndArgs...) } if !isList(t, listB, msgAndArgs...) { return Fail(t, "listB is not a list type", msgAndArgs...) } extraA, extraB := diffLists(listA, listB) if len(extraA) == 0 && len(extraB) == 0 { return Fail(t, "listA and listB contain the same elements", msgAndArgs) } return true } // Condition uses a Comparison to assert a complex condition. func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } result := comp() if !result { Fail(t, "Condition failed!", msgAndArgs...) } return result } // PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics // methods, and represents a simple func that takes no arguments, and returns nothing. type PanicTestFunc func() // didPanic returns true if the function passed to it panics. Otherwise, it returns false. func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { didPanic = true defer func() { message = recover() if didPanic { stack = string(debug.Stack()) } }() // call the target function f() didPanic = false return } // Panics asserts that the code inside the specified PanicTestFunc panics. // // assert.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } return true } // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } funcDidPanic, panicValue, panickedStack := didPanic(f) if !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } if panicValue != expected { return Fail(t, 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...) } return true } // PanicsWithError asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } funcDidPanic, panicValue, panickedStack := didPanic(f) if !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } panicErr, isError := panicValue.(error) if !isError || panicErr.Error() != errString { msg := fmt.Sprintf("func %#v should panic with error message:\t%#v\n", f, errString) if isError { msg += fmt.Sprintf("\tError message:\t%#v\n", panicErr.Error()) } msg += fmt.Sprintf("\tPanic value:\t%#v\n", panicValue) msg += fmt.Sprintf("\tPanic stack:\t%s\n", panickedStack) return Fail(t, msg, msgAndArgs...) } return true } // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // // assert.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...) } return true } // WithinDuration asserts that the two times are within duration delta of each other. // // assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } dt := expected.Sub(actual) if dt < -delta || dt > delta { return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) } return true } // WithinRange asserts that a time is within a time range (inclusive). // // assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if end.Before(start) { return Fail(t, "Start should be before end", msgAndArgs...) } if actual.Before(start) { return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...) } else if actual.After(end) { return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...) } return true } func toFloat(x interface{}) (float64, bool) { var xf float64 xok := true switch xn := x.(type) { case uint: xf = float64(xn) case uint8: xf = float64(xn) case uint16: xf = float64(xn) case uint32: xf = float64(xn) case uint64: xf = float64(xn) case int: xf = float64(xn) case int8: xf = float64(xn) case int16: xf = float64(xn) case int32: xf = float64(xn) case int64: xf = float64(xn) case float32: xf = float64(xn) case float64: xf = xn case time.Duration: xf = float64(xn) default: xok = false } return xf, xok } // InDelta asserts that the two numerals are within delta of each other. // // assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } af, aok := toFloat(expected) bf, bok := toFloat(actual) if !aok || !bok { return Fail(t, "Parameters must be numerical", msgAndArgs...) } if math.IsNaN(af) && math.IsNaN(bf) { return true } if math.IsNaN(af) { return Fail(t, "Expected must not be NaN", msgAndArgs...) } if math.IsNaN(bf) { return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...) } dt := af - bf if dt < -delta || dt > delta { return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) } return true } // InDeltaSlice is the same as InDelta, except it compares two slices. func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) expectedSlice := reflect.ValueOf(expected) for i := 0; i < actualSlice.Len(); i++ { result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...) if !result { return result } } return true } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Map || reflect.TypeOf(expected).Kind() != reflect.Map { return Fail(t, "Arguments must be maps", msgAndArgs...) } expectedMap := reflect.ValueOf(expected) actualMap := reflect.ValueOf(actual) if expectedMap.Len() != actualMap.Len() { return Fail(t, "Arguments must have the same number of keys", msgAndArgs...) } for _, k := range expectedMap.MapKeys() { ev := expectedMap.MapIndex(k) av := actualMap.MapIndex(k) if !ev.IsValid() { return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...) } if !av.IsValid() { return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...) } if !InDelta( t, ev.Interface(), av.Interface(), delta, msgAndArgs..., ) { return false } } return true } func calcRelativeError(expected, actual interface{}) (float64, error) { af, aok := toFloat(expected) bf, bok := toFloat(actual) if !aok || !bok { return 0, fmt.Errorf("Parameters must be numerical") } if math.IsNaN(af) && math.IsNaN(bf) { return 0, nil } if math.IsNaN(af) { return 0, errors.New("expected value must not be NaN") } if af == 0 { return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") } if math.IsNaN(bf) { return 0, errors.New("actual value must not be NaN") } return math.Abs(af-bf) / math.Abs(af), nil } // InEpsilon asserts that expected and actual have a relative error less than epsilon func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if math.IsNaN(epsilon) { return Fail(t, "epsilon must not be NaN", msgAndArgs...) } actualEpsilon, err := calcRelativeError(expected, actual) if err != nil { return Fail(t, err.Error(), msgAndArgs...) } if math.IsNaN(actualEpsilon) { return Fail(t, "relative error is NaN", msgAndArgs...) } if actualEpsilon > epsilon { return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...) } return true } // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if expected == nil || actual == nil { return Fail(t, "Parameters must be slice", msgAndArgs...) } expectedSlice := reflect.ValueOf(expected) actualSlice := reflect.ValueOf(actual) if expectedSlice.Type().Kind() != reflect.Slice { return Fail(t, "Expected value must be slice", msgAndArgs...) } expectedLen := expectedSlice.Len() if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) { return false } for i := 0; i < expectedLen; i++ { if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) { return false } } return true } /* Errors */ // NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoError(t, err) { // assert.Equal(t, expectedObj, actualObj) // } func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if err != nil { if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, fmt.Sprintf("Received unexpected error:\n%s", truncatingFormat("%+v", err)), msgAndArgs...) } return true } // Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Error(t, err) func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { if err == nil { if h, ok := t.(tHelper); ok { h.Helper() } return Fail(t, "An error is expected but got nil.", msgAndArgs...) } return true } // EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // assert.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !Error(t, theError, msgAndArgs...) { return false } expected := errString actual := theError.Error() // don't need to use deep equals here, we know they are both strings if expected != actual { return Fail(t, fmt.Sprintf("Error message not equal:\n"+ "expected: %q\n"+ "actual : %s", expected, truncatingFormat("%q", actual)), msgAndArgs...) } return true } // ErrorContains asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !Error(t, theError, msgAndArgs...) { return false } actual := theError.Error() if !strings.Contains(actual, contains) { return Fail(t, fmt.Sprintf("Error %s does not contain %#v", truncatingFormat("%#v", actual), contains), msgAndArgs...) } return true } // matchRegexp return true if a specified regexp matches a string. func matchRegexp(rx interface{}, str interface{}) bool { var r *regexp.Regexp if rr, ok := rx.(*regexp.Regexp); ok { r = rr } else { r = regexp.MustCompile(fmt.Sprint(rx)) } switch v := str.(type) { case []byte: return r.Match(v) case string: return r.MatchString(v) default: return r.MatchString(fmt.Sprint(v)) } } // Regexp asserts that a specified regexp matches a string. // // assert.Regexp(t, regexp.MustCompile("start"), "it's starting") // assert.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } match := matchRegexp(rx, str) if !match { Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...) } return match } // NotRegexp asserts that a specified regexp does not match a string. // // assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") // assert.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } match := matchRegexp(rx, str) if match { Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) } return !match } // Zero asserts that i is the zero value for its type. func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { return Fail(t, fmt.Sprintf("Should be zero, but was %s", truncatingFormat("%v", i)), msgAndArgs...) } return true } // NotZero asserts that i is not the zero value for its type. func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) } return true } // FileExists checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } info, err := os.Lstat(path) if err != nil { if os.IsNotExist(err) { return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) } return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) } if info.IsDir() { return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...) } return true } // NoFileExists checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } info, err := os.Lstat(path) if err != nil { return true } if info.IsDir() { return true } return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...) } // DirExists checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } info, err := os.Lstat(path) if err != nil { if os.IsNotExist(err) { return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) } return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) } if !info.IsDir() { return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...) } return true } // NoDirExists checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } info, err := os.Lstat(path) if err != nil { if os.IsNotExist(err) { return true } return true } if !info.IsDir() { return true } return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...) } // JSONEq asserts that two JSON strings are equivalent. // // assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } var expectedJSONAsInterface, actualJSONAsInterface interface{} if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) } // Shortcut if same bytes if actual == expected { return true } if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) } return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) } // YAMLEq asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // assert.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } var expectedYAMLAsInterface, actualYAMLAsInterface interface{} if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil { return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...) } // Shortcut if same bytes if actual == expected { return true } if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil { return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...) } return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...) } func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { t := reflect.TypeOf(v) k := t.Kind() if k == reflect.Ptr { t = t.Elem() k = t.Kind() } return t, k } // diff returns a diff of both values as long as both are of the same type and // are a struct, map, slice, array or string. Otherwise it returns an empty string. func diff(expected interface{}, actual interface{}) string { if expected == nil || actual == nil { return "" } et, ek := typeAndKind(expected) at, _ := typeAndKind(actual) if et != at { return "" } if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { return "" } var e, a string switch et { case reflect.TypeOf(""): e = reflect.ValueOf(expected).String() a = reflect.ValueOf(actual).String() case reflect.TypeOf(time.Time{}): e = spewConfigStringerEnabled.Sdump(expected) a = spewConfigStringerEnabled.Sdump(actual) default: e = spewConfig.Sdump(expected) a = spewConfig.Sdump(actual) } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ A: difflib.SplitLines(e), B: difflib.SplitLines(a), FromFile: "Expected", FromDate: "", ToFile: "Actual", ToDate: "", Context: 1, }) return "\n\nDiff:\n" + diff } func isFunction(arg interface{}) bool { if arg == nil { return false } return reflect.TypeOf(arg).Kind() == reflect.Func } var spewConfig = spew.ConfigState{ Indent: " ", DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, DisableMethods: true, MaxDepth: 10, } var spewConfigStringerEnabled = spew.ConfigState{ Indent: " ", DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, MaxDepth: 10, } type tHelper = interface { Helper() } // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } ch := make(chan bool, 1) checkCond := func() { ch <- condition() } timer := time.NewTimer(waitFor) defer timer.Stop() ticker := time.NewTicker(tick) defer ticker.Stop() var tickC <-chan time.Time // Check the condition once first on the initial call. go checkCond() for { select { case <-timer.C: return Fail(t, "Condition never satisfied", msgAndArgs...) case <-tickC: tickC = nil go checkCond() case v := <-ch: if v { return true } tickC = ticker.C } } } // CollectT implements the TestingT interface and collects all errors. type CollectT struct { // A slice of errors. Non-nil slice denotes a failure. // If it's non-nil but len(c.errors) == 0, this is also a failure // obtained by direct c.FailNow() call. errors []error } // Helper is like [testing.T.Helper] but does nothing. func (CollectT) Helper() {} // Errorf collects the error. func (c *CollectT) Errorf(format string, args ...interface{}) { c.errors = append(c.errors, fmt.Errorf(format, args...)) } // FailNow stops execution by calling runtime.Goexit. func (c *CollectT) FailNow() { c.fail() runtime.Goexit() } // Deprecated: That was a method for internal usage that should not have been published. Now just panics. func (*CollectT) Reset() { panic("Reset() is deprecated") } // Deprecated: That was a method for internal usage that should not have been published. Now just panics. func (*CollectT) Copy(TestingT) { panic("Copy() is deprecated") } func (c *CollectT) fail() { if !c.failed() { c.errors = []error{} // Make it non-nil to mark a failure. } } func (c *CollectT) failed() bool { return c.errors != nil } // EventuallyWithT asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // assert.EventuallyWithT(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } var lastFinishedTickErrs []error ch := make(chan *CollectT, 1) checkCond := func() { collect := new(CollectT) defer func() { ch <- collect }() condition(collect) } timer := time.NewTimer(waitFor) defer timer.Stop() ticker := time.NewTicker(tick) defer ticker.Stop() var tickC <-chan time.Time // Check the condition once first on the initial call. go checkCond() for { select { case <-timer.C: for _, err := range lastFinishedTickErrs { t.Errorf("%v", err) } return Fail(t, "Condition never satisfied", msgAndArgs...) case <-tickC: tickC = nil go checkCond() case collect := <-ch: if !collect.failed() { return true } // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. lastFinishedTickErrs = collect.errors tickC = ticker.C } } } // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } ch := make(chan bool, 1) checkCond := func() { ch <- condition() } timer := time.NewTimer(waitFor) defer timer.Stop() ticker := time.NewTicker(tick) defer ticker.Stop() var tickC <-chan time.Time // Check the condition once first on the initial call. go checkCond() for { select { case <-timer.C: return true case <-tickC: tickC = nil go checkCond() case v := <-ch: if v { return Fail(t, "Condition satisfied", msgAndArgs...) } tickC = ticker.C } } } // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if errors.Is(err, target) { return true } var expectedText string if target != nil { expectedText = target.Error() if err == nil { return Fail(t, fmt.Sprintf("Expected error with %q in chain but got nil.", expectedText), msgAndArgs...) } } chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ "expected: %s\n"+ "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !errors.Is(err, target) { return true } var expectedText string if target != nil { expectedText = target.Error() } chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ "found: %s\n"+ "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if errors.As(err, target) { return true } expectedType := reflect.TypeOf(target).Elem().String() if err == nil { return Fail(t, fmt.Sprintf("An error is expected but got nil.\n"+ "expected: %s", expectedType), msgAndArgs...) } chain := buildErrorChainString(err, true) return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ "expected: %s\n"+ "in chain: %s", expectedType, truncatingFormat("%s", chain), ), msgAndArgs...) } // NotErrorAs asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !errors.As(err, target) { return true } chain := buildErrorChainString(err, true) return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ "found: %s\n"+ "in chain: %s", reflect.TypeOf(target).Elem().String(), truncatingFormat("%s", chain), ), msgAndArgs...) } func unwrapAll(err error) (errs []error) { errs = append(errs, err) switch x := err.(type) { case interface{ Unwrap() error }: err = x.Unwrap() if err == nil { return } errs = append(errs, unwrapAll(err)...) case interface{ Unwrap() []error }: for _, err := range x.Unwrap() { errs = append(errs, unwrapAll(err)...) } } return } func buildErrorChainString(err error, withType bool) string { if err == nil { return "" } var chain string errs := unwrapAll(err) for i := range errs { if i != 0 { chain += "\n\t" } chain += fmt.Sprintf("%q", errs[i].Error()) if withType { chain += fmt.Sprintf(" (%T)", errs[i]) } } return chain } ================================================ FILE: assert/assertions_test.go ================================================ package assert import ( "bufio" "bytes" "encoding/json" "errors" "fmt" "io" "math" "os" "path/filepath" "reflect" "regexp" "runtime" "strings" "testing" "time" ) var ( i interface{} zeros = []interface{}{ false, byte(0), complex64(0), complex128(0), float32(0), float64(0), int(0), int8(0), int16(0), int32(0), int64(0), rune(0), uint(0), uint8(0), uint16(0), uint32(0), uint64(0), uintptr(0), "", [0]interface{}{}, []interface{}(nil), struct{ x int }{}, (*interface{})(nil), (func())(nil), nil, interface{}(nil), map[interface{}]interface{}(nil), (chan interface{})(nil), (<-chan interface{})(nil), (chan<- interface{})(nil), } nonZeros = []interface{}{ true, byte(1), complex64(1), complex128(1), float32(1), float64(1), int(1), int8(1), int16(1), int32(1), int64(1), rune(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1), uintptr(1), "s", [1]interface{}{1}, []interface{}{}, struct{ x int }{1}, (&i), (func() {}), interface{}(1), map[interface{}]interface{}{}, (make(chan interface{})), (<-chan interface{})(make(chan interface{})), (chan<- interface{})(make(chan interface{})), } ) // AssertionTesterInterface defines an interface to be used for testing assertion methods type AssertionTesterInterface interface { TestMethod() } // AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface type AssertionTesterConformingObject struct{} func (a *AssertionTesterConformingObject) TestMethod() { } // AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface type AssertionTesterNonConformingObject struct{} func TestObjectsAreEqual(t *testing.T) { t.Parallel() cases := []struct { expected interface{} actual interface{} result bool }{ // cases that are expected to be equal {"Hello World", "Hello World", true}, {123, 123, true}, {123.5, 123.5, true}, {[]byte("Hello World"), []byte("Hello World"), true}, {nil, nil, true}, // cases that are expected not to be equal {map[int]int{5: 10}, map[int]int{10: 20}, false}, {'x', "x", false}, {"x", 'x', false}, {0, 0.1, false}, {0.1, 0, false}, {time.Now, time.Now, false}, {func() {}, func() {}, false}, {uint32(10), int32(10), false}, } for _, c := range cases { t.Run(fmt.Sprintf("ObjectsAreEqual(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := ObjectsAreEqual(c.expected, c.actual) if res != c.result { t.Errorf("ObjectsAreEqual(%#v, %#v) should return %#v", c.expected, c.actual, c.result) } }) } } func TestObjectsAreEqualValues(t *testing.T) { t.Parallel() now := time.Now() cases := []struct { expected interface{} actual interface{} result bool }{ {uint32(10), int32(10), true}, {0, nil, false}, {nil, 0, false}, {now, now.In(time.Local), false}, // should not be time zone independent {int(270), int8(14), false}, // should handle overflow/underflow {int8(14), int(270), false}, {[]int{270, 270}, []int8{14, 14}, false}, {complex128(1e+100 + 1e+100i), complex64(complex(math.Inf(0), math.Inf(0))), false}, {complex64(complex(math.Inf(0), math.Inf(0))), complex128(1e+100 + 1e+100i), false}, {complex128(1e+100 + 1e+100i), 270, false}, {270, complex128(1e+100 + 1e+100i), false}, {complex128(1e+100 + 1e+100i), 3.14, false}, {3.14, complex128(1e+100 + 1e+100i), false}, {complex128(1e+10 + 1e+10i), complex64(1e+10 + 1e+10i), true}, {complex64(1e+10 + 1e+10i), complex128(1e+10 + 1e+10i), true}, } for _, c := range cases { t.Run(fmt.Sprintf("ObjectsAreEqualValues(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := ObjectsAreEqualValues(c.expected, c.actual) if res != c.result { t.Errorf("ObjectsAreEqualValues(%#v, %#v) should return %#v", c.expected, c.actual, c.result) } }) } } type Nested struct { Exported interface{} notExported interface{} } type S struct { Exported1 interface{} Exported2 Nested notExported1 interface{} notExported2 Nested } type S2 struct { foo interface{} } type S3 struct { Exported1 *Nested Exported2 *Nested } type S4 struct { Exported1 []*Nested } type S5 struct { Exported Nested } type S6 struct { Exported string unexported string } func TestObjectsExportedFieldsAreEqual(t *testing.T) { t.Parallel() intValue := 1 cases := []struct { expected interface{} actual interface{} result bool }{ {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{5, 6}}, true}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, "a", Nested{5, 6}}, true}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{5, "a"}}, true}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{"a", "a"}}, true}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, "a"}, 4, Nested{5, 6}}, true}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{"a", Nested{2, 3}, 4, Nested{5, 6}}, false}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{"a", 3}, 4, Nested{5, 6}}, false}, {S{1, Nested{2, 3}, 4, Nested{5, 6}}, S2{1}, false}, {1, S{1, Nested{2, 3}, 4, Nested{5, 6}}, false}, {S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, 2}, &Nested{3, 4}}, true}, {S3{nil, &Nested{3, 4}}, S3{nil, &Nested{3, 4}}, true}, {S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, 2}, &Nested{3, "b"}}, true}, {S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, "a"}, &Nested{3, "b"}}, true}, {S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{"a", 2}, &Nested{3, 4}}, false}, {S3{&Nested{1, 2}, &Nested{3, 4}}, S3{}, false}, {S3{}, S3{}, true}, {S4{[]*Nested{{1, 2}}}, S4{[]*Nested{{1, 2}}}, true}, {S4{[]*Nested{{1, 2}}}, S4{[]*Nested{{1, 3}}}, true}, {S4{[]*Nested{{1, 2}, {3, 4}}}, S4{[]*Nested{{1, "a"}, {3, "b"}}}, true}, {S4{[]*Nested{{1, 2}, {3, 4}}}, S4{[]*Nested{{1, "a"}, {2, "b"}}}, false}, {Nested{&intValue, 2}, Nested{&intValue, 2}, true}, {Nested{&Nested{1, 2}, 3}, Nested{&Nested{1, "b"}, 3}, true}, {Nested{&Nested{1, 2}, 3}, Nested{nil, 3}, false}, { Nested{map[interface{}]*Nested{nil: nil}, 2}, Nested{map[interface{}]*Nested{nil: nil}, 2}, true, }, { Nested{map[interface{}]*Nested{"a": nil}, 2}, Nested{map[interface{}]*Nested{"a": nil}, 2}, true, }, { Nested{map[interface{}]*Nested{"a": nil}, 2}, Nested{map[interface{}]*Nested{"a": {1, 2}}, 2}, false, }, { Nested{map[interface{}]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, Nested{map[interface{}]Nested{"a": {1, 5}, "b": {3, 7}}, 2}, true, }, { Nested{map[interface{}]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, Nested{map[interface{}]Nested{"a": {2, 2}, "b": {3, 4}}, 2}, false, }, } for _, c := range cases { t.Run(fmt.Sprintf("ObjectsExportedFieldsAreEqual(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := ObjectsExportedFieldsAreEqual(c.expected, c.actual) if res != c.result { t.Errorf("ObjectsExportedFieldsAreEqual(%#v, %#v) should return %#v", c.expected, c.actual, c.result) } }) } } func TestCopyExportedFields(t *testing.T) { t.Parallel() intValue := 1 cases := []struct { input interface{} expected interface{} }{ { input: Nested{"a", "b"}, expected: Nested{"a", nil}, }, { input: Nested{&intValue, 2}, expected: Nested{&intValue, nil}, }, { input: Nested{nil, 3}, expected: Nested{nil, nil}, }, { input: S{1, Nested{2, 3}, 4, Nested{5, 6}}, expected: S{1, Nested{2, nil}, nil, Nested{}}, }, { input: S3{}, expected: S3{}, }, { input: S3{&Nested{1, 2}, &Nested{3, 4}}, expected: S3{&Nested{1, nil}, &Nested{3, nil}}, }, { input: S3{Exported1: &Nested{"a", "b"}}, expected: S3{Exported1: &Nested{"a", nil}}, }, { input: S4{[]*Nested{ nil, {1, 2}, }}, expected: S4{[]*Nested{ nil, {1, nil}, }}, }, { input: S4{ []*Nested{ {1, 2}, }, }, expected: S4{ []*Nested{ {1, nil}, }, }, }, { input: S4{[]*Nested{ {1, 2}, {3, 4}, }}, expected: S4{[]*Nested{ {1, nil}, {3, nil}, }}, }, { input: S5{Exported: Nested{"a", "b"}}, expected: S5{Exported: Nested{"a", nil}}, }, { input: S6{"a", "b"}, expected: S6{"a", ""}, }, } for _, c := range cases { t.Run("", func(t *testing.T) { output := copyExportedFields(c.input) if !ObjectsAreEqualValues(c.expected, output) { t.Errorf("%#v, %#v should be equal", c.expected, output) } }) } } func TestEqualExportedValues(t *testing.T) { t.Parallel() cases := []struct { value1 interface{} value2 interface{} expectedEqual bool expectedFail string }{ { value1: S{1, Nested{2, 3}, 4, Nested{5, 6}}, value2: S{1, Nested{2, nil}, nil, Nested{}}, expectedEqual: true, }, { value1: S{1, Nested{2, 3}, 4, Nested{5, 6}}, value2: S{1, Nested{1, nil}, nil, Nested{}}, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -3,3 +3,3 @@ Exported2: (assert.Nested) { - Exported: (int) 2, + Exported: (int) 1, notExported: (interface {}) `, }, { value1: S3{&Nested{1, 2}, &Nested{3, 4}}, value2: S3{&Nested{"a", 2}, &Nested{3, 4}}, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -2,3 +2,3 @@ Exported1: (*assert.Nested)({ - Exported: (int) 1, + Exported: (string) (len=1) "a", notExported: (interface {}) `, }, { value1: S4{[]*Nested{ {1, 2}, {3, 4}, }}, value2: S4{[]*Nested{ {1, "a"}, {2, "b"}, }}, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -7,3 +7,3 @@ (*assert.Nested)({ - Exported: (int) 3, + Exported: (int) 2, notExported: (interface {}) `, }, { value1: S{[2]int{1, 2}, Nested{2, 3}, 4, Nested{5, 6}}, value2: S{[2]int{1, 2}, Nested{2, nil}, nil, Nested{}}, expectedEqual: true, }, { value1: &S{1, Nested{2, 3}, 4, Nested{5, 6}}, value2: &S{1, Nested{2, nil}, nil, Nested{}}, expectedEqual: true, }, { value1: &S{1, Nested{2, 3}, 4, Nested{5, 6}}, value2: &S{1, Nested{1, nil}, nil, Nested{}}, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -3,3 +3,3 @@ Exported2: (assert.Nested) { - Exported: (int) 2, + Exported: (int) 1, notExported: (interface {}) `, }, { value1: []int{1, 2}, value2: []int{1, 2}, expectedEqual: true, }, { value1: []int{1, 2}, value2: []int{1, 3}, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -2,3 +2,3 @@ (int) 1, - (int) 2 + (int) 3 }`, }, { value1: []*Nested{ {1, 2}, {3, 4}, }, value2: []*Nested{ {1, "a"}, {3, "b"}, }, expectedEqual: true, }, { value1: []*Nested{ {1, 2}, {3, 4}, }, value2: []*Nested{ {1, "a"}, {2, "b"}, }, expectedEqual: false, expectedFail: ` Diff: --- Expected +++ Actual @@ -6,3 +6,3 @@ (*assert.Nested)({ - Exported: (int) 3, + Exported: (int) 2, notExported: (interface {}) `, }, } for _, c := range cases { t.Run("", func(t *testing.T) { mockT := new(mockTestingT) actual := EqualExportedValues(mockT, c.value1, c.value2) if actual != c.expectedEqual { t.Errorf("Expected EqualExportedValues to be %t, but was %t", c.expectedEqual, actual) } actualFail := mockT.errorString() if !strings.Contains(actualFail, c.expectedFail) { t.Errorf("Contains failure should include %q but was %q", c.expectedFail, actualFail) } }) } } func TestImplements(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface") } if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") } if Implements(mockT, (*AssertionTesterInterface)(nil), nil) { t.Error("Implements method should return false: nil does not implement AssertionTesterInterface") } } func TestNotImplements(t *testing.T) { t.Parallel() mockT := new(testing.T) if !NotImplements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { t.Error("NotImplements method should return true: AssertionTesterNonConformingObject does not implement AssertionTesterInterface") } if NotImplements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { t.Error("NotImplements method should return false: AssertionTesterConformingObject implements AssertionTesterInterface") } if NotImplements(mockT, (*AssertionTesterInterface)(nil), nil) { t.Error("NotImplements method should return false: nil can't be checked to be implementing AssertionTesterInterface or not") } } func TestIsType(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") } if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") } } func TestNotIsType(t *testing.T) { t.Parallel() mockT := new(testing.T) if !IsNotType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { t.Error("NotIsType should return true: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") } if IsNotType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { t.Error("NotIsType should return false: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") } } func TestEqual(t *testing.T) { t.Parallel() type myType string mockT := new(testing.T) var m map[string]interface{} cases := []struct { expected interface{} actual interface{} result bool remark string }{ {"Hello World", "Hello World", true, ""}, {123, 123, true, ""}, {123.5, 123.5, true, ""}, {[]byte("Hello World"), []byte("Hello World"), true, ""}, {nil, nil, true, ""}, {int32(123), int32(123), true, ""}, {uint64(123), uint64(123), true, ""}, {myType("1"), myType("1"), true, ""}, {&struct{}{}, &struct{}{}, true, "pointer equality is based on equality of underlying value"}, // Not expected to be equal {m["bar"], "something", false, ""}, {myType("1"), myType("2"), false, ""}, // A case that might be confusing, especially with numeric literals {10, uint(10), false, ""}, } for _, c := range cases { t.Run(fmt.Sprintf("Equal(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := Equal(mockT, c.expected, c.actual) if res != c.result { t.Errorf("Equal(%#v, %#v) should return %#v: %s", c.expected, c.actual, c.result, c.remark) } }) } } func ptr(i int) *int { return &i } func TestSame(t *testing.T) { t.Parallel() mockT := new(mockTestingT) if Same(mockT, ptr(1), ptr(1)) { t.Error("Same should return false") } if Same(mockT, 1, 1) { t.Error("Same should return false") } p := ptr(2) if Same(mockT, p, *p) { t.Error("Same should return false") } if !Same(mockT, p, p) { t.Error("Same should return true") } t.Run("same object, different type", func(t *testing.T) { type s struct { i int } type sPtr *s ps := &s{1} dps := sPtr(ps) if Same(mockT, dps, ps) { t.Error("Same should return false") } expPat := `expected: &assert.s\{i:1\} \(assert.sPtr\)\((0x[a-f0-9]+)\)\s*\n` + `\s+actual : &assert.s\{i:1\} \(\*assert.s\)\((0x[a-f0-9]+)\)` Regexp(t, regexp.MustCompile(expPat), mockT.errorString()) }) } func TestNotSame(t *testing.T) { t.Parallel() mockT := new(testing.T) if !NotSame(mockT, ptr(1), ptr(1)) { t.Error("NotSame should return true; different pointers") } if !NotSame(mockT, 1, 1) { t.Error("NotSame should return true; constant inputs") } p := ptr(2) if !NotSame(mockT, p, *p) { t.Error("NotSame should return true; mixed-type inputs") } if NotSame(mockT, p, p) { t.Error("NotSame should return false") } } func Test_samePointers(t *testing.T) { t.Parallel() p := ptr(2) type args struct { first interface{} second interface{} } tests := []struct { name string args args same BoolAssertionFunc ok BoolAssertionFunc }{ { name: "1 != 2", args: args{first: 1, second: 2}, same: False, ok: False, }, { name: "1 != 1 (not same ptr)", args: args{first: 1, second: 1}, same: False, ok: False, }, { name: "ptr(1) == ptr(1)", args: args{first: p, second: p}, same: True, ok: True, }, { name: "int(1) != float32(1)", args: args{first: int(1), second: float32(1)}, same: False, ok: False, }, { name: "array != slice", args: args{first: [2]int{1, 2}, second: []int{1, 2}}, same: False, ok: False, }, { name: "non-pointer vs pointer (1 != ptr(2))", args: args{first: 1, second: p}, same: False, ok: False, }, { name: "pointer vs non-pointer (ptr(2) != 1)", args: args{first: p, second: 1}, same: False, ok: False, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { same, ok := samePointers(tt.args.first, tt.args.second) tt.same(t, same) tt.ok(t, ok) }) } } // bufferT implements TestingT. Its implementation of Errorf writes the output that would be produced by // testing.T.Errorf to an internal bytes.Buffer. type bufferT struct { buf bytes.Buffer } // Helper is like [testing.T.Helper] but does nothing. func (bufferT) Helper() {} func (t *bufferT) Errorf(format string, args ...interface{}) { // implementation of decorate is copied from testing.T decorate := func(s string) string { _, file, line, ok := runtime.Caller(3) // decorate + log + public function. if ok { // Truncate file name at last file name separator. if index := strings.LastIndex(file, "/"); index >= 0 { file = file[index+1:] } else if index = strings.LastIndex(file, "\\"); index >= 0 { file = file[index+1:] } } else { file = "???" line = 1 } buf := new(bytes.Buffer) // Every line is indented at least one tab. buf.WriteByte('\t') fmt.Fprintf(buf, "%s:%d: ", file, line) lines := strings.Split(s, "\n") if l := len(lines); l > 1 && lines[l-1] == "" { lines = lines[:l-1] } for i, line := range lines { if i > 0 { // Second and subsequent lines are indented an extra tab. buf.WriteString("\n\t\t") } buf.WriteString(line) } buf.WriteByte('\n') return buf.String() } t.buf.WriteString(decorate(fmt.Sprintf(format, args...))) } func TestStringEqual(t *testing.T) { t.Parallel() for i, currCase := range []struct { equalWant string equalGot string msgAndArgs []interface{} want string }{ {equalWant: "hi, \nmy name is", equalGot: "what,\nmy name is", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"hi, \\\\nmy name is\"\n\\s+actual\\s+: \"what,\\\\nmy name is\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1,2 \\+1,2 @@\n\\s+-hi, \n\\s+\\+what,\n\\s+my name is"}, } { mockT := &bufferT{} Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...) Regexp(t, regexp.MustCompile(currCase.want), mockT.buf.String(), "Case %d", i) } } func TestEqualFormatting(t *testing.T) { t.Parallel() for i, currCase := range []struct { equalWant string equalGot string msgAndArgs []interface{} want string }{ {equalWant: "want", equalGot: "got", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n"}, {equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{"hello, %v!", "world"}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+hello, world!\n"}, {equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{123}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+123\n"}, {equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{struct{ a string }{"hello"}}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+{a:hello}\n"}, } { mockT := &bufferT{} Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...) Regexp(t, regexp.MustCompile(currCase.want), mockT.buf.String(), "Case %d", i) } } func TestFormatUnequalValues(t *testing.T) { t.Parallel() expected, actual := formatUnequalValues("foo", "bar") Equal(t, `"foo"`, expected, "value should not include type") Equal(t, `"bar"`, actual, "value should not include type") expected, actual = formatUnequalValues(123, 123) Equal(t, `123`, expected, "value should not include type") Equal(t, `123`, actual, "value should not include type") expected, actual = formatUnequalValues(int64(123), int32(123)) Equal(t, `int64(123)`, expected, "value should include type") Equal(t, `int32(123)`, actual, "value should include type") expected, actual = formatUnequalValues(int64(123), nil) Equal(t, `int64(123)`, expected, "value should include type") Equal(t, `()`, actual, "value should include type") type testStructType struct { Val string } expected, actual = formatUnequalValues(&testStructType{Val: "test"}, &testStructType{Val: "test"}) Equal(t, `&assert.testStructType{Val:"test"}`, expected, "value should not include type annotation") Equal(t, `&assert.testStructType{Val:"test"}`, actual, "value should not include type annotation") } func TestNotNil(t *testing.T) { t.Parallel() mockT := new(testing.T) if !NotNil(mockT, new(AssertionTesterConformingObject)) { t.Error("NotNil should return true: object is not nil") } if NotNil(mockT, nil) { t.Error("NotNil should return false: object is nil") } if NotNil(mockT, (*struct{})(nil)) { t.Error("NotNil should return false: object is (*struct{})(nil)") } } func TestNil(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Nil(mockT, nil) { t.Error("Nil should return true: object is nil") } if !Nil(mockT, (*struct{})(nil)) { t.Error("Nil should return true: object is (*struct{})(nil)") } if Nil(mockT, new(AssertionTesterConformingObject)) { t.Error("Nil should return false: object is not nil") } } func TestTrue(t *testing.T) { t.Parallel() mockT := new(testing.T) if !True(mockT, true) { t.Error("True should return true") } if True(mockT, false) { t.Error("True should return false") } } func TestFalse(t *testing.T) { t.Parallel() mockT := new(testing.T) if !False(mockT, false) { t.Error("False should return true") } if False(mockT, true) { t.Error("False should return false") } } func TestExactly(t *testing.T) { t.Parallel() mockT := new(testing.T) a := float32(1) b := float64(1) c := float32(1) d := float32(2) cases := []struct { expected interface{} actual interface{} result bool }{ {a, b, false}, {a, d, false}, {a, c, true}, {nil, a, false}, {a, nil, false}, } for _, c := range cases { t.Run(fmt.Sprintf("Exactly(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := Exactly(mockT, c.expected, c.actual) if res != c.result { t.Errorf("Exactly(%#v, %#v) should return %#v", c.expected, c.actual, c.result) } }) } } func TestNotEqual(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { expected interface{} actual interface{} result bool }{ // cases that are expected not to match {"Hello World", "Hello World!", true}, {123, 1234, true}, {123.5, 123.55, true}, {[]byte("Hello World"), []byte("Hello World!"), true}, {nil, new(AssertionTesterConformingObject), true}, // cases that are expected to match {nil, nil, false}, {"Hello World", "Hello World", false}, {123, 123, false}, {123.5, 123.5, false}, {[]byte("Hello World"), []byte("Hello World"), false}, {new(AssertionTesterConformingObject), new(AssertionTesterConformingObject), false}, {&struct{}{}, &struct{}{}, false}, {func() int { return 23 }, func() int { return 24 }, false}, // A case that might be confusing, especially with numeric literals {int(10), uint(10), true}, } for _, c := range cases { t.Run(fmt.Sprintf("NotEqual(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := NotEqual(mockT, c.expected, c.actual) if res != c.result { t.Errorf("NotEqual(%#v, %#v) should return %#v", c.expected, c.actual, c.result) } }) } } func TestEqualValuesAndNotEqualValues(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { expected interface{} actual interface{} notEqualResult bool // result for NotEqualValues }{ // cases that are expected not to match {"Hello World", "Hello World!", true}, {123, 1234, true}, {123.5, 123.55, true}, {[]byte("Hello World"), []byte("Hello World!"), true}, {nil, new(AssertionTesterConformingObject), true}, // cases that are expected to match {nil, nil, false}, {"Hello World", "Hello World", false}, {123, 123, false}, {123.5, 123.5, false}, {[]byte("Hello World"), []byte("Hello World"), false}, {new(AssertionTesterConformingObject), new(AssertionTesterConformingObject), false}, {&struct{}{}, &struct{}{}, false}, // Different behavior from NotEqual() {func() int { return 23 }, func() int { return 24 }, true}, {int(10), int(11), true}, {int(10), uint(10), false}, {struct{}{}, struct{}{}, false}, } for _, c := range cases { // Test NotEqualValues t.Run(fmt.Sprintf("NotEqualValues(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := NotEqualValues(mockT, c.expected, c.actual) if res != c.notEqualResult { t.Errorf("NotEqualValues(%#v, %#v) should return %#v", c.expected, c.actual, c.notEqualResult) } }) // Test EqualValues (inverse of NotEqualValues) t.Run(fmt.Sprintf("EqualValues(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { expectedEqualResult := !c.notEqualResult // EqualValues should return opposite of NotEqualValues res := EqualValues(mockT, c.expected, c.actual) if res != expectedEqualResult { t.Errorf("EqualValues(%#v, %#v) should return %#v", c.expected, c.actual, expectedEqualResult) } }) } } func TestContainsNotContains(t *testing.T) { t.Parallel() type A struct { Name, Value string } list := []string{"Foo", "Bar"} complexList := []*A{ {"b", "c"}, {"d", "e"}, {"g", "h"}, {"j", "k"}, } simpleMap := map[interface{}]interface{}{"Foo": "Bar"} var zeroMap map[interface{}]interface{} cases := []struct { expected interface{} actual interface{} result bool }{ {"Hello World", "Hello", true}, {"Hello World", "Salut", false}, {list, "Bar", true}, {list, "Salut", false}, {complexList, &A{"g", "h"}, true}, {complexList, &A{"g", "e"}, false}, {simpleMap, "Foo", true}, {simpleMap, "Bar", false}, {zeroMap, "Bar", false}, } for _, c := range cases { t.Run(fmt.Sprintf("Contains(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { mockT := new(testing.T) res := Contains(mockT, c.expected, c.actual) if res != c.result { if res { t.Errorf("Contains(%#v, %#v) should return true:\n\t%#v contains %#v", c.expected, c.actual, c.expected, c.actual) } else { t.Errorf("Contains(%#v, %#v) should return false:\n\t%#v does not contain %#v", c.expected, c.actual, c.expected, c.actual) } } }) } for _, c := range cases { t.Run(fmt.Sprintf("NotContains(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { mockT := new(testing.T) res := NotContains(mockT, c.expected, c.actual) // NotContains should be inverse of Contains. If it's not, something is wrong if res == Contains(mockT, c.expected, c.actual) { if res { t.Errorf("NotContains(%#v, %#v) should return true:\n\t%#v does not contains %#v", c.expected, c.actual, c.expected, c.actual) } else { t.Errorf("NotContains(%#v, %#v) should return false:\n\t%#v contains %#v", c.expected, c.actual, c.expected, c.actual) } } }) } } func TestContainsNotContainsFailMessage(t *testing.T) { t.Parallel() mockT := new(mockTestingT) type nonContainer struct { Value string } cases := []struct { assertion func(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool container interface{} instance interface{} expected string }{ { assertion: Contains, container: "Hello World", instance: errors.New("Hello"), expected: "\"Hello World\" does not contain &errors.errorString{s:\"Hello\"}", }, { assertion: Contains, container: map[string]int{"one": 1}, instance: "two", expected: "map[string]int{\"one\":1} does not contain \"two\"\n", }, { assertion: NotContains, container: map[string]int{"one": 1}, instance: "one", expected: "map[string]int{\"one\":1} should not contain \"one\"", }, { assertion: Contains, container: nonContainer{Value: "Hello"}, instance: "Hello", expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n", }, { assertion: NotContains, container: nonContainer{Value: "Hello"}, instance: "Hello", expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n", }, } for _, c := range cases { name := filepath.Base(runtime.FuncForPC(reflect.ValueOf(c.assertion).Pointer()).Name()) t.Run(fmt.Sprintf("%v(%T, %T)", name, c.container, c.instance), func(t *testing.T) { c.assertion(mockT, c.container, c.instance) actualFail := mockT.errorString() if !strings.Contains(actualFail, c.expected) { t.Errorf("Contains failure should include %q but was %q", c.expected, actualFail) } }) } } func TestContainsNotContainsOnNilValue(t *testing.T) { t.Parallel() mockT := new(mockTestingT) Contains(mockT, nil, "key") expectedFail := " could not be applied builtin len()" actualFail := mockT.errorString() if !strings.Contains(actualFail, expectedFail) { t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail) } NotContains(mockT, nil, "key") if !strings.Contains(actualFail, expectedFail) { t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail) } } func TestSubsetNotSubset(t *testing.T) { t.Parallel() cases := []struct { list interface{} subset interface{} result bool message string }{ // cases that are expected to contain {[]int{1, 2, 3}, nil, true, `nil is the empty set which is a subset of every set`}, {[]int{1, 2, 3}, []int{}, true, `[] is a subset of ['\x01' '\x02' '\x03']`}, {[]int{1, 2, 3}, []int{1, 2}, true, `['\x01' '\x02'] is a subset of ['\x01' '\x02' '\x03']`}, {[]int{1, 2, 3}, []int{1, 2, 3}, true, `['\x01' '\x02' '\x03'] is a subset of ['\x01' '\x02' '\x03']`}, {[]string{"hello", "world"}, []string{"hello"}, true, `["hello"] is a subset of ["hello" "world"]`}, {map[string]string{ "a": "x", "c": "z", "b": "y", }, map[string]string{ "a": "x", "b": "y", }, true, `map["a":"x" "b":"y"] is a subset of map["a":"x" "b":"y" "c":"z"]`}, {[]string{"a", "b", "c"}, map[string]int{"a": 1, "c": 3}, true, `map["a":'\x01' "c":'\x03'] is a subset of ["a" "b" "c"]`}, // cases that are expected not to contain {[]string{"hello", "world"}, []string{"hello", "testify"}, false, `[]string{"hello", "world"} does not contain "testify"`}, {[]int{1, 2, 3}, []int{4, 5}, false, `[]int{1, 2, 3} does not contain 4`}, {[]int{1, 2, 3}, []int{1, 5}, false, `[]int{1, 2, 3} does not contain 5`}, {map[string]string{ "a": "x", "c": "z", "b": "y", }, map[string]string{ "a": "x", "b": "z", }, false, `map[string]string{"a":"x", "b":"y", "c":"z"} does not contain map[string]string{"a":"x", "b":"z"}`}, {map[string]string{ "a": "x", "b": "y", }, map[string]string{ "a": "x", "b": "y", "c": "z", }, false, `map[string]string{"a":"x", "b":"y"} does not contain map[string]string{"a":"x", "b":"y", "c":"z"}`}, {[]string{"a", "b", "c"}, map[string]int{"c": 3, "d": 4}, false, `[]string{"a", "b", "c"} does not contain "d"`}, } for _, c := range cases { t.Run("SubSet: "+c.message, func(t *testing.T) { mockT := new(mockTestingT) res := Subset(mockT, c.list, c.subset) if res != c.result { t.Errorf("Subset should return %t: %s", c.result, c.message) } if !c.result { expectedFail := c.message actualFail := mockT.errorString() if !strings.Contains(actualFail, expectedFail) { t.Log(actualFail) t.Errorf("Subset failure should contain %q but was %q", expectedFail, actualFail) } } }) } for _, c := range cases { t.Run("NotSubSet: "+c.message, func(t *testing.T) { mockT := new(mockTestingT) res := NotSubset(mockT, c.list, c.subset) // NotSubset should match the inverse of Subset. If it doesn't, something is wrong if res == Subset(mockT, c.list, c.subset) { t.Errorf("NotSubset should return %t: %s", !c.result, c.message) } if c.result { expectedFail := c.message actualFail := mockT.errorString() if !strings.Contains(actualFail, expectedFail) { t.Log(actualFail) t.Errorf("NotSubset failure should contain %q but was %q", expectedFail, actualFail) } } }) } } func TestNotSubsetNil(t *testing.T) { t.Parallel() mockT := new(testing.T) NotSubset(mockT, []string{"foo"}, nil) if !mockT.Failed() { t.Error("NotSubset on nil set should have failed the test") } } func Test_containsElement(t *testing.T) { t.Parallel() list1 := []string{"Foo", "Bar"} list2 := []int{1, 2} simpleMap := map[interface{}]interface{}{"Foo": "Bar"} ok, found := containsElement("Hello World", "World") True(t, ok) True(t, found) ok, found = containsElement(list1, "Foo") True(t, ok) True(t, found) ok, found = containsElement(list1, "Bar") True(t, ok) True(t, found) ok, found = containsElement(list2, 1) True(t, ok) True(t, found) ok, found = containsElement(list2, 2) True(t, ok) True(t, found) ok, found = containsElement(list1, "Foo!") True(t, ok) False(t, found) ok, found = containsElement(list2, 3) True(t, ok) False(t, found) ok, found = containsElement(list2, "1") True(t, ok) False(t, found) ok, found = containsElement(simpleMap, "Foo") True(t, ok) True(t, found) ok, found = containsElement(simpleMap, "Bar") True(t, ok) False(t, found) ok, found = containsElement(1433, "1") False(t, ok) False(t, found) } func TestElementsMatch(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { expected interface{} actual interface{} result bool }{ // matching {nil, nil, true}, {nil, nil, true}, {[]int{}, []int{}, true}, {[]int{1}, []int{1}, true}, {[]int{1, 1}, []int{1, 1}, true}, {[]int{1, 2}, []int{1, 2}, true}, {[]int{1, 2}, []int{2, 1}, true}, {[2]int{1, 2}, [2]int{2, 1}, true}, {[]string{"hello", "world"}, []string{"world", "hello"}, true}, {[]string{"hello", "hello"}, []string{"hello", "hello"}, true}, {[]string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}, true}, {[3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}, true}, {[]int{}, nil, true}, // not matching {[]int{1}, []int{1, 1}, false}, {[]int{1, 2}, []int{2, 2}, false}, {[]string{"hello", "hello"}, []string{"hello"}, false}, } for _, c := range cases { t.Run(fmt.Sprintf("ElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := ElementsMatch(mockT, c.actual, c.expected) if res != c.result { t.Errorf("ElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result) } }) } } func TestDiffLists(t *testing.T) { t.Parallel() tests := []struct { name string listA interface{} listB interface{} extraA []interface{} extraB []interface{} }{ { name: "equal empty", listA: []string{}, listB: []string{}, extraA: nil, extraB: nil, }, { name: "equal same order", listA: []string{"hello", "world"}, listB: []string{"hello", "world"}, extraA: nil, extraB: nil, }, { name: "equal different order", listA: []string{"hello", "world"}, listB: []string{"world", "hello"}, extraA: nil, extraB: nil, }, { name: "extra A", listA: []string{"hello", "hello", "world"}, listB: []string{"hello", "world"}, extraA: []interface{}{"hello"}, extraB: nil, }, { name: "extra A twice", listA: []string{"hello", "hello", "hello", "world"}, listB: []string{"hello", "world"}, extraA: []interface{}{"hello", "hello"}, extraB: nil, }, { name: "extra B", listA: []string{"hello", "world"}, listB: []string{"hello", "hello", "world"}, extraA: nil, extraB: []interface{}{"hello"}, }, { name: "extra B twice", listA: []string{"hello", "world"}, listB: []string{"hello", "hello", "world", "hello"}, extraA: nil, extraB: []interface{}{"hello", "hello"}, }, { name: "integers 1", listA: []int{1, 2, 3, 4, 5}, listB: []int{5, 4, 3, 2, 1}, extraA: nil, extraB: nil, }, { name: "integers 2", listA: []int{1, 2, 1, 2, 1}, listB: []int{2, 1, 2, 1, 2}, extraA: []interface{}{1}, extraB: []interface{}{2}, }, } for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { actualExtraA, actualExtraB := diffLists(test.listA, test.listB) Equal(t, test.extraA, actualExtraA, "extra A does not match for listA=%v listB=%v", test.listA, test.listB) Equal(t, test.extraB, actualExtraB, "extra B does not match for listA=%v listB=%v", test.listA, test.listB) }) } } func TestNotElementsMatch(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { expected interface{} actual interface{} result bool }{ // not matching {[]int{1}, []int{}, true}, {[]int{}, []int{2}, true}, {[]int{1}, []int{2}, true}, {[]int{1}, []int{1, 1}, true}, {[]int{1, 2}, []int{3, 4}, true}, {[]int{3, 4}, []int{1, 2}, true}, {[]int{1, 1, 2, 3}, []int{1, 2, 3}, true}, {[]string{"hello"}, []string{"world"}, true}, {[]string{"hello", "hello"}, []string{"world", "world"}, true}, {[3]string{"hello", "hello", "hello"}, [3]string{"world", "world", "world"}, true}, // matching {nil, nil, false}, {[]int{}, nil, false}, {[]int{}, []int{}, false}, {[]int{1}, []int{1}, false}, {[]int{1, 1}, []int{1, 1}, false}, {[]int{1, 2}, []int{2, 1}, false}, {[2]int{1, 2}, [2]int{2, 1}, false}, {[]int{1, 1, 2}, []int{1, 2, 1}, false}, {[]string{"hello", "world"}, []string{"world", "hello"}, false}, {[]string{"hello", "hello"}, []string{"hello", "hello"}, false}, {[]string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}, false}, {[3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}, false}, } for _, c := range cases { t.Run(fmt.Sprintf("NotElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { res := NotElementsMatch(mockT, c.actual, c.expected) if res != c.result { t.Errorf("NotElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result) } }) } } func TestCondition(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Condition(mockT, func() bool { return true }, "Truth") { t.Error("Condition should return true") } if Condition(mockT, func() bool { return false }, "Lie") { t.Error("Condition should return false") } } func TestDidPanic(t *testing.T) { t.Parallel() const panicMsg = "Panic!" if funcDidPanic, msg, _ := didPanic(func() { panic(panicMsg) }); !funcDidPanic || msg != panicMsg { t.Error("didPanic should return true, panicMsg") } if funcDidPanic, msg, _ := didPanic(func() { panic(nil) }); !funcDidPanic || msg != nil { t.Error("didPanic should return true, nil") } if funcDidPanic, _, _ := didPanic(func() { }); funcDidPanic { t.Error("didPanic should return false") } } func TestPanics(t *testing.T) { t.Parallel() mockT := new(testing.T) if !Panics(mockT, func() { panic("Panic!") }) { t.Error("Panics should return true") } if Panics(mockT, func() { }) { t.Error("Panics should return false") } } func TestPanicsWithValue(t *testing.T) { t.Parallel() mockT := new(testing.T) if !PanicsWithValue(mockT, "Panic!", func() { panic("Panic!") }) { t.Error("PanicsWithValue should return true") } if !PanicsWithValue(mockT, nil, func() { panic(nil) }) { t.Error("PanicsWithValue should return true") } if PanicsWithValue(mockT, "Panic!", func() { }) { t.Error("PanicsWithValue should return false") } if PanicsWithValue(mockT, "at the disco", func() { panic("Panic!") }) { t.Error("PanicsWithValue should return false") } } func TestPanicsWithError(t *testing.T) { t.Parallel() mockT := new(captureTestingT) succeeded := PanicsWithError(mockT, "panic", func() { panic(errors.New("panic")) }) mockT.checkResultAndErrMsg(t, true, succeeded, "") succeeded = PanicsWithError(mockT, "Panic!", func() {}) Equal(t, false, succeeded, "PanicsWithError should return false") Contains(t, mockT.msg, "Panic value:\t") succeeded = PanicsWithError(mockT, "expected panic err msg", func() { panic(errors.New("actual panic err msg")) }) Equal(t, false, succeeded, "PanicsWithError should return false") Contains(t, mockT.msg, `Error message: "actual panic err msg"`) succeeded = PanicsWithError(mockT, "expected panic err msg", func() { panic(&PanicsWithErrorWrapper{"wrapped", errors.New("actual panic err msg")}) }) Equal(t, false, succeeded, "PanicsWithError should return false") Contains(t, mockT.msg, `Error message: "wrapped: actual panic err msg"`) succeeded = PanicsWithError(mockT, "expected panic msg", func() { panic("actual panic msg") }) Equal(t, false, succeeded, "PanicsWithError should return false") Contains(t, mockT.msg, `Panic value: "actual panic msg"`) NotContains(t, mockT.msg, "Error message:", "PanicsWithError should not report error message if not due an error") } type PanicsWithErrorWrapper struct { Prefix string Err error } func (e PanicsWithErrorWrapper) Error() string { return e.Prefix + ": " + e.Err.Error() } func TestNotPanics(t *testing.T) { t.Parallel() mockT := new(testing.T) if !NotPanics(mockT, func() { }) { t.Error("NotPanics should return true") } if NotPanics(mockT, func() { panic("Panic!") }) { t.Error("NotPanics should return false") } } func TestNoError(t *testing.T) { t.Parallel() mockT := new(testing.T) // start with a nil error var err error True(t, NoError(mockT, err), "NoError should return True for nil arg") // now set an error err = errors.New("some error") False(t, NoError(mockT, err), "NoError with error should return False") // returning an empty error interface err = func() error { var err *customError return err }() if err == nil { // err is not nil here! t.Errorf("Error should be nil due to empty interface: %s", err) } False(t, NoError(mockT, err), "NoError should fail with empty error interface") } type customError struct{} func (*customError) Error() string { return "fail" } func TestError(t *testing.T) { t.Parallel() mockT := new(testing.T) // start with a nil error var err error False(t, Error(mockT, err), "Error should return False for nil arg") // now set an error err = errors.New("some error") True(t, Error(mockT, err), "Error with error should return True") // go vet check True(t, Errorf(mockT, err, "example with %s", "formatted message"), "Errorf with error should return True") // returning an empty error interface err = func() error { var err *customError return err }() if err == nil { // err is not nil here! t.Errorf("Error should be nil due to empty interface: %s", err) } True(t, Error(mockT, err), "Error should pass with empty error interface") } func TestEqualError(t *testing.T) { t.Parallel() mockT := new(testing.T) // start with a nil error var err error False(t, EqualError(mockT, err, ""), "EqualError should return false for nil arg") // now set an error err = errors.New("some error") False(t, EqualError(mockT, err, "Not some error"), "EqualError should return false for different error string") True(t, EqualError(mockT, err, "some error"), "EqualError should return true") } func TestErrorContains(t *testing.T) { t.Parallel() mockT := new(testing.T) // start with a nil error var err error False(t, ErrorContains(mockT, err, ""), "ErrorContains should return false for nil arg") // now set an error err = errors.New("some error: another error") False(t, ErrorContains(mockT, err, "bad error"), "ErrorContains should return false for different error string") True(t, ErrorContains(mockT, err, "some error"), "ErrorContains should return true") True(t, ErrorContains(mockT, err, "another error"), "ErrorContains should return true") } func Test_isEmpty(t *testing.T) { t.Parallel() chWithValue := make(chan struct{}, 1) chWithValue <- struct{}{} True(t, isEmpty("")) True(t, isEmpty(nil)) True(t, isEmpty(error(nil))) True(t, isEmpty((*int)(nil))) True(t, isEmpty((*string)(nil))) True(t, isEmpty(new(string))) True(t, isEmpty([]string{})) True(t, isEmpty([]string(nil))) True(t, isEmpty([]byte(nil))) True(t, isEmpty([]byte{})) True(t, isEmpty([]byte(""))) True(t, isEmpty([]bool(nil))) True(t, isEmpty([]bool{})) True(t, isEmpty([]interface{}(nil))) True(t, isEmpty([]interface{}{})) True(t, isEmpty(struct{}{})) True(t, isEmpty(&struct{}{})) True(t, isEmpty(struct{ A int }{A: 0})) True(t, isEmpty(struct{ a int }{a: 0})) True(t, isEmpty(struct { a int B int }{a: 0, B: 0})) True(t, isEmpty(0)) True(t, isEmpty(int(0))) True(t, isEmpty(int8(0))) True(t, isEmpty(int16(0))) True(t, isEmpty(uint16(0))) True(t, isEmpty(int32(0))) True(t, isEmpty(uint32(0))) True(t, isEmpty(int64(0))) True(t, isEmpty(uint64(0))) True(t, isEmpty('\u0000')) // rune => int32 True(t, isEmpty(float32(0))) True(t, isEmpty(float64(0))) True(t, isEmpty(0i)) // complex True(t, isEmpty(0.0i)) // complex True(t, isEmpty(false)) True(t, isEmpty(new(bool))) True(t, isEmpty(map[string]string{})) True(t, isEmpty(map[string]string(nil))) True(t, isEmpty(new(time.Time))) True(t, isEmpty(time.Time{})) True(t, isEmpty(make(chan struct{}))) True(t, isEmpty(chan struct{}(nil))) True(t, isEmpty(chan<- struct{}(nil))) True(t, isEmpty(make(chan struct{}))) True(t, isEmpty(make(chan<- struct{}))) True(t, isEmpty(make(chan struct{}, 1))) True(t, isEmpty(make(chan<- struct{}, 1))) True(t, isEmpty([1]int{0})) True(t, isEmpty([2]int{0, 0})) True(t, isEmpty([8]int{})) True(t, isEmpty([...]int{7: 0})) True(t, isEmpty([...]bool{false, false})) True(t, isEmpty(errors.New(""))) // BEWARE True(t, isEmpty([]error{})) True(t, isEmpty([]error(nil))) True(t, isEmpty(&[1]int{0})) True(t, isEmpty(&[2]int{0, 0})) False(t, isEmpty("something")) False(t, isEmpty(errors.New("something"))) False(t, isEmpty([]string{"something"})) False(t, isEmpty(1)) False(t, isEmpty(int(1))) False(t, isEmpty(uint(1))) False(t, isEmpty(byte(1))) False(t, isEmpty(int8(1))) False(t, isEmpty(uint8(1))) False(t, isEmpty(int16(1))) False(t, isEmpty(uint16(1))) False(t, isEmpty(int32(1))) False(t, isEmpty(uint32(1))) False(t, isEmpty(int64(1))) False(t, isEmpty(uint64(1))) False(t, isEmpty('A')) // rune => int32 False(t, isEmpty(true)) False(t, isEmpty(1.0)) False(t, isEmpty(1i)) // complex False(t, isEmpty([]byte{0})) // elements values are ignored for slices False(t, isEmpty([]byte{0, 0})) // elements values are ignored for slices False(t, isEmpty([]string{""})) // elements values are ignored for slices False(t, isEmpty([]string{"a"})) // elements values are ignored for slices False(t, isEmpty([]bool{false})) // elements values are ignored for slices False(t, isEmpty([]bool{true})) // elements values are ignored for slices False(t, isEmpty([]error{errors.New("xxx")})) False(t, isEmpty([]error{nil})) // BEWARE False(t, isEmpty([]error{errors.New("")})) // BEWARE False(t, isEmpty(map[string]string{"Hello": "World"})) False(t, isEmpty(map[string]string{"": ""})) False(t, isEmpty(map[string]string{"foo": ""})) False(t, isEmpty(map[string]string{"": "foo"})) False(t, isEmpty(chWithValue)) False(t, isEmpty([1]bool{true})) False(t, isEmpty([2]bool{false, true})) False(t, isEmpty([...]bool{10: true})) False(t, isEmpty([]int{0})) False(t, isEmpty([]int{42})) False(t, isEmpty([1]int{42})) False(t, isEmpty([2]int{0, 42})) False(t, isEmpty(&[1]int{42})) False(t, isEmpty(&[2]int{0, 42})) False(t, isEmpty([1]*int{new(int)})) // array elements must be the zero value, not any Empty value False(t, isEmpty(struct{ A int }{A: 42})) False(t, isEmpty(struct{ a int }{a: 42})) False(t, isEmpty(struct{ a *int }{a: new(int)})) // fields must be the zero value, not any Empty value False(t, isEmpty(struct{ a []int }{a: []int{}})) // fields must be the zero value, not any Empty value False(t, isEmpty(struct { a int B int }{a: 0, B: 42})) False(t, isEmpty(struct { a int B int }{a: 42, B: 0})) } func Benchmark_isEmpty(b *testing.B) { b.ReportAllocs() v := new(int) b.ResetTimer() for i := 0; i < b.N; i++ { isEmpty("") isEmpty(42) isEmpty(v) } } func TestEmpty(t *testing.T) { t.Parallel() mockT := new(testing.T) chWithValue := make(chan struct{}, 1) chWithValue <- struct{}{} var tiP *time.Time var tiNP time.Time var s *string var f *os.File sP := &s x := 1 xP := &x type TString string type TStruct struct { x int } True(t, Empty(mockT, ""), "Empty string is empty") True(t, Empty(mockT, nil), "Nil is empty") True(t, Empty(mockT, []string{}), "Empty string array is empty") True(t, Empty(mockT, 0), "Zero int value is empty") True(t, Empty(mockT, false), "False value is empty") True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty") True(t, Empty(mockT, s), "Nil string pointer is empty") True(t, Empty(mockT, f), "Nil os.File pointer is empty") True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty") True(t, Empty(mockT, tiNP), "time.Time is empty") True(t, Empty(mockT, TStruct{}), "struct with zero values is empty") True(t, Empty(mockT, TString("")), "empty aliased string is empty") True(t, Empty(mockT, sP), "ptr to nil value is empty") True(t, Empty(mockT, [1]int{}), "array is state") False(t, Empty(mockT, "something"), "Non Empty string is not empty") False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty") False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty") False(t, Empty(mockT, 1), "Non-zero int value is not empty") False(t, Empty(mockT, true), "True value is not empty") False(t, Empty(mockT, chWithValue), "Channel with values is not empty") False(t, Empty(mockT, TStruct{x: 1}), "struct with initialized values is empty") False(t, Empty(mockT, TString("abc")), "non-empty aliased string is empty") False(t, Empty(mockT, xP), "ptr to non-nil value is not empty") False(t, Empty(mockT, [1]int{42}), "array is not state") // error messages validation tests := []struct { name string value interface{} expectedResult bool expectedErrMsg string }{ { name: "Non Empty string is not empty", value: "something", expectedResult: false, expectedErrMsg: "Should be empty, but was something\n", }, { name: "Non nil object is not empty", value: errors.New("something"), expectedResult: false, expectedErrMsg: "Should be empty, but was something\n", }, { name: "Non empty string array is not empty", value: []string{"something"}, expectedResult: false, expectedErrMsg: "Should be empty, but was [something]\n", }, { name: "Non-zero int value is not empty", value: 1, expectedResult: false, expectedErrMsg: "Should be empty, but was 1\n", }, { name: "True value is not empty", value: true, expectedResult: false, expectedErrMsg: "Should be empty, but was true\n", }, { name: "Channel with values is not empty", value: chWithValue, expectedResult: false, expectedErrMsg: fmt.Sprintf("Should be empty, but was %v\n", chWithValue), }, { name: "struct with initialized values is empty", value: TStruct{x: 1}, expectedResult: false, expectedErrMsg: "Should be empty, but was {1}\n", }, { name: "non-empty aliased string is empty", value: TString("abc"), expectedResult: false, expectedErrMsg: "Should be empty, but was abc\n", }, { name: "ptr to non-nil value is not empty", value: xP, expectedResult: false, expectedErrMsg: fmt.Sprintf("Should be empty, but was %p\n", xP), }, { name: "array is not state", value: [1]int{42}, expectedResult: false, expectedErrMsg: "Should be empty, but was [42]\n", }, // Here are some edge cases { name: "string with only spaces is not empty", value: " ", expectedResult: false, expectedErrMsg: "Should be empty, but was \n", // TODO FIX THIS strange error message }, { name: "string with a line feed is not empty", value: "\n", expectedResult: false, // TODO This is the exact same error message as for an empty string expectedErrMsg: "Should be empty, but was \n", // TODO FIX THIS strange error message }, { name: "string with only tabulation and lines feed is not empty", value: "\n\t\n", expectedResult: false, // TODO The line feeds and tab are not helping to spot what is expected expectedErrMsg: "" + // this syntax is used to show how errors are reported. "Should be empty, but was \n" + "\t\n", }, { name: "string with trailing lines feed is not empty", value: "foo\n\n", expectedResult: false, // TODO it's not clear if one or two lines feed are expected expectedErrMsg: "Should be empty, but was foo\n\n", }, { name: "string with leading and trailing tabulation and lines feed is not empty", value: "\n\nfoo\t\n\t\n", expectedResult: false, // TODO The line feeds and tab are not helping to figure what is expected expectedErrMsg: "" + "Should be empty, but was \n" + "\n" + "foo\t\n" + "\t\n", }, { name: "non-printable character is not empty", value: "\u00a0", // NO-BREAK SPACE UNICODE CHARACTER expectedResult: false, // TODO here you cannot figure out what is expected expectedErrMsg: "Should be empty, but was \u00a0\n", }, // Here we are testing there is no error message on success { name: "Empty string is empty", value: "", expectedResult: true, expectedErrMsg: "", }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { mockCT := new(captureTestingT) res := Empty(mockCT, tt.value) mockCT.checkResultAndErrMsg(t, res, tt.expectedResult, tt.expectedErrMsg) }) } } func TestNotEmpty(t *testing.T) { t.Parallel() mockT := new(testing.T) chWithValue := make(chan struct{}, 1) chWithValue <- struct{}{} False(t, NotEmpty(mockT, ""), "Empty string is empty") False(t, NotEmpty(mockT, nil), "Nil is empty") False(t, NotEmpty(mockT, []string{}), "Empty string array is empty") False(t, NotEmpty(mockT, 0), "Zero int value is empty") False(t, NotEmpty(mockT, false), "False value is empty") False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty") False(t, NotEmpty(mockT, [1]int{}), "array is state") True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty") True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty") True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty") True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty") True(t, NotEmpty(mockT, true), "True value is not empty") True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty") True(t, NotEmpty(mockT, [1]int{42}), "array is not state") // error messages validation tests := []struct { name string value interface{} expectedResult bool expectedErrMsg string }{ { name: "Empty string is empty", value: "", expectedResult: false, expectedErrMsg: `Should NOT be empty, but was ` + "\n", // TODO FIX THIS strange error message }, { name: "Nil is empty", value: nil, expectedResult: false, expectedErrMsg: "Should NOT be empty, but was \n", }, { name: "Empty string array is empty", value: []string{}, expectedResult: false, expectedErrMsg: "Should NOT be empty, but was []\n", }, { name: "Zero int value is empty", value: 0, expectedResult: false, expectedErrMsg: "Should NOT be empty, but was 0\n", }, { name: "False value is empty", value: false, expectedResult: false, expectedErrMsg: "Should NOT be empty, but was false\n", }, { name: "array is state", value: [1]int{}, expectedResult: false, expectedErrMsg: "Should NOT be empty, but was [0]\n", }, // Here we are testing there is no error message on success { name: "Non Empty string is not empty", value: "something", expectedResult: true, expectedErrMsg: "", }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { mockCT := new(captureTestingT) res := NotEmpty(mockCT, tt.value) mockCT.checkResultAndErrMsg(t, tt.expectedResult, res, tt.expectedErrMsg) }) } } func Test_getLen(t *testing.T) { t.Parallel() falseCases := []interface{}{ nil, 0, true, false, 'A', struct{}{}, } for _, v := range falseCases { l, ok := getLen(v) False(t, ok, "Expected getLen fail to get length of %#v", v) Equal(t, 0, l, "getLen should return 0 for %#v", v) } ch := make(chan int, 5) ch <- 1 ch <- 2 ch <- 3 trueCases := []struct { v interface{} l int }{ {[]int{1, 2, 3}, 3}, {[...]int{1, 2, 3}, 3}, {"ABC", 3}, {map[int]int{1: 2, 2: 4, 3: 6}, 3}, {ch, 3}, {[]int{}, 0}, {map[int]int{}, 0}, {make(chan int), 0}, {[]int(nil), 0}, {map[int]int(nil), 0}, {(chan int)(nil), 0}, } for _, c := range trueCases { l, ok := getLen(c.v) True(t, ok, "Expected getLen success to get length of %#v", c.v) Equal(t, c.l, l) } } func TestLen(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, Len(mockT, nil, 0), "nil does not have length") False(t, Len(mockT, 0, 0), "int does not have length") False(t, Len(mockT, true, 0), "true does not have length") False(t, Len(mockT, false, 0), "false does not have length") False(t, Len(mockT, 'A', 0), "Rune does not have length") False(t, Len(mockT, struct{}{}, 0), "Struct does not have length") ch := make(chan int, 5) ch <- 1 ch <- 2 ch <- 3 cases := []struct { v interface{} l int expected1234567 string // message when expecting 1234567 items }{ {[]int{1, 2, 3}, 3, `"[1 2 3]" should have 1234567 item(s), but has 3`}, {[...]int{1, 2, 3}, 3, `"[1 2 3]" should have 1234567 item(s), but has 3`}, {"ABC", 3, `"ABC" should have 1234567 item(s), but has 3`}, {map[int]int{1: 2, 2: 4, 3: 6}, 3, `"map[1:2 2:4 3:6]" should have 1234567 item(s), but has 3`}, {ch, 3, ""}, {[]int{}, 0, `"[]" should have 1234567 item(s), but has 0`}, {map[int]int{}, 0, `"map[]" should have 1234567 item(s), but has 0`}, {make(chan int), 0, ""}, {[]int(nil), 0, `"[]" should have 1234567 item(s), but has 0`}, {map[int]int(nil), 0, `"map[]" should have 1234567 item(s), but has 0`}, {(chan int)(nil), 0, `"" should have 1234567 item(s), but has 0`}, } for _, c := range cases { True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l) False(t, Len(mockT, c.v, c.l+1), "%#v have %d items", c.v, c.l) if c.expected1234567 != "" { msgMock := new(mockTestingT) Len(msgMock, c.v, 1234567) Contains(t, msgMock.errorString(), c.expected1234567) } } } func TestWithinDuration(t *testing.T) { t.Parallel() mockT := new(testing.T) a := time.Now() b := a.Add(10 * time.Second) True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference") True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference") False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference") False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference") False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference") False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference") False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference") False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference") } func TestWithinRange(t *testing.T) { t.Parallel() mockT := new(testing.T) n := time.Now() s := n.Add(-time.Second) e := n.Add(time.Second) True(t, WithinRange(mockT, n, n, n), "Exact same actual, start, and end values return true") True(t, WithinRange(mockT, n, s, e), "Time in range is within the time range") True(t, WithinRange(mockT, s, s, e), "The start time is within the time range") True(t, WithinRange(mockT, e, s, e), "The end time is within the time range") False(t, WithinRange(mockT, s.Add(-time.Nanosecond), s, e, "Just before the start time is not within the time range")) False(t, WithinRange(mockT, e.Add(time.Nanosecond), s, e, "Just after the end time is not within the time range")) False(t, WithinRange(mockT, n, e, s, "Just after the end time is not within the time range")) } func TestInDelta(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01") True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01") True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1") False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail") False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail") False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail") True(t, InDelta(mockT, math.NaN(), math.NaN(), 0.01), "Expected NaN for both to pass") cases := []struct { a, b interface{} delta float64 }{ {uint(2), uint(1), 1}, {uint8(2), uint8(1), 1}, {uint16(2), uint16(1), 1}, {uint32(2), uint32(1), 1}, {uint64(2), uint64(1), 1}, {int(2), int(1), 1}, {int8(2), int8(1), 1}, {int16(2), int16(1), 1}, {int32(2), int32(1), 1}, {int64(2), int64(1), 1}, {float32(2), float32(1), 1}, {float64(2), float64(1), 1}, } for _, tc := range cases { True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta) } } func TestInDeltaSlice(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, InDeltaSlice(mockT, []float64{1.001, math.NaN(), 0.999}, []float64{1, math.NaN(), 1}, 0.1), "{1.001, NaN, 0.009} is element-wise close to {1, NaN, 1} in delta=0.1") True(t, InDeltaSlice(mockT, []float64{1, math.NaN(), 2}, []float64{0, math.NaN(), 3}, 1), "{1, NaN, 2} is element-wise close to {0, NaN, 3} in delta=1") False(t, InDeltaSlice(mockT, []float64{1, math.NaN(), 2}, []float64{0, math.NaN(), 3}, 0.1), "{1, NaN, 2} is not element-wise close to {0, NaN, 3} in delta=0.1") False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") } func TestInDeltaMapValues(t *testing.T) { t.Parallel() mockT := new(testing.T) for _, tc := range []struct { title string expect interface{} actual interface{} f func(TestingT, bool, ...interface{}) bool delta float64 }{ { title: "Within delta", expect: map[string]float64{ "foo": 1.0, "bar": 2.0, "baz": math.NaN(), }, actual: map[string]float64{ "foo": 1.01, "bar": 1.99, "baz": math.NaN(), }, delta: 0.1, f: True, }, { title: "Within delta", expect: map[int]float64{ 1: 1.0, 2: 2.0, }, actual: map[int]float64{ 1: 1.0, 2: 1.99, }, delta: 0.1, f: True, }, { title: "Different number of keys", expect: map[int]float64{ 1: 1.0, 2: 2.0, }, actual: map[int]float64{ 1: 1.0, }, delta: 0.1, f: False, }, { title: "Within delta with zero value", expect: map[string]float64{ "zero": 0, }, actual: map[string]float64{ "zero": 0, }, delta: 0.1, f: True, }, { title: "With missing key with zero value", expect: map[string]float64{ "zero": 0, "foo": 0, }, actual: map[string]float64{ "zero": 0, "bar": 0, }, f: False, }, } { tc.f(t, InDeltaMapValues(mockT, tc.expect, tc.actual, tc.delta), tc.title+"\n"+diff(tc.expect, tc.actual)) } } func TestInEpsilon(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { a, b interface{} epsilon float64 }{ {uint8(2), uint16(2), .001}, {2.1, 2.2, 0.1}, {2.2, 2.1, 0.1}, {-2.1, -2.2, 0.1}, {-2.2, -2.1, 0.1}, {uint64(100), uint8(101), 0.01}, {0.1, -0.1, 2}, {0.1, 0, 2}, {math.NaN(), math.NaN(), 1}, {time.Second, time.Second + time.Millisecond, 0.002}, } for _, tc := range cases { True(t, InEpsilon(t, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon), "test: %q", tc) } cases = []struct { a, b interface{} epsilon float64 }{ {uint8(2), int16(-2), .001}, {uint64(100), uint8(102), 0.01}, {2.1, 2.2, 0.001}, {2.2, 2.1, 0.001}, {2.1, -2.2, 1}, {2.1, "bla-bla", 0}, {0.1, -0.1, 1.99}, {0, 0.1, 2}, // expected must be different to zero {time.Second, time.Second + 10*time.Millisecond, 0.002}, {math.NaN(), 0, 1}, {0, math.NaN(), 1}, {0, 0, math.NaN()}, {math.Inf(1), 1, 1}, {math.Inf(-1), 1, 1}, {1, math.Inf(1), 1}, {1, math.Inf(-1), 1}, {math.Inf(1), math.Inf(1), 1}, {math.Inf(1), math.Inf(-1), 1}, {math.Inf(-1), math.Inf(1), 1}, {math.Inf(-1), math.Inf(-1), 1}, } for _, tc := range cases { False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) } } func TestInEpsilonSlice(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, InEpsilonSlice(mockT, []float64{2.2, math.NaN(), 2.0}, []float64{2.1, math.NaN(), 2.1}, 0.06), "{2.2, NaN, 2.0} is element-wise close to {2.1, NaN, 2.1} in epsilon=0.06") False(t, InEpsilonSlice(mockT, []float64{2.2, 2.0}, []float64{2.1, 2.1}, 0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in epsilon=0.04") False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") } func TestRegexp(t *testing.T) { t.Parallel() mockT := new(testing.T) cases := []struct { rx, str string }{ {"^start", "start of the line"}, {"end$", "in the end"}, {"end$", "in the end"}, {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"}, } for _, tc := range cases { True(t, Regexp(mockT, tc.rx, tc.str)) True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str)) True(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str))) False(t, NotRegexp(mockT, tc.rx, tc.str)) False(t, NotRegexp(mockT, tc.rx, []byte(tc.str))) False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) } cases = []struct { rx, str string }{ {"^asdfastart", "Not the start of the line"}, {"end$", "in the end."}, {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"}, } for _, tc := range cases { False(t, Regexp(mockT, tc.rx, tc.str), "Expected %q to not match %q", tc.rx, tc.str) False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str)) False(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str))) True(t, NotRegexp(mockT, tc.rx, tc.str)) True(t, NotRegexp(mockT, tc.rx, []byte(tc.str))) True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) } } func testAutogeneratedFunction() { defer func() { if err := recover(); err == nil { panic("did not panic") } CallerInfo() }() t := struct { io.Closer }{} c := t c.Close() } func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) { t.Parallel() NotPanics(t, func() { testAutogeneratedFunction() }) } func TestZero(t *testing.T) { t.Parallel() mockT := new(testing.T) for _, test := range zeros { True(t, Zero(mockT, test, "%#v is not the %T zero value", test, test)) } for _, test := range nonZeros { False(t, Zero(mockT, test, "%#v is not the %T zero value", test, test)) } } func TestNotZero(t *testing.T) { t.Parallel() mockT := new(testing.T) for _, test := range zeros { False(t, NotZero(mockT, test, "%#v is not the %T zero value", test, test)) } for _, test := range nonZeros { True(t, NotZero(mockT, test, "%#v is not the %T zero value", test, test)) } } func TestFileExists(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, FileExists(mockT, "assertions.go")) mockT = new(testing.T) False(t, FileExists(mockT, "random_file")) mockT = new(testing.T) False(t, FileExists(mockT, "../_codegen")) link := getTempSymlinkPath(t, "assertions.go") mockT = new(testing.T) True(t, FileExists(mockT, link)) link = getTempSymlinkPath(t, "non_existent_file") mockT = new(testing.T) True(t, FileExists(mockT, link)) } func TestNoFileExists(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, NoFileExists(mockT, "assertions.go")) mockT = new(testing.T) True(t, NoFileExists(mockT, "non_existent_file")) mockT = new(testing.T) True(t, NoFileExists(mockT, "../_codegen")) link := getTempSymlinkPath(t, "assertions.go") mockT = new(testing.T) False(t, NoFileExists(mockT, link)) link = getTempSymlinkPath(t, "non_existent_file") mockT = new(testing.T) False(t, NoFileExists(mockT, link)) } func getTempSymlinkPath(t *testing.T, file string) string { t.Helper() tempDir := t.TempDir() link := filepath.Join(tempDir, file+"_symlink") if err := os.Symlink(file, link); err != nil { t.Fatalf("could not create temp symlink %q pointing to %q: %v", link, file, err) } return link } func TestDirExists(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, DirExists(mockT, "assertions.go")) mockT = new(testing.T) False(t, DirExists(mockT, "non_existent_dir")) mockT = new(testing.T) True(t, DirExists(mockT, "../_codegen")) link := getTempSymlinkPath(t, "assertions.go") mockT = new(testing.T) False(t, DirExists(mockT, link)) link = getTempSymlinkPath(t, "non_existent_dir") mockT = new(testing.T) False(t, DirExists(mockT, link)) } func TestNoDirExists(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, NoDirExists(mockT, "assertions.go")) mockT = new(testing.T) True(t, NoDirExists(mockT, "non_existent_dir")) mockT = new(testing.T) False(t, NoDirExists(mockT, "../_codegen")) link := getTempSymlinkPath(t, "assertions.go") mockT = new(testing.T) True(t, NoDirExists(mockT, link)) link = getTempSymlinkPath(t, "non_existent_dir") mockT = new(testing.T) True(t, NoDirExists(mockT, link)) } func TestJSONEq_EqualSONString(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) } func TestJSONEq_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) } func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")) } func TestJSONEq_Array(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) } func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) } func TestJSONEq_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) } func TestJSONEq_ActualIsNotJSON(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")) } func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)) } func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, "Not JSON", "Not JSON")) } func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)) } func TestYAMLEq_EqualYAMLString(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) } func TestYAMLEq_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) } func TestYAMLEq_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(testing.T) expected := ` numeric: 1.5 array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] hash: nested: hash nested_slice: [this, is, nested] string: "foo" ` actual := ` numeric: 1.5 hash: nested: hash nested_slice: [this, is, nested] string: "foo" array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] ` True(t, YAMLEq(mockT, expected, actual)) } func TestYAMLEq_Array(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) } func TestYAMLEq_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) } func TestYAMLEq_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) } func TestYAMLEq_ActualIsSimpleString(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, `{"foo": "bar"}`, "Simple String")) } func TestYAMLEq_ExpectedIsSimpleString(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, "Simple String", `{"foo": "bar", "hello": "world"}`)) } func TestYAMLEq_ExpectedAndActualSimpleString(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, YAMLEq(mockT, "Simple String", "Simple String")) } func TestYAMLEq_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)) } func TestYAMLEq_OnlyFirstDocument(t *testing.T) { t.Parallel() mockT := new(testing.T) True(t, YAMLEq(mockT, `--- doc1: same --- doc2: different `, `--- doc1: same --- doc2: notsame `, )) } func TestYAMLEq_InvalidIdenticalYAML(t *testing.T) { t.Parallel() mockT := new(testing.T) False(t, YAMLEq(mockT, `}`, `}`)) } type diffTestingStruct struct { A string B int } func (d *diffTestingStruct) String() string { return d.A } func TestDiff(t *testing.T) { t.Parallel() expected := ` Diff: --- Expected +++ Actual @@ -1,3 +1,3 @@ (struct { foo string }) { - foo: (string) (len=5) "hello" + foo: (string) (len=3) "bar" } ` actual := diff( struct{ foo string }{"hello"}, struct{ foo string }{"bar"}, ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -2,5 +2,5 @@ (int) 1, - (int) 2, (int) 3, - (int) 4 + (int) 5, + (int) 7 } ` actual = diff( []int{1, 2, 3, 4}, []int{1, 3, 5, 7}, ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -2,4 +2,4 @@ (int) 1, - (int) 2, - (int) 3 + (int) 3, + (int) 5 } ` actual = diff( []int{1, 2, 3, 4}[0:3], []int{1, 3, 5, 7}[0:3], ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -1,6 +1,6 @@ (map[string]int) (len=4) { - (string) (len=4) "four": (int) 4, + (string) (len=4) "five": (int) 5, (string) (len=3) "one": (int) 1, - (string) (len=5) "three": (int) 3, - (string) (len=3) "two": (int) 2 + (string) (len=5) "seven": (int) 7, + (string) (len=5) "three": (int) 3 } ` actual = diff( map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7}, ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -1,3 +1,3 @@ (*errors.errorString)({ - s: (string) (len=19) "some expected error" + s: (string) (len=12) "actual error" }) ` actual = diff( errors.New("some expected error"), errors.New("actual error"), ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -2,3 +2,3 @@ A: (string) (len=11) "some string", - B: (int) 10 + B: (int) 15 } ` actual = diff( diffTestingStruct{A: "some string", B: 10}, diffTestingStruct{A: "some string", B: 15}, ) Equal(t, expected, actual) expected = ` Diff: --- Expected +++ Actual @@ -1,2 +1,2 @@ -(time.Time) 2020-09-24 00:00:00 +0000 UTC +(time.Time) 2020-09-25 00:00:00 +0000 UTC ` actual = diff( time.Date(2020, 9, 24, 0, 0, 0, 0, time.UTC), time.Date(2020, 9, 25, 0, 0, 0, 0, time.UTC), ) Equal(t, expected, actual) } func TestTimeEqualityErrorFormatting(t *testing.T) { t.Parallel() mockT := new(mockTestingT) Equal(mockT, time.Second*2, time.Millisecond) expectedErr := "\\s+Error Trace:\\s+Error:\\s+Not equal:\\s+\n\\s+expected: 2s\n\\s+actual\\s+: 1ms\n" Regexp(t, regexp.MustCompile(expectedErr), mockT.errorString()) } func TestDiffEmptyCases(t *testing.T) { t.Parallel() Equal(t, "", diff(nil, nil)) Equal(t, "", diff(struct{ foo string }{}, nil)) Equal(t, "", diff(nil, struct{ foo string }{})) Equal(t, "", diff(1, 2)) Equal(t, "", diff(1, 2)) Equal(t, "", diff([]int{1}, []bool{true})) } // Ensure there are no data races func TestDiffRace(t *testing.T) { t.Parallel() expected := map[string]string{ "a": "A", "b": "B", "c": "C", } actual := map[string]string{ "d": "D", "e": "E", "f": "F", } // run diffs in parallel simulating tests with t.Parallel() numRoutines := 10 rChans := make([]chan string, numRoutines) for idx := range rChans { rChans[idx] = make(chan string) go func(ch chan string) { defer close(ch) ch <- diff(expected, actual) }(rChans[idx]) } for _, ch := range rChans { for msg := range ch { NotZero(t, msg) // dummy assert } } } type mockTestingT struct { errorFmt string args []interface{} } // Helper is like [testing.T.Helper] but does nothing. func (mockTestingT) Helper() {} func (m *mockTestingT) errorString() string { return fmt.Sprintf(m.errorFmt, m.args...) } func (m *mockTestingT) Errorf(format string, args ...interface{}) { m.errorFmt = format m.args = args } func (m *mockTestingT) Failed() bool { return m.errorFmt != "" } func TestFailNowWithPlainTestingT(t *testing.T) { t.Parallel() mockT := &mockTestingT{} Panics(t, func() { FailNow(mockT, "failed") }, "should panic since mockT is missing FailNow()") } type mockFailNowTestingT struct{} // Helper is like [testing.T.Helper] but does nothing. func (mockFailNowTestingT) Helper() {} func (m *mockFailNowTestingT) Errorf(format string, args ...interface{}) {} func (m *mockFailNowTestingT) FailNow() {} func TestFailNowWithFullTestingT(t *testing.T) { t.Parallel() mockT := &mockFailNowTestingT{} NotPanics(t, func() { FailNow(mockT, "failed") }, "should call mockT.FailNow() rather than panicking") } func TestBytesEqual(t *testing.T) { t.Parallel() cases := []struct { a, b []byte }{ {make([]byte, 2), make([]byte, 2)}, {make([]byte, 2), make([]byte, 2, 3)}, {nil, make([]byte, 0)}, } for i, c := range cases { Equal(t, reflect.DeepEqual(c.a, c.b), ObjectsAreEqual(c.a, c.b), "case %d failed", i+1) } } func BenchmarkBytesEqual(b *testing.B) { const size = 1024 * 8 s := make([]byte, size) for i := range s { s[i] = byte(i % 255) } s2 := make([]byte, size) copy(s2, s) mockT := &mockFailNowTestingT{} b.ResetTimer() for i := 0; i < b.N; i++ { Equal(mockT, s, s2) } } func BenchmarkNotNil(b *testing.B) { for i := 0; i < b.N; i++ { NotNil(b, b) } } func ExampleComparisonAssertionFunc() { t := &testing.T{} // provided by test adder := func(x, y int) int { return x + y } type args struct { x int y int } tests := []struct { name string args args expect int assertion ComparisonAssertionFunc }{ {"2+2=4", args{2, 2}, 4, Equal}, {"2+2!=5", args{2, 2}, 5, NotEqual}, {"2+3==5", args{2, 3}, 5, Exactly}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y)) }) } } func TestComparisonAssertionFunc(t *testing.T) { t.Parallel() type iface interface { Name() string } tests := []struct { name string expect interface{} got interface{} assertion ComparisonAssertionFunc }{ {"implements", (*iface)(nil), t, Implements}, {"isType", (*testing.T)(nil), t, IsType}, {"equal", t, t, Equal}, {"equalValues", t, t, EqualValues}, {"notEqualValues", t, nil, NotEqualValues}, {"exactly", t, t, Exactly}, {"notEqual", t, nil, NotEqual}, {"notContains", []int{1, 2, 3}, 4, NotContains}, {"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset}, {"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset}, {"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch}, {"regexp", "^t.*y$", "testify", Regexp}, {"notRegexp", "^t.*y$", "Testify", NotRegexp}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.expect, tt.got) }) } } func ExampleValueAssertionFunc() { t := &testing.T{} // provided by test dumbParse := func(input string) interface{} { var x interface{} _ = json.Unmarshal([]byte(input), &x) return x } tests := []struct { name string arg string assertion ValueAssertionFunc }{ {"true is not nil", "true", NotNil}, {"empty string is nil", "", Nil}, {"zero is not nil", "0", NotNil}, {"zero is zero", "0", Zero}, {"false is zero", "false", Zero}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, dumbParse(tt.arg)) }) } } func TestValueAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string value interface{} assertion ValueAssertionFunc }{ {"notNil", true, NotNil}, {"nil", nil, Nil}, {"empty", []int{}, Empty}, {"notEmpty", []int{1}, NotEmpty}, {"zero", false, Zero}, {"notZero", 42, NotZero}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.value) }) } } func ExampleBoolAssertionFunc() { t := &testing.T{} // provided by test isOkay := func(x int) bool { return x >= 42 } tests := []struct { name string arg int assertion BoolAssertionFunc }{ {"-1 is bad", -1, False}, {"42 is good", 42, True}, {"41 is bad", 41, False}, {"45 is cool", 45, True}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, isOkay(tt.arg)) }) } } func TestBoolAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string value bool assertion BoolAssertionFunc }{ {"true", true, True}, {"false", false, False}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.value) }) } } func ExampleErrorAssertionFunc() { t := &testing.T{} // provided by test dumbParseNum := func(input string, v interface{}) error { return json.Unmarshal([]byte(input), v) } tests := []struct { name string arg string assertion ErrorAssertionFunc }{ {"1.2 is number", "1.2", NoError}, {"1.2.3 not number", "1.2.3", Error}, {"true is not number", "true", Error}, {"3 is number", "3", NoError}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var x float64 tt.assertion(t, dumbParseNum(tt.arg, &x)) }) } } func TestErrorAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string err error assertion ErrorAssertionFunc }{ {"noError", nil, NoError}, {"error", errors.New("whoops"), Error}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.err) }) } } func ExamplePanicAssertionFunc() { t := &testing.T{} // provided by test tests := []struct { name string panicFn PanicTestFunc assertion PanicAssertionFunc }{ {"with panic", func() { panic(nil) }, Panics}, {"without panic", func() {}, NotPanics}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.panicFn) }) } } func TestPanicAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string panicFn PanicTestFunc assertion PanicAssertionFunc }{ {"not panic", func() {}, NotPanics}, {"panic", func() { panic(nil) }, Panics}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.panicFn) }) } } func TestEventuallyFalse(t *testing.T) { t.Parallel() mockT := new(testing.T) condition := func() bool { return false } False(t, Eventually(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) } func TestEventuallyTrue(t *testing.T) { t.Parallel() state := 0 condition := func() bool { defer func() { state += 1 }() return state == 2 } True(t, Eventually(t, condition, 100*time.Millisecond, 20*time.Millisecond)) } // errorsCapturingT is a mock implementation of TestingT that captures errors reported with Errorf. type errorsCapturingT struct { errors []error } // Helper is like [testing.T.Helper] but does nothing. func (errorsCapturingT) Helper() {} func (t *errorsCapturingT) Errorf(format string, args ...interface{}) { t.errors = append(t.errors, fmt.Errorf(format, args...)) } func TestEventuallyWithTFalse(t *testing.T) { t.Parallel() mockT := new(errorsCapturingT) condition := func(collect *CollectT) { Fail(collect, "condition fixed failure") } False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) Len(t, mockT.errors, 2) } func TestEventuallyWithTTrue(t *testing.T) { t.Parallel() mockT := new(errorsCapturingT) counter := 0 condition := func(collect *CollectT) { counter += 1 True(collect, counter == 2) } True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) Len(t, mockT.errors, 0) Equal(t, 2, counter, "Condition is expected to be called 2 times") } func TestEventuallyWithT_ConcurrencySafe(t *testing.T) { t.Parallel() mockT := new(errorsCapturingT) condition := func(collect *CollectT) { Fail(collect, "condition fixed failure") } // To trigger race conditions, we run EventuallyWithT with a nanosecond tick. False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, time.Nanosecond)) Len(t, mockT.errors, 2) } func TestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors(t *testing.T) { t.Parallel() // We'll use a channel to control whether a condition should sleep or not. mustSleep := make(chan bool, 2) mustSleep <- false mustSleep <- true close(mustSleep) condition := func(collect *CollectT) { if <-mustSleep { // Sleep to ensure that the second condition runs longer than timeout. time.Sleep(time.Second) return } // The first condition will fail. We expect to get this error as a result. Fail(collect, "condition fixed failure") } mockT := new(errorsCapturingT) False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) Len(t, mockT.errors, 2) } func TestEventuallyWithTFailNow(t *testing.T) { t.Parallel() mockT := new(CollectT) condition := func(collect *CollectT) { collect.FailNow() } False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) Len(t, mockT.errors, 1) } // Check that a long running condition doesn't block Eventually. // See issue 805 (and its long tail of following issues) func TestEventuallyTimeout(t *testing.T) { t.Parallel() mockT := new(testing.T) NotPanics(t, func() { done, done2 := make(chan struct{}), make(chan struct{}) // A condition function that returns after the Eventually timeout condition := func() bool { // Wait until Eventually times out and terminates <-done close(done2) return true } False(t, Eventually(mockT, condition, time.Millisecond, time.Microsecond)) close(done) <-done2 }) } func TestEventuallySucceedQuickly(t *testing.T) { t.Parallel() mockT := new(testing.T) condition := func() bool { return true } // By making the tick longer than the total duration, we expect that this test would fail if // we didn't check the condition before the first tick elapses. True(t, Eventually(mockT, condition, 100*time.Millisecond, time.Second)) } func TestEventuallyWithTSucceedQuickly(t *testing.T) { t.Parallel() mockT := new(testing.T) condition := func(t *CollectT) {} // By making the tick longer than the total duration, we expect that this test would fail if // we didn't check the condition before the first tick elapses. True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, time.Second)) } func TestNeverFalse(t *testing.T) { t.Parallel() condition := func() bool { return false } True(t, Never(t, condition, 100*time.Millisecond, 20*time.Millisecond)) } // TestNeverTrue checks Never with a condition that returns true on second call. func TestNeverTrue(t *testing.T) { t.Parallel() mockT := new(testing.T) // A list of values returned by condition. // Channel protects against concurrent access. returns := make(chan bool, 2) returns <- false returns <- true defer close(returns) // Will return true on second call. condition := func() bool { return <-returns } False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) } func TestNeverFailQuickly(t *testing.T) { t.Parallel() mockT := new(testing.T) // By making the tick longer than the total duration, we expect that this test would fail if // we didn't check the condition before the first tick elapses. condition := func() bool { return true } False(t, Never(mockT, condition, 100*time.Millisecond, time.Second)) } func Test_validateEqualArgs(t *testing.T) { t.Parallel() if validateEqualArgs(func() {}, func() {}) == nil { t.Error("non-nil functions should error") } if validateEqualArgs(func() {}, func() {}) == nil { t.Error("non-nil functions should error") } if validateEqualArgs(nil, nil) != nil { t.Error("nil functions are equal") } } func Test_truncatingFormat(t *testing.T) { t.Parallel() original := strings.Repeat("a", bufio.MaxScanTokenSize/2-102) result := truncatingFormat("%#v", original) Equal(t, fmt.Sprintf("%#v", original), result, "string should not be truncated") original = original + "x" result = truncatingFormat("%#v", original) NotEqual(t, fmt.Sprintf("%#v", original), result, "string should have been truncated.") if !strings.HasSuffix(result, "<... truncated>") { t.Error("truncated string should have <... truncated> suffix") } } // parseLabeledOutput does the inverse of labeledOutput - it takes a formatted // output string and turns it back into a slice of labeledContent. func parseLabeledOutput(output string) []labeledContent { labelPattern := regexp.MustCompile(`^\t([^\t]*): *\t(.*)$`) contentPattern := regexp.MustCompile(`^\t *\t(.*)$`) var contents []labeledContent lines := strings.Split(output, "\n") i := -1 for _, line := range lines { if line == "" { // skip blank lines continue } matches := labelPattern.FindStringSubmatch(line) if len(matches) == 3 { // a label contents = append(contents, labeledContent{ label: matches[1], content: matches[2] + "\n", }) i++ continue } matches = contentPattern.FindStringSubmatch(line) if len(matches) == 2 { // just content if i >= 0 { contents[i].content += matches[1] + "\n" continue } } // Couldn't parse output return nil } return contents } type captureTestingT struct { failed bool msg string } // Helper is like [testing.T.Helper] but does nothing. func (captureTestingT) Helper() {} func (ctt *captureTestingT) Errorf(format string, args ...interface{}) { ctt.msg = fmt.Sprintf(format, args...) ctt.failed = true } func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) { t.Helper() if res != expectedRes { t.Errorf("Should return %t", expectedRes) return } if res == ctt.failed { t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !ctt.failed) return } contents := parseLabeledOutput(ctt.msg) if res == true { if contents != nil { t.Errorf("Should not log an error. Log output: %q", ctt.msg) } return } if contents == nil { t.Errorf("Should log an error. Log output: %q", ctt.msg) return } for _, content := range contents { if content.label == "Error" { if expectedErrMsg == content.content { return } t.Errorf("Recorded Error: %q", content.content) } } t.Errorf("Expected Error: %q", expectedErrMsg) } func TestErrorIs(t *testing.T) { t.Parallel() tests := []struct { err error target error result bool resultErrMsg string }{ { err: io.EOF, target: io.EOF, result: true, }, { err: fmt.Errorf("wrap: %w", io.EOF), target: io.EOF, result: true, }, { err: io.EOF, target: io.ErrClosedPipe, result: false, resultErrMsg: "" + "Target error should be in err chain:\n" + "expected: \"io: read/write on closed pipe\"\n" + "in chain: \"EOF\"\n", }, { err: nil, target: io.EOF, result: false, resultErrMsg: "Expected error with \"EOF\" in chain but got nil.\n", }, { err: io.EOF, target: nil, result: false, resultErrMsg: "" + "Target error should be in err chain:\n" + "expected: \"\"\n" + "in chain: \"EOF\"\n", }, { err: nil, target: nil, result: true, }, { err: fmt.Errorf("abc: %w", errors.New("def")), target: io.EOF, result: false, resultErrMsg: "" + "Target error should be in err chain:\n" + "expected: \"EOF\"\n" + "in chain: \"abc: def\"\n" + "\t\"def\"\n", }, } for _, tt := range tests { tt := tt t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { mockT := new(captureTestingT) res := ErrorIs(mockT, tt.err, tt.target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } func TestNotErrorIs(t *testing.T) { t.Parallel() tests := []struct { err error target error result bool resultErrMsg string }{ { err: io.EOF, target: io.EOF, result: false, resultErrMsg: "" + "Target error should not be in err chain:\n" + "found: \"EOF\"\n" + "in chain: \"EOF\"\n", }, { err: fmt.Errorf("wrap: %w", io.EOF), target: io.EOF, result: false, resultErrMsg: "" + "Target error should not be in err chain:\n" + "found: \"EOF\"\n" + "in chain: \"wrap: EOF\"\n" + "\t\"EOF\"\n", }, { err: io.EOF, target: io.ErrClosedPipe, result: true, }, { err: nil, target: io.EOF, result: true, }, { err: io.EOF, target: nil, result: true, }, { err: nil, target: nil, result: false, resultErrMsg: "" + "Target error should not be in err chain:\n" + "found: \"\"\n" + "in chain: \n", }, { err: fmt.Errorf("abc: %w", errors.New("def")), target: io.EOF, result: true, }, } for _, tt := range tests { tt := tt t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { mockT := new(captureTestingT) res := NotErrorIs(mockT, tt.err, tt.target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } func TestErrorAs(t *testing.T) { t.Parallel() tests := []struct { err error result bool resultErrMsg string }{ { err: fmt.Errorf("wrap: %w", &customError{}), result: true, }, { err: io.EOF, result: false, resultErrMsg: "" + "Should be in error chain:\n" + "expected: *assert.customError\n" + "in chain: \"EOF\" (*errors.errorString)\n", }, { err: nil, result: false, resultErrMsg: "" + "An error is expected but got nil.\n" + `expected: *assert.customError` + "\n", }, { err: fmt.Errorf("abc: %w", errors.New("def")), result: false, resultErrMsg: "" + "Should be in error chain:\n" + "expected: *assert.customError\n" + "in chain: \"abc: def\" (*fmt.wrapError)\n" + "\t\"def\" (*errors.errorString)\n", }, } for _, tt := range tests { tt := tt var target *customError t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) { mockT := new(captureTestingT) res := ErrorAs(mockT, tt.err, &target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } func TestNotErrorAs(t *testing.T) { t.Parallel() tests := []struct { err error result bool resultErrMsg string }{ { err: fmt.Errorf("wrap: %w", &customError{}), result: false, resultErrMsg: "" + "Target error should not be in err chain:\n" + "found: *assert.customError\n" + "in chain: \"wrap: fail\" (*fmt.wrapError)\n" + "\t\"fail\" (*assert.customError)\n", }, { err: io.EOF, result: true, }, { err: nil, result: true, }, } for _, tt := range tests { tt := tt var target *customError t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) { mockT := new(captureTestingT) res := NotErrorAs(mockT, tt.err, &target) mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) }) } } func TestLenWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Len(mockT, longSlice, 1) Contains(t, mockT.errorString(), ` Error Trace: Error: "[0 0 0`) Contains(t, mockT.errorString(), `<... truncated>" should have 1 item(s), but has 1000000`) } func TestContainsWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Contains(mockT, longSlice, 1) Contains(t, mockT.errorString(), ` Error Trace: Error: []int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated> does not contain 1`) } func TestNotContainsWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotContains(mockT, longSlice, 0) Contains(t, mockT.errorString(), ` Error Trace: Error: []int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated> should not contain 0`) } func TestSubsetWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Subset(mockT, longSlice, []int{1}) Contains(t, mockT.errorString(), ` Error Trace: Error: []int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated> does not contain 1`) } func TestSubsetWithMapTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Subset(mockT, map[bool][]int{true: longSlice}, map[bool][]int{false: longSlice}) Contains(t, mockT.errorString(), ` Error Trace: Error: map[bool][]int{true:[]int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated> does not contain map[bool][]int{false:[]int{0, 0, 0,`) } func TestNotSubsetWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotSubset(mockT, longSlice, longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: ['\x00' '\x00' '\x00'`) Contains(t, mockT.errorString(), `<... truncated> is a subset of ['\x00' '\x00' '\x00'`) } func TestNotSubsetWithMapTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotSubset(mockT, map[int][]int{1: longSlice}, map[int][]int{1: longSlice}) Contains(t, mockT.errorString(), ` Error Trace: Error: map['\x01':['\x00' '\x00' '\x00'`) Contains(t, mockT.errorString(), `<... truncated> is a subset of map['\x01':['\x00' '\x00' '\x00'`) } func TestSameWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Same(mockT, &[]int{}, &longSlice) Contains(t, mockT.errorString(), `&[]int{0, 0, 0,`) } func TestNotSameWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotSame(mockT, &longSlice, &longSlice) Contains(t, mockT.errorString(), `&[]int{0, 0, 0,`) } func TestNilWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Nil(mockT, &longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: Expected nil, but got: &[]int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestEmptyWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Empty(mockT, longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: Should be empty, but was [0 0 0`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestNotEqualWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotEqual(mockT, longSlice, longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: Should not be: []int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestNotEqualValuesWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NotEqualValues(mockT, longSlice, longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: Should not be: []int{0, 0, 0,`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestNoErrorWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) NoError(mockT, fmt.Errorf("long: %v", longSlice)) Contains(t, mockT.errorString(), ` Error Trace: Error: Received unexpected error: long: [0 0 0`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestEqualErrorWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) EqualError(mockT, fmt.Errorf("long: %v", longSlice), "EOF") Contains(t, mockT.errorString(), ` Error Trace: Error: Error message not equal: expected: "EOF" actual : "long: [0 0 0`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestErrorContainsWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) ErrorContains(mockT, fmt.Errorf("long: %v", longSlice), "EOF") Contains(t, mockT.errorString(), ` Error Trace: Error: Error "long: [0 0 0`) Contains(t, mockT.errorString(), `<... truncated> does not contain "EOF"`) } func TestZeroWithSliceTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) Zero(mockT, longSlice) Contains(t, mockT.errorString(), ` Error Trace: Error: Should be zero, but was [0 0 0`) Contains(t, mockT.errorString(), `<... truncated>`) } func TestErrorIsWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) ErrorIs(mockT, fmt.Errorf("long: %v", longSlice), fmt.Errorf("also: %v", longSlice)) Contains(t, mockT.errorString(), ` Error Trace: Error: Target error should be in err chain: expected: "also: [0 0 0`) Contains(t, mockT.errorString(), `<... truncated> in chain: "long: [0 0 0`) } func TestNotErrorIsWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) err := fmt.Errorf("long: %v", longSlice) NotErrorIs(mockT, err, err) Contains(t, mockT.errorString(), ` Error Trace: Error: Target error should not be in err chain: found: "long: [0 0 0`) Contains(t, mockT.errorString(), `<... truncated> in chain: "long: [0 0 0`) } func TestErrorAsWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) var target *customError ErrorAs(mockT, fmt.Errorf("long: %v", longSlice), &target) Contains(t, mockT.errorString(), ` Error Trace: Error: Should be in error chain: expected: *assert.customError`) Contains(t, mockT.errorString(), ` in chain: "long: [0 0 0`) Contains(t, mockT.errorString(), "<... truncated>") } func TestNotErrorAsWithErrorTooLongToPrint(t *testing.T) { t.Parallel() mockT := new(mockTestingT) longSlice := make([]int, 1_000_000) var target *customError NotErrorAs(mockT, fmt.Errorf("long: %v %w", longSlice, &customError{}), &target) Contains(t, mockT.errorString(), ` Error Trace: Error: Target error should not be in err chain: found: *assert.customError`) Contains(t, mockT.errorString(), ` in chain: "long: [0 0 0`) Contains(t, mockT.errorString(), "<... truncated>") } ================================================ FILE: assert/doc.go ================================================ // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. // // # Note // // All functions in this package return a bool value indicating whether the assertion has passed. // // # Example Usage // // The following is a complete example using assert in a standard test function: // // import ( // "testing" // "github.com/stretchr/testify/assert" // ) // // func TestSomething(t *testing.T) { // // var a string = "Hello" // var b string = "Hello" // // assert.Equal(t, a, b, "The two words should be the same.") // // } // // if you assert many times, use the format below: // // import ( // "testing" // "github.com/stretchr/testify/assert" // ) // // func TestSomething(t *testing.T) { // assert := assert.New(t) // // var a string = "Hello" // var b string = "Hello" // // assert.Equal(a, b, "The two words should be the same.") // } // // # Assertions // // Assertions allow you to easily write test code, and are global funcs in the assert package. // All assertion functions take, as the first argument, the [*testing.T] object provided by the // testing framework. This allows the assertion funcs to write the failings and other details to // the correct place. // // Every assertion function also takes an optional string message as the final argument, // allowing custom error messages to be appended to the message the assertion method outputs. package assert ================================================ FILE: assert/errors.go ================================================ package assert import ( "errors" ) // AnError is an error instance useful for testing. If the code does not care // about error specifics, and only needs to return the error for example, this // error should be used to make the test code more readable. var AnError = errors.New("assert.AnError general error for testing") ================================================ FILE: assert/forward_assertions.go ================================================ package assert // Assertions provides assertion methods around the // TestingT interface. type Assertions struct { t TestingT } // New makes a new Assertions object for the specified TestingT. func New(t TestingT) *Assertions { return &Assertions{ t: t, } } //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" ================================================ FILE: assert/forward_assertions_test.go ================================================ package assert import ( "errors" "regexp" "testing" "time" ) func TestImplementsWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface") } if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") } } func TestIsTypeWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") } if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") } } func TestEqualWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.Equal("Hello World", "Hello World") { t.Error("Equal should return true") } if !assert.Equal(123, 123) { t.Error("Equal should return true") } if !assert.Equal(123.5, 123.5) { t.Error("Equal should return true") } if !assert.Equal([]byte("Hello World"), []byte("Hello World")) { t.Error("Equal should return true") } if !assert.Equal(nil, nil) { t.Error("Equal should return true") } } func TestEqualValuesWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.EqualValues(uint32(10), int32(10)) { t.Error("EqualValues should return true") } } func TestNotNilWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.NotNil(new(AssertionTesterConformingObject)) { t.Error("NotNil should return true: object is not nil") } if assert.NotNil(nil) { t.Error("NotNil should return false: object is nil") } } func TestNilWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.Nil(nil) { t.Error("Nil should return true: object is nil") } if assert.Nil(new(AssertionTesterConformingObject)) { t.Error("Nil should return false: object is not nil") } } func TestTrueWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.True(true) { t.Error("True should return true") } if assert.True(false) { t.Error("True should return false") } } func TestFalseWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.False(false) { t.Error("False should return true") } if assert.False(true) { t.Error("False should return false") } } func TestExactlyWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) a := float32(1) b := float64(1) c := float32(1) d := float32(2) if assert.Exactly(a, b) { t.Error("Exactly should return false") } if assert.Exactly(a, d) { t.Error("Exactly should return false") } if !assert.Exactly(a, c) { t.Error("Exactly should return true") } if assert.Exactly(nil, a) { t.Error("Exactly should return false") } if assert.Exactly(a, nil) { t.Error("Exactly should return false") } } func TestNotEqualWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.NotEqual("Hello World", "Hello World!") { t.Error("NotEqual should return true") } if !assert.NotEqual(123, 1234) { t.Error("NotEqual should return true") } if !assert.NotEqual(123.5, 123.55) { t.Error("NotEqual should return true") } if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) { t.Error("NotEqual should return true") } if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) { t.Error("NotEqual should return true") } } func TestNotEqualValuesWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.NotEqualValues("Hello World", "Hello World!") { t.Error("NotEqualValues should return true") } if !assert.NotEqualValues(123, 1234) { t.Error("NotEqualValues should return true") } if !assert.NotEqualValues(123.5, 123.55) { t.Error("NotEqualValues should return true") } if !assert.NotEqualValues([]byte("Hello World"), []byte("Hello World!")) { t.Error("NotEqualValues should return true") } if !assert.NotEqualValues(nil, new(AssertionTesterConformingObject)) { t.Error("NotEqualValues should return true") } if assert.NotEqualValues(10, uint(10)) { t.Error("NotEqualValues should return false") } } func TestContainsWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) list := []string{"Foo", "Bar"} if !assert.Contains("Hello World", "Hello") { t.Error("Contains should return true: \"Hello World\" contains \"Hello\"") } if assert.Contains("Hello World", "Salut") { t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"") } if !assert.Contains(list, "Foo") { t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") } if assert.Contains(list, "Salut") { t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"") } } func TestNotContainsWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) list := []string{"Foo", "Bar"} if !assert.NotContains("Hello World", "Hello!") { t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"") } if assert.NotContains("Hello World", "Hello") { t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"") } if !assert.NotContains(list, "Foo!") { t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"") } if assert.NotContains(list, "Foo") { t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") } } func TestConditionWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.Condition(func() bool { return true }, "Truth") { t.Error("Condition should return true") } if assert.Condition(func() bool { return false }, "Lie") { t.Error("Condition should return false") } } func TestDidPanicWrapper(t *testing.T) { t.Parallel() if funcDidPanic, _, _ := didPanic(func() { panic("Panic!") }); !funcDidPanic { t.Error("didPanic should return true") } if funcDidPanic, _, _ := didPanic(func() { }); funcDidPanic { t.Error("didPanic should return false") } } func TestPanicsWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.Panics(func() { panic("Panic!") }) { t.Error("Panics should return true") } if assert.Panics(func() { }) { t.Error("Panics should return false") } } func TestNotPanicsWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.NotPanics(func() { }) { t.Error("NotPanics should return true") } if assert.NotPanics(func() { panic("Panic!") }) { t.Error("NotPanics should return false") } } func TestNoErrorWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) // start with a nil error var err error assert.True(mockAssert.NoError(err), "NoError should return True for nil arg") // now set an error err = errors.New("Some error") assert.False(mockAssert.NoError(err), "NoError with error should return False") } func TestErrorWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) // start with a nil error var err error assert.False(mockAssert.Error(err), "Error should return False for nil arg") // now set an error err = errors.New("Some error") assert.True(mockAssert.Error(err), "Error with error should return True") } func TestErrorContainsWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) // start with a nil error var err error assert.False(mockAssert.ErrorContains(err, ""), "ErrorContains should return false for nil arg") // now set an error err = errors.New("some error: another error") assert.False(mockAssert.ErrorContains(err, "different error"), "ErrorContains should return false for different error string") assert.True(mockAssert.ErrorContains(err, "some error"), "ErrorContains should return true") assert.True(mockAssert.ErrorContains(err, "another error"), "ErrorContains should return true") } func TestEqualErrorWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) // start with a nil error var err error assert.False(mockAssert.EqualError(err, ""), "EqualError should return false for nil arg") // now set an error err = errors.New("some error") assert.False(mockAssert.EqualError(err, "Not some error"), "EqualError should return false for different error string") assert.True(mockAssert.EqualError(err, "some error"), "EqualError should return true") } func TestEmptyWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) assert.True(mockAssert.Empty(""), "Empty string is empty") assert.True(mockAssert.Empty(nil), "Nil is empty") assert.True(mockAssert.Empty([]string{}), "Empty string array is empty") assert.True(mockAssert.Empty(0), "Zero int value is empty") assert.True(mockAssert.Empty(false), "False value is empty") assert.False(mockAssert.Empty("something"), "Non Empty string is not empty") assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty") assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty") assert.False(mockAssert.Empty(1), "Non-zero int value is not empty") assert.False(mockAssert.Empty(true), "True value is not empty") } func TestNotEmptyWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) assert.False(mockAssert.NotEmpty(""), "Empty string is empty") assert.False(mockAssert.NotEmpty(nil), "Nil is empty") assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty") assert.False(mockAssert.NotEmpty(0), "Zero int value is empty") assert.False(mockAssert.NotEmpty(false), "False value is empty") assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty") assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty") assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty") assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty") assert.True(mockAssert.NotEmpty(true), "True value is not empty") } func TestLenWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) assert.False(mockAssert.Len(nil, 0), "nil does not have length") assert.False(mockAssert.Len(0, 0), "int does not have length") assert.False(mockAssert.Len(true, 0), "true does not have length") assert.False(mockAssert.Len(false, 0), "false does not have length") assert.False(mockAssert.Len('A', 0), "Rune does not have length") assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length") ch := make(chan int, 5) ch <- 1 ch <- 2 ch <- 3 cases := []struct { v interface{} l int }{ {[]int{1, 2, 3}, 3}, {[...]int{1, 2, 3}, 3}, {"ABC", 3}, {map[int]int{1: 2, 2: 4, 3: 6}, 3}, {ch, 3}, {[]int{}, 0}, {map[int]int{}, 0}, {make(chan int), 0}, {[]int(nil), 0}, {map[int]int(nil), 0}, {(chan int)(nil), 0}, } for _, c := range cases { assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l) } } func TestWithinDurationWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) a := time.Now() b := a.Add(10 * time.Second) assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference") assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference") assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference") assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference") assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference") assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference") assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference") assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference") } func TestInDeltaWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01") True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01") True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1") False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail") cases := []struct { a, b interface{} delta float64 }{ {uint8(2), uint8(1), 1}, {uint16(2), uint16(1), 1}, {uint32(2), uint32(1), 1}, {uint64(2), uint64(1), 1}, {int(2), int(1), 1}, {int8(2), int8(1), 1}, {int16(2), int16(1), 1}, {int32(2), int32(1), 1}, {int64(2), int64(1), 1}, {float32(2), float32(1), 1}, {float64(2), float64(1), 1}, } for _, tc := range cases { True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta) } } func TestInEpsilonWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) cases := []struct { a, b interface{} epsilon float64 }{ {uint8(2), uint16(2), .001}, {2.1, 2.2, 0.1}, {2.2, 2.1, 0.1}, {-2.1, -2.2, 0.1}, {-2.2, -2.1, 0.1}, {uint64(100), uint8(101), 0.01}, {0.1, -0.1, 2}, } for _, tc := range cases { True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) } cases = []struct { a, b interface{} epsilon float64 }{ {uint8(2), int16(-2), .001}, {uint64(100), uint8(102), 0.01}, {2.1, 2.2, 0.001}, {2.2, 2.1, 0.001}, {2.1, -2.2, 1}, {2.1, "bla-bla", 0}, {0.1, -0.1, 1.99}, } for _, tc := range cases { False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) } } func TestRegexpWrapper(t *testing.T) { t.Parallel() assert := New(new(testing.T)) cases := []struct { rx, str string }{ {"^start", "start of the line"}, {"end$", "in the end"}, {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"}, } for _, tc := range cases { True(t, assert.Regexp(tc.rx, tc.str)) True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str)) False(t, assert.NotRegexp(tc.rx, tc.str)) False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str)) } cases = []struct { rx, str string }{ {"^asdfastart", "Not the start of the line"}, {"end$", "in the end."}, {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"}, } for _, tc := range cases { False(t, assert.Regexp(tc.rx, tc.str), "Expected %q to not match %q", tc.rx, tc.str) False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str)) True(t, assert.NotRegexp(tc.rx, tc.str)) True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str)) } } func TestZeroWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) for _, test := range zeros { assert.True(mockAssert.Zero(test), "Zero should return true for %v", test) } for _, test := range nonZeros { assert.False(mockAssert.Zero(test), "Zero should return false for %v", test) } } func TestNotZeroWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) for _, test := range zeros { assert.False(mockAssert.NotZero(test), "Zero should return true for %v", test) } for _, test := range nonZeros { assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test) } } func TestJSONEqWrapper_EqualSONString(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) { t.Error("JSONEq should return true") } } func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { t.Error("JSONEq should return true") } } func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") { t.Error("JSONEq should return true") } } func TestJSONEqWrapper_Array(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) { t.Error("JSONEq should return true") } } func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) { t.Error("JSONEq should return false") } } func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { t.Error("JSONEq should return false") } } func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") { t.Error("JSONEq should return false") } } func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) { t.Error("JSONEq should return false") } } func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq("Not JSON", "Not JSON") { t.Error("JSONEq should return false") } } func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) { t.Error("JSONEq should return false") } } func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) { t.Error("YAMLEq should return true") } } func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { t.Error("YAMLEq should return true") } } func TestYAMLEqWrapper_HashOfArraysAndHashes(t *testing.T) { t.Parallel() assert := New(new(testing.T)) expected := ` numeric: 1.5 array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] hash: nested: hash nested_slice: [this, is, nested] string: "foo" ` actual := ` numeric: 1.5 hash: nested: hash nested_slice: [this, is, nested] string: "foo" array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] ` if !assert.YAMLEq(expected, actual) { t.Error("YAMLEq should return true") } } func TestYAMLEqWrapper_Array(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) { t.Error("YAMLEq should return true") } } func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) { t.Error("YAMLEq should return false") } } func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.YAMLEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { t.Error("YAMLEq should return false") } } func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.YAMLEq(`{"foo": "bar"}`, "Simple String") { t.Error("YAMLEq should return false") } } func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.YAMLEq("Simple String", `{"foo": "bar", "hello": "world"}`) { t.Error("YAMLEq should return false") } } func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if !assert.YAMLEq("Simple String", "Simple String") { t.Error("YAMLEq should return true") } } func TestYAMLEqWrapper_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() assert := New(new(testing.T)) if assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) { t.Error("YAMLEq should return false") } } ================================================ FILE: assert/http_assertions.go ================================================ package assert import ( "fmt" "net/http" "net/http/httptest" "net/url" "strings" ) // httpCode is a helper that returns HTTP code of the response. It returns -1 and // an error if building a new request fails. func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { w := httptest.NewRecorder() req, err := http.NewRequest(method, url, http.NoBody) if err != nil { return -1, err } req.URL.RawQuery = values.Encode() handler(w, req) return w.Code, nil } // HTTPSuccess asserts that a specified handler returns a success status code. // // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent if !isSuccessCode { Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isSuccessCode } // HTTPRedirect asserts that a specified handler returns a redirect status code. // // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect if !isRedirectCode { Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isRedirectCode } // HTTPError asserts that a specified handler returns an error status code. // // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isErrorCode := code >= http.StatusBadRequest if !isErrorCode { Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isErrorCode } // HTTPStatusCode asserts that a specified handler returns a specified status code. // // assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } successful := code == statuscode if !successful { Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...) } return successful } // HTTPBody is a helper that returns HTTP body of the response. It returns // empty string if building a new request fails. func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { w := httptest.NewRecorder() if len(values) > 0 { url += "?" + values.Encode() } req, err := http.NewRequest(method, url, http.NoBody) if err != nil { return "" } handler(w, req) return w.Body.String() } // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } body := HTTPBody(handler, method, url, values) contains := strings.Contains(body, fmt.Sprint(str)) if !contains { Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...) } return contains } // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } body := HTTPBody(handler, method, url, values) contains := strings.Contains(body, fmt.Sprint(str)) if contains { Fail(t, fmt.Sprintf("Expected response body for %q to NOT contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...) } return !contains } ================================================ FILE: assert/http_assertions_test.go ================================================ package assert import ( "fmt" "io" "net/http" "net/url" "testing" ) func httpOK(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } func httpReadBody(w http.ResponseWriter, r *http.Request) { _, _ = io.Copy(io.Discard, r.Body) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("hello")) } func httpRedirect(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusTemporaryRedirect) } func httpError(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) } func httpStatusCode(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusSwitchingProtocols) } func TestHTTPSuccess(t *testing.T) { t.Parallel() assert := New(t) mockT1 := new(testing.T) assert.Equal(HTTPSuccess(mockT1, httpOK, "GET", "/", nil), true) assert.False(mockT1.Failed()) mockT2 := new(testing.T) assert.Equal(HTTPSuccess(mockT2, httpRedirect, "GET", "/", nil), false) assert.True(mockT2.Failed()) mockT3 := new(mockTestingT) assert.Equal(HTTPSuccess( mockT3, httpError, "GET", "/", nil, "was not expecting a failure here", ), false) assert.True(mockT3.Failed()) assert.Contains(mockT3.errorString(), "was not expecting a failure here") mockT4 := new(testing.T) assert.Equal(HTTPSuccess(mockT4, httpStatusCode, "GET", "/", nil), false) assert.True(mockT4.Failed()) mockT5 := new(testing.T) assert.Equal(HTTPSuccess(mockT5, httpReadBody, "POST", "/", nil), true) assert.False(mockT5.Failed()) } func TestHTTPRedirect(t *testing.T) { t.Parallel() assert := New(t) mockT1 := new(mockTestingT) assert.Equal(HTTPRedirect( mockT1, httpOK, "GET", "/", nil, "was expecting a 3xx status code. Got 200.", ), false) assert.True(mockT1.Failed()) assert.Contains(mockT1.errorString(), "was expecting a 3xx status code. Got 200.") mockT2 := new(testing.T) assert.Equal(HTTPRedirect(mockT2, httpRedirect, "GET", "/", nil), true) assert.False(mockT2.Failed()) mockT3 := new(testing.T) assert.Equal(HTTPRedirect(mockT3, httpError, "GET", "/", nil), false) assert.True(mockT3.Failed()) mockT4 := new(testing.T) assert.Equal(HTTPRedirect(mockT4, httpStatusCode, "GET", "/", nil), false) assert.True(mockT4.Failed()) } func TestHTTPError(t *testing.T) { t.Parallel() assert := New(t) mockT1 := new(testing.T) assert.Equal(HTTPError(mockT1, httpOK, "GET", "/", nil), false) assert.True(mockT1.Failed()) mockT2 := new(mockTestingT) assert.Equal(HTTPError( mockT2, httpRedirect, "GET", "/", nil, "Expected this request to error out. But it didn't", ), false) assert.True(mockT2.Failed()) assert.Contains(mockT2.errorString(), "Expected this request to error out. But it didn't") mockT3 := new(testing.T) assert.Equal(HTTPError(mockT3, httpError, "GET", "/", nil), true) assert.False(mockT3.Failed()) mockT4 := new(testing.T) assert.Equal(HTTPError(mockT4, httpStatusCode, "GET", "/", nil), false) assert.True(mockT4.Failed()) } func TestHTTPStatusCode(t *testing.T) { t.Parallel() assert := New(t) mockT1 := new(testing.T) assert.Equal(HTTPStatusCode(mockT1, httpOK, "GET", "/", nil, http.StatusSwitchingProtocols), false) assert.True(mockT1.Failed()) mockT2 := new(testing.T) assert.Equal(HTTPStatusCode(mockT2, httpRedirect, "GET", "/", nil, http.StatusSwitchingProtocols), false) assert.True(mockT2.Failed()) mockT3 := new(mockTestingT) assert.Equal(HTTPStatusCode( mockT3, httpError, "GET", "/", nil, http.StatusSwitchingProtocols, "Expected the status code to be %d", http.StatusSwitchingProtocols, ), false) assert.True(mockT3.Failed()) assert.Contains(mockT3.errorString(), "Expected the status code to be 101") mockT4 := new(testing.T) assert.Equal(HTTPStatusCode(mockT4, httpStatusCode, "GET", "/", nil, http.StatusSwitchingProtocols), true) assert.False(mockT4.Failed()) } func TestHTTPStatusesWrapper(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true) assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true) assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false) assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true) } func httpHelloName(w http.ResponseWriter, r *http.Request) { name := r.FormValue("name") _, _ = fmt.Fprintf(w, "Hello, %s!", name) } func TestHTTPRequestWithNoParams(t *testing.T) { t.Parallel() var got *http.Request handler := func(w http.ResponseWriter, r *http.Request) { got = r w.WriteHeader(http.StatusOK) } True(t, HTTPSuccess(t, handler, "GET", "/url", nil)) Empty(t, got.URL.Query()) Equal(t, "/url", got.URL.RequestURI()) } func TestHTTPRequestWithParams(t *testing.T) { t.Parallel() var got *http.Request handler := func(w http.ResponseWriter, r *http.Request) { got = r w.WriteHeader(http.StatusOK) } params := url.Values{} params.Add("id", "12345") True(t, HTTPSuccess(t, handler, "GET", "/url", params)) Equal(t, url.Values{"id": []string{"12345"}}, got.URL.Query()) Equal(t, "/url?id=12345", got.URL.String()) Equal(t, "/url?id=12345", got.URL.RequestURI()) } func TestHttpBody(t *testing.T) { t.Parallel() assert := New(t) mockT := new(mockTestingT) assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.False(HTTPBodyNotContains( mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World", "Expected the request body to not contain 'World'. But it did.", )) assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) assert.Contains(mockT.errorString(), "Expected the request body to not contain 'World'. But it did.") assert.True(HTTPBodyContains(mockT, httpReadBody, "GET", "/", nil, "hello")) } func TestHttpBodyWrappers(t *testing.T) { t.Parallel() assert := New(t) mockAssert := New(new(testing.T)) assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) } ================================================ FILE: assert/internal/unsafetests/doc.go ================================================ // This package exists just to isolate tests that reference the [unsafe] package. // // The tests in this package are totally safe. package unsafetests ================================================ FILE: assert/internal/unsafetests/unsafetests_test.go ================================================ package unsafetests_test import ( "fmt" "testing" "unsafe" "github.com/stretchr/testify/assert" ) type ignoreTestingT struct{} var _ assert.TestingT = ignoreTestingT{} func (ignoreTestingT) Helper() {} func (ignoreTestingT) Errorf(format string, args ...interface{}) { // Run the formatting, but ignore the result msg := fmt.Sprintf(format, args...) _ = msg } func TestUnsafePointers(t *testing.T) { var ignore ignoreTestingT assert.True(t, assert.Nil(t, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil")) assert.False(t, assert.NotNil(ignore, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil")) assert.True(t, assert.Nil(t, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil")) assert.False(t, assert.NotNil(ignore, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil")) assert.False(t, assert.Nil(ignore, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil")) assert.True(t, assert.NotNil(t, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil")) } ================================================ FILE: assert/yaml/yaml_custom.go ================================================ //go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default // Package yaml is an implementation of YAML functions that calls a pluggable implementation. // // This implementation is selected with the testify_yaml_custom build tag. // // go test -tags testify_yaml_custom // // This implementation can be used at build time to replace the default implementation // to avoid linking with [gopkg.in/yaml.v3]. // // In your test package: // // import assertYaml "github.com/stretchr/testify/assert/yaml" // // func init() { // assertYaml.Unmarshal = func (in []byte, out interface{}) error { // // ... // return nil // } // } package yaml var Unmarshal func(in []byte, out interface{}) error ================================================ FILE: assert/yaml/yaml_default.go ================================================ //go:build !testify_yaml_fail && !testify_yaml_custom // Package yaml is just an indirection to handle YAML deserialization. // // This package is just an indirection that allows the builder to override the // indirection with an alternative implementation of this package that uses // another implementation of YAML deserialization. This allows to not either not // use YAML deserialization at all, or to use another implementation than // [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]). // // Alternative implementations are selected using build tags: // // - testify_yaml_fail: [Unmarshal] always fails with an error // - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it // before calling any of [github.com/stretchr/testify/assert.YAMLEq] or // [github.com/stretchr/testify/assert.YAMLEqf]. // // Usage: // // go test -tags testify_yaml_fail // // You can check with "go list" which implementation is linked: // // go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml // go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml // go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml // // [PR #1120]: https://github.com/stretchr/testify/pull/1120 package yaml import goyaml "gopkg.in/yaml.v3" // Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. func Unmarshal(in []byte, out interface{}) error { return goyaml.Unmarshal(in, out) } ================================================ FILE: assert/yaml/yaml_fail.go ================================================ //go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default // Package yaml is an implementation of YAML functions that always fail. // // This implementation can be used at build time to replace the default implementation // to avoid linking with [gopkg.in/yaml.v3]: // // go test -tags testify_yaml_fail package yaml import "errors" var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)") func Unmarshal([]byte, interface{}) error { return errNotImplemented } ================================================ FILE: doc.go ================================================ // Module testify is a set of packages that provide many tools for testifying that your code will behave as you intend. // // Testify contains the following packages: // // The [github.com/stretchr/testify/assert] package provides a comprehensive set of assertion functions that tie in to [the Go testing system]. // The [github.com/stretchr/testify/require] package provides the same assertions but as fatal checks. // // The [github.com/stretchr/testify/mock] package provides a system by which it is possible to mock your objects and verify calls are happening as expected. // // The [github.com/stretchr/testify/suite] package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces. // // A [golangci-lint] compatible linter for testify is available called [testifylint]. // // [the Go testing system]: https://go.dev/doc/code#Testing // [golangci-lint]: https://golangci-lint.run/ // [testifylint]: https://github.com/Antonboom/testifylint package testify ================================================ FILE: go.mod ================================================ module github.com/stretchr/testify // This should match the minimum supported version that is tested in // .github/workflows/main.yml go 1.17 require ( github.com/stretchr/objx v0.5.2 // To avoid a cycle the version of testify used by objx should be excluded below gopkg.in/yaml.v3 v3.0.1 ) // Break dependency cycle with objx. // See https://github.com/stretchr/objx/pull/140 exclude github.com/stretchr/testify v1.8.4 ================================================ FILE: go.sum ================================================ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= ================================================ FILE: http/doc.go ================================================ // Deprecated: Use [net/http/httptest] instead. package http ================================================ FILE: http/test_response_writer.go ================================================ package http import ( "net/http" ) // Deprecated: Use [net/http/httptest] instead. type TestResponseWriter struct { // StatusCode is the last int written by the call to WriteHeader(int) StatusCode int // Output is a string containing the written bytes using the Write([]byte) func. Output string // header is the internal storage of the http.Header object header http.Header } // Deprecated: Use [net/http/httptest] instead. func (rw *TestResponseWriter) Header() http.Header { if rw.header == nil { rw.header = make(http.Header) } return rw.header } // Deprecated: Use [net/http/httptest] instead. func (rw *TestResponseWriter) Write(bytes []byte) (int, error) { // assume 200 success if no header has been set if rw.StatusCode == 0 { rw.WriteHeader(200) } // add these bytes to the output string rw.Output += string(bytes) // return normal values return 0, nil } // Deprecated: Use [net/http/httptest] instead. func (rw *TestResponseWriter) WriteHeader(i int) { rw.StatusCode = i } ================================================ FILE: http/test_round_tripper.go ================================================ package http import ( "net/http" "github.com/stretchr/testify/mock" ) // Deprecated: Use [net/http/httptest] instead. type TestRoundTripper struct { mock.Mock } // Deprecated: Use [net/http/httptest] instead. func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { args := t.Called(req) return args.Get(0).(*http.Response), args.Error(1) } ================================================ FILE: internal/difflib/LICENSE ================================================ Copyright (c) 2013, Patrick Mezard All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: internal/difflib/difflib.go ================================================ // Package difflib is a partial port of Python difflib module. // // It provides tools to compare sequences of strings and generate textual diffs. // // The following class and functions have been ported: // // - SequenceMatcher // // - unified_diff // // Getting unified diffs was the main goal of the port. Keep in mind this code // is mostly suitable to output text differences in a human friendly way, there // are no guarantees generated diffs are consumable by patch(1). // // This package was adopted from [github.com/pmezard/go-difflib] which // is no longer maintained. // // [github.com/pmezard/go-difflib]: https://github.com/pmezard/go-difflib package difflib import ( "bufio" "bytes" "fmt" "io" "strings" ) func min(a, b int) int { if a < b { return a } return b } func max(a, b int) int { if a > b { return a } return b } type Match struct { A int B int Size int } type OpCode struct { Tag byte I1 int I2 int J1 int J2 int } // SequenceMatcher compares sequence of strings. The basic // algorithm predates, and is a little fancier than, an algorithm // published in the late 1980's by Ratcliff and Obershelp under the // hyperbolic name "gestalt pattern matching". The basic idea is to find // the longest contiguous matching subsequence that contains no "junk" // elements (R-O doesn't address junk). The same idea is then applied // recursively to the pieces of the sequences to the left and to the right // of the matching subsequence. This does not yield minimal edit // sequences, but does tend to yield matches that "look right" to people. // // SequenceMatcher tries to compute a "human-friendly diff" between two // sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the // longest *contiguous* & junk-free matching subsequence. That's what // catches peoples' eyes. The Windows(tm) windiff has another interesting // notion, pairing up elements that appear uniquely in each sequence. // That, and the method here, appear to yield more intuitive difference // reports than does diff. This method appears to be the least vulnerable // to synching up on blocks of "junk lines", though (like blank lines in // ordinary text files, or maybe "

" lines in HTML files). That may be // because this is the only method of the 3 that has a *concept* of // "junk" . // // Timing: Basic R-O is cubic time worst case and quadratic time expected // case. SequenceMatcher is quadratic time for the worst case and has // expected-case behavior dependent in a complicated way on how many // elements the sequences have in common; best case time is linear. type SequenceMatcher struct { a []string b []string b2j map[string][]int IsJunk func(string) bool autoJunk bool bJunk map[string]struct{} matchingBlocks []Match fullBCount map[string]int bPopular map[string]struct{} opCodes []OpCode } func NewMatcher(a, b []string) *SequenceMatcher { m := SequenceMatcher{autoJunk: true} m.SetSeqs(a, b) return &m } // Set two sequences to be compared. func (m *SequenceMatcher) SetSeqs(a, b []string) { m.SetSeq1(a) m.SetSeq2(b) } // Set the first sequence to be compared. The second sequence to be compared is // not changed. // // SequenceMatcher computes and caches detailed information about the second // sequence, so if you want to compare one sequence S against many sequences, // use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other // sequences. // // See also SetSeqs() and SetSeq2(). func (m *SequenceMatcher) SetSeq1(a []string) { if &a == &m.a { return } m.a = a m.matchingBlocks = nil m.opCodes = nil } // Set the second sequence to be compared. The first sequence to be compared is // not changed. func (m *SequenceMatcher) SetSeq2(b []string) { if &b == &m.b { return } m.b = b m.matchingBlocks = nil m.opCodes = nil m.fullBCount = nil m.chainB() } func (m *SequenceMatcher) chainB() { // Populate line -> index mapping b2j := map[string][]int{} for i, s := range m.b { indices := b2j[s] indices = append(indices, i) b2j[s] = indices } // Purge junk elements m.bJunk = map[string]struct{}{} if m.IsJunk != nil { junk := m.bJunk for s, _ := range b2j { if m.IsJunk(s) { junk[s] = struct{}{} } } for s, _ := range junk { delete(b2j, s) } } // Purge remaining popular elements popular := map[string]struct{}{} n := len(m.b) if m.autoJunk && n >= 200 { ntest := n/100 + 1 for s, indices := range b2j { if len(indices) > ntest { popular[s] = struct{}{} } } for s, _ := range popular { delete(b2j, s) } } m.bPopular = popular m.b2j = b2j } func (m *SequenceMatcher) isBJunk(s string) bool { _, ok := m.bJunk[s] return ok } // Find longest matching block in a[alo:ahi] and b[blo:bhi]. // // If IsJunk is not defined: // // Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where // // alo <= i <= i+k <= ahi // blo <= j <= j+k <= bhi // // and for all (i',j',k') meeting those conditions, // // k >= k' // i <= i' // and if i == i', j <= j' // // In other words, of all maximal matching blocks, return one that // starts earliest in a, and of all those maximal matching blocks that // start earliest in a, return the one that starts earliest in b. // // If IsJunk is defined, first the longest matching block is // determined as above, but with the additional restriction that no // junk element appears in the block. Then that block is extended as // far as possible by matching (only) junk elements on both sides. So // the resulting block never matches on junk except as identical junk // happens to be adjacent to an "interesting" match. // // If no blocks match, return (alo, blo, 0). func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { // CAUTION: stripping common prefix or suffix would be incorrect. // E.g., // ab // acab // Longest matching block is "ab", but if common prefix is // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so // strip, so ends up claiming that ab is changed to acab by // inserting "ca" in the middle. That's minimal but unintuitive: // "it's obvious" that someone inserted "ac" at the front. // Windiff ends up at the same place as diff, but by pairing up // the unique 'b's and then matching the first two 'a's. besti, bestj, bestsize := alo, blo, 0 // find longest junk-free match // during an iteration of the loop, j2len[j] = length of longest // junk-free match ending with a[i-1] and b[j] j2len := map[int]int{} for i := alo; i != ahi; i++ { // look at all instances of a[i] in b; note that because // b2j has no junk keys, the loop is skipped if a[i] is junk newj2len := map[int]int{} for _, j := range m.b2j[m.a[i]] { // a[i] matches b[j] if j < blo { continue } if j >= bhi { break } k := j2len[j-1] + 1 newj2len[j] = k if k > bestsize { besti, bestj, bestsize = i-k+1, j-k+1, k } } j2len = newj2len } // Extend the best by non-junk elements on each end. In particular, // "popular" non-junk elements aren't in b2j, which greatly speeds // the inner loop above, but also means "the best" match so far // doesn't contain any junk *or* popular non-junk elements. for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && m.a[besti-1] == m.b[bestj-1] { besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 } for besti+bestsize < ahi && bestj+bestsize < bhi && !m.isBJunk(m.b[bestj+bestsize]) && m.a[besti+bestsize] == m.b[bestj+bestsize] { bestsize += 1 } // Now that we have a wholly interesting match (albeit possibly // empty!), we may as well suck up the matching junk on each // side of it too. Can't think of a good reason not to, and it // saves post-processing the (possibly considerable) expense of // figuring out what to do with it. In the case of an empty // interesting match, this is clearly the right thing to do, // because no other kind of match is possible in the regions. for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && m.a[besti-1] == m.b[bestj-1] { besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 } for besti+bestsize < ahi && bestj+bestsize < bhi && m.isBJunk(m.b[bestj+bestsize]) && m.a[besti+bestsize] == m.b[bestj+bestsize] { bestsize += 1 } return Match{A: besti, B: bestj, Size: bestsize} } // Return list of triples describing matching subsequences. // // Each triple is of the form (i, j, n), and means that // a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in // i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are // adjacent triples in the list, and the second is not the last triple in the // list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe // adjacent equal blocks. // // The last triple is a dummy, (len(a), len(b), 0), and is the only // triple with n==0. func (m *SequenceMatcher) GetMatchingBlocks() []Match { if m.matchingBlocks != nil { return m.matchingBlocks } var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { match := m.findLongestMatch(alo, ahi, blo, bhi) i, j, k := match.A, match.B, match.Size if match.Size > 0 { if alo < i && blo < j { matched = matchBlocks(alo, i, blo, j, matched) } matched = append(matched, match) if i+k < ahi && j+k < bhi { matched = matchBlocks(i+k, ahi, j+k, bhi, matched) } } return matched } matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) // It's possible that we have adjacent equal blocks in the // matching_blocks list now. nonAdjacent := []Match{} i1, j1, k1 := 0, 0, 0 for _, b := range matched { // Is this block adjacent to i1, j1, k1? i2, j2, k2 := b.A, b.B, b.Size if i1+k1 == i2 && j1+k1 == j2 { // Yes, so collapse them -- this just increases the length of // the first block by the length of the second, and the first // block so lengthened remains the block to compare against. k1 += k2 } else { // Not adjacent. Remember the first block (k1==0 means it's // the dummy we started with), and make the second block the // new block to compare against. if k1 > 0 { nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) } i1, j1, k1 = i2, j2, k2 } } if k1 > 0 { nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) } nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) m.matchingBlocks = nonAdjacent return m.matchingBlocks } // Return list of 5-tuples describing how to turn a into b. // // Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple // has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the // tuple preceding it, and likewise for j1 == the previous j2. // // The tags are characters, with these meanings: // // 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] // // 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. // // 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. // // 'e' (equal): a[i1:i2] == b[j1:j2] func (m *SequenceMatcher) GetOpCodes() []OpCode { if m.opCodes != nil { return m.opCodes } i, j := 0, 0 matching := m.GetMatchingBlocks() opCodes := make([]OpCode, 0, len(matching)) for _, m := range matching { // invariant: we've pumped out correct diffs to change // a[:i] into b[:j], and the next matching block is // a[ai:ai+size] == b[bj:bj+size]. So we need to pump // out a diff to change a[i:ai] into b[j:bj], pump out // the matching block, and move (i,j) beyond the match ai, bj, size := m.A, m.B, m.Size tag := byte(0) if i < ai && j < bj { tag = 'r' } else if i < ai { tag = 'd' } else if j < bj { tag = 'i' } if tag > 0 { opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) } i, j = ai+size, bj+size // the list of matching blocks is terminated by a // sentinel with size 0 if size > 0 { opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) } } m.opCodes = opCodes return m.opCodes } // Isolate change clusters by eliminating ranges with no changes. // // Return a generator of groups with up to n lines of context. // Each group is in the same format as returned by GetOpCodes(). func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { if n < 0 { n = 3 } codes := m.GetOpCodes() if len(codes) == 0 { codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} } // Fixup leading and trailing groups if they show no changes. if codes[0].Tag == 'e' { c := codes[0] i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} } if codes[len(codes)-1].Tag == 'e' { c := codes[len(codes)-1] i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} } nn := n + n groups := [][]OpCode{} group := []OpCode{} for _, c := range codes { i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 // End the current group and start a new one whenever // there is a large range with no changes. if c.Tag == 'e' && i2-i1 > nn { group = append(group, OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}) groups = append(groups, group) group = []OpCode{} i1, j1 = max(i1, i2-n), max(j1, j2-n) } group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) } if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { groups = append(groups, group) } return groups } // Convert range to the "ed" format func formatRangeUnified(start, stop int) string { // Per the diff spec at http://www.unix.org/single_unix_specification/ beginning := start + 1 // lines start numbering with one length := stop - start if length == 1 { return fmt.Sprintf("%d", beginning) } if length == 0 { beginning -= 1 // empty ranges begin at line just before the range } return fmt.Sprintf("%d,%d", beginning, length) } // Unified diff parameters type UnifiedDiff struct { A []string // First sequence lines FromFile string // First file name FromDate string // First file time B []string // Second sequence lines ToFile string // Second file name ToDate string // Second file time Eol string // Headers end of line, defaults to LF Context int // Number of context lines } // Compare two sequences of lines; generate the delta as a unified diff. // // Unified diffs are a compact way of showing line changes and a few // lines of context. The number of context lines is set by 'n' which // defaults to three. // // By default, the diff control lines (those with ---, +++, or @@) are // created with a trailing newline. This is helpful so that inputs // created from file.readlines() result in diffs that are suitable for // file.writelines() since both the inputs and outputs have trailing // newlines. // // For inputs that do not have trailing newlines, set the lineterm // argument to "" so that the output will be uniformly newline free. // // The unidiff format normally has a header for filenames and modification // times. Any or all of these may be specified using strings for // 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. // The modification times are normally expressed in the ISO 8601 format. func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { buf := bufio.NewWriter(writer) defer buf.Flush() wf := func(format string, args ...interface{}) error { _, err := buf.WriteString(fmt.Sprintf(format, args...)) return err } ws := func(s string) error { _, err := buf.WriteString(s) return err } if len(diff.Eol) == 0 { diff.Eol = "\n" } started := false m := NewMatcher(diff.A, diff.B) for _, g := range m.GetGroupedOpCodes(diff.Context) { if !started { started = true fromDate := "" if len(diff.FromDate) > 0 { fromDate = "\t" + diff.FromDate } toDate := "" if len(diff.ToDate) > 0 { toDate = "\t" + diff.ToDate } if diff.FromFile != "" || diff.ToFile != "" { err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) if err != nil { return err } err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) if err != nil { return err } } } first, last := g[0], g[len(g)-1] range1 := formatRangeUnified(first.I1, last.I2) range2 := formatRangeUnified(first.J1, last.J2) if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { return err } for _, c := range g { i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 if c.Tag == 'e' { for _, line := range diff.A[i1:i2] { if err := ws(" " + line); err != nil { return err } } continue } if c.Tag == 'r' || c.Tag == 'd' { for _, line := range diff.A[i1:i2] { if err := ws("-" + line); err != nil { return err } } } if c.Tag == 'r' || c.Tag == 'i' { for _, line := range diff.B[j1:j2] { if err := ws("+" + line); err != nil { return err } } } } } return nil } // Like WriteUnifiedDiff but returns the diff a string. func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { w := &bytes.Buffer{} err := WriteUnifiedDiff(w, diff) return string(w.Bytes()), err } // Convert range to the "ed" format. func formatRangeContext(start, stop int) string { // Per the diff spec at http://www.unix.org/single_unix_specification/ beginning := start + 1 // lines start numbering with one length := stop - start if length == 0 { beginning -= 1 // empty ranges begin at line just before the range } if length <= 1 { return fmt.Sprintf("%d", beginning) } return fmt.Sprintf("%d,%d", beginning, beginning+length-1) } // Split a string on "\n" while preserving them. The output can be used // as input for UnifiedDiff and ContextDiff structures. func SplitLines(s string) []string { lines := strings.SplitAfter(s, "\n") lines[len(lines)-1] += "\n" return lines } ================================================ FILE: internal/difflib/difflib_test.go ================================================ package difflib import ( "bytes" "fmt" "math" "reflect" "strings" "testing" ) func assertAlmostEqual(t *testing.T, a, b float64, places int) { if math.Abs(a-b) > math.Pow10(-places) { t.Errorf("%.7f != %.7f", a, b) } } func assertEqual(t *testing.T, a, b interface{}) { if !reflect.DeepEqual(a, b) { t.Errorf("%v != %v", a, b) } } func splitChars(s string) []string { chars := make([]string, 0, len(s)) // Assume ASCII inputs for i := 0; i != len(s); i++ { chars = append(chars, string(s[i])) } return chars } func TestGetOptCodes(t *testing.T) { a := "qabxcd" b := "abycdf" s := NewMatcher(splitChars(a), splitChars(b)) w := &bytes.Buffer{} for _, op := range s.GetOpCodes() { fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag), op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2]) } result := string(w.Bytes()) expected := `d a[0:1], (q) b[0:0] () e a[1:3], (ab) b[0:2] (ab) r a[3:4], (x) b[2:3] (y) e a[4:6], (cd) b[3:5] (cd) i a[6:6], () b[5:6] (f) ` if expected != result { t.Errorf("unexpected op codes: \n%s", result) } } func TestGroupedOpCodes(t *testing.T) { a := []string{} for i := 0; i != 39; i++ { a = append(a, fmt.Sprintf("%02d", i)) } b := []string{} b = append(b, a[:8]...) b = append(b, " i") b = append(b, a[8:19]...) b = append(b, " x") b = append(b, a[20:22]...) b = append(b, a[27:34]...) b = append(b, " y") b = append(b, a[35:]...) s := NewMatcher(a, b) w := &bytes.Buffer{} for _, g := range s.GetGroupedOpCodes(-1) { fmt.Fprintf(w, "group\n") for _, op := range g { fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag), op.I1, op.I2, op.J1, op.J2) } } result := string(w.Bytes()) expected := `group e, 5, 8, 5, 8 i, 8, 8, 8, 9 e, 8, 11, 9, 12 group e, 16, 19, 17, 20 r, 19, 20, 20, 21 e, 20, 22, 21, 23 d, 22, 27, 23, 23 e, 27, 30, 23, 26 group e, 31, 34, 27, 30 r, 34, 35, 30, 31 e, 35, 38, 31, 34 ` if expected != result { t.Errorf("unexpected op codes: \n%s", result) } } func rep(s string, count int) string { return strings.Repeat(s, count) } func TestWithAsciiOneInsert(t *testing.T) { sm := NewMatcher(splitChars(rep("b", 100)), splitChars("a"+rep("b", 100))) assertEqual(t, sm.GetOpCodes(), []OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}}) assertEqual(t, len(sm.bPopular), 0) sm = NewMatcher(splitChars(rep("b", 100)), splitChars(rep("b", 50)+"a"+rep("b", 50))) assertEqual(t, sm.GetOpCodes(), []OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}}) assertEqual(t, len(sm.bPopular), 0) } func TestWithAsciiOnDelete(t *testing.T) { sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)), splitChars(rep("a", 40)+rep("b", 40))) assertEqual(t, sm.GetOpCodes(), []OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}}) } func TestSFBugsComparingEmptyLists(t *testing.T) { groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1) assertEqual(t, len(groups), 0) diff := UnifiedDiff{ FromFile: "Original", ToFile: "Current", Context: 3, } result, err := GetUnifiedDiffString(diff) assertEqual(t, err, nil) assertEqual(t, result, "") } func TestOutputFormatRangeFormatUnified(t *testing.T) { // Per the diff spec at http://www.unix.org/single_unix_specification/ // // Each field shall be of the form: // %1d", if the range contains exactly one line, // and: // "%1d,%1d", , otherwise. // If a range is empty, its beginning line number shall be the number of // the line just before the range, or 0 if the empty range starts the file. fm := formatRangeUnified assertEqual(t, fm(3, 3), "3,0") assertEqual(t, fm(3, 4), "4") assertEqual(t, fm(3, 5), "4,2") assertEqual(t, fm(3, 6), "4,3") assertEqual(t, fm(0, 0), "0,0") } func TestOutputFormatRangeFormatContext(t *testing.T) { // Per the diff spec at http://www.unix.org/single_unix_specification/ // // The range of lines in file1 shall be written in the following format // if the range contains two or more lines: // "*** %d,%d ****\n", , // and the following format otherwise: // "*** %d ****\n", // The ending line number of an empty range shall be the number of the preceding line, // or 0 if the range is at the start of the file. // // Next, the range of lines in file2 shall be written in the following format // if the range contains two or more lines: // "--- %d,%d ----\n", , // and the following format otherwise: // "--- %d ----\n", fm := formatRangeContext assertEqual(t, fm(3, 3), "3") assertEqual(t, fm(3, 4), "4") assertEqual(t, fm(3, 5), "4,5") assertEqual(t, fm(3, 6), "4,6") assertEqual(t, fm(0, 0), "0") } func TestOutputFormatTabDelimiter(t *testing.T) { diff := UnifiedDiff{ A: splitChars("one"), B: splitChars("two"), FromFile: "Original", FromDate: "2005-01-26 23:30:50", ToFile: "Current", ToDate: "2010-04-12 10:20:52", Eol: "\n", } ud, err := GetUnifiedDiffString(diff) assertEqual(t, err, nil) assertEqual(t, SplitLines(ud)[:2], []string{ "--- Original\t2005-01-26 23:30:50\n", "+++ Current\t2010-04-12 10:20:52\n", }) } func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) { diff := UnifiedDiff{ A: splitChars("one"), B: splitChars("two"), FromFile: "Original", ToFile: "Current", Eol: "\n", } ud, err := GetUnifiedDiffString(diff) assertEqual(t, err, nil) assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"}) } func TestOmitFilenames(t *testing.T) { diff := UnifiedDiff{ A: SplitLines("o\nn\ne\n"), B: SplitLines("t\nw\no\n"), Eol: "\n", } ud, err := GetUnifiedDiffString(diff) assertEqual(t, err, nil) assertEqual(t, SplitLines(ud), []string{ "@@ -0,0 +1,2 @@\n", "+t\n", "+w\n", "@@ -2,2 +3,0 @@\n", "-n\n", "-e\n", "\n", }) } func TestSplitLines(t *testing.T) { allTests := []struct { input string want []string }{ {"foo", []string{"foo\n"}}, {"foo\nbar", []string{"foo\n", "bar\n"}}, {"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}}, } for _, test := range allTests { assertEqual(t, SplitLines(test.input), test.want) } } func benchmarkSplitLines(b *testing.B, count int) { str := strings.Repeat("foo\n", count) b.ResetTimer() n := 0 for i := 0; i < b.N; i++ { n += len(SplitLines(str)) } } func BenchmarkSplitLines100(b *testing.B) { benchmarkSplitLines(b, 100) } func BenchmarkSplitLines10000(b *testing.B) { benchmarkSplitLines(b, 10000) } ================================================ FILE: internal/spew/LICENSE ================================================ ISC License Copyright (c) 2012-2016 Dave Collins Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: internal/spew/README.md ================================================ go-spew ======= [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) Go-spew implements a deep pretty printer for Go data structures to aid in debugging. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. ## License Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. ================================================ FILE: internal/spew/bypass.go ================================================ // Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is not running on Google App Engine, compiled by GopherJS, and // "-tags safe" is not added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. // Go versions prior to 1.4 are disabled because they use a different layout // for interfaces which make the implementation of unsafeReflectValue more complex. //go:build !js && !appengine && !safe && !disableunsafe && go1.4 // +build !js,!appengine,!safe,!disableunsafe,go1.4 package spew import ( "reflect" "unsafe" ) const ( // UnsafeDisabled is a build-time constant which specifies whether or // not access to the unsafe package is available. UnsafeDisabled = false // ptrSize is the size of a pointer on the current arch. ptrSize = unsafe.Sizeof((*byte)(nil)) ) type flag uintptr var ( // flagRO indicates whether the value field of a reflect.Value // is read-only. flagRO flag // flagAddr indicates whether the address of the reflect.Value's // value may be taken. flagAddr flag ) // flagKindMask holds the bits that make up the kind // part of the flags field. In all the supported versions, // it is in the lower 5 bits. const flagKindMask = flag(0x1f) // Different versions of Go have used different // bit layouts for the flags type. This table // records the known combinations. var okFlags = []struct { ro, addr flag }{{ // From Go 1.4 to 1.5 ro: 1 << 5, addr: 1 << 7, }, { // Up to Go tip. ro: 1<<5 | 1<<6, addr: 1 << 8, }} var flagValOffset = func() uintptr { field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") if !ok { panic("reflect.Value has no flag field") } return field.Offset }() // flagField returns a pointer to the flag field of a reflect.Value. func flagField(v *reflect.Value) *flag { return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) } // unsafeReflectValue converts the passed reflect.Value into a one that bypasses // the typical safety restrictions preventing access to unaddressable and // unexported data. It works by digging the raw pointer to the underlying // value out of the protected value and generating a new unprotected (unsafe) // reflect.Value to it. // // This allows us to check for implementations of the Stringer and error // interfaces to be used for pretty printing ordinarily unaddressable and // inaccessible values such as unexported struct fields. func unsafeReflectValue(v reflect.Value) reflect.Value { if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { return v } flagFieldPtr := flagField(&v) *flagFieldPtr &^= flagRO *flagFieldPtr |= flagAddr return v } // Sanity checks against future reflect package changes // to the type or semantics of the Value.flag field. func init() { field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") if !ok { panic("reflect.Value has no flag field") } if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { panic("reflect.Value flag field has changed kind") } type t0 int var t struct { A t0 // t0 will have flagEmbedRO set. t0 // a will have flagStickyRO set a t0 } vA := reflect.ValueOf(t).FieldByName("A") va := reflect.ValueOf(t).FieldByName("a") vt0 := reflect.ValueOf(t).FieldByName("t0") // Infer flagRO from the difference between the flags // for the (otherwise identical) fields in t. flagPublic := *flagField(&vA) flagWithRO := *flagField(&va) | *flagField(&vt0) flagRO = flagPublic ^ flagWithRO // Infer flagAddr from the difference between a value // taken from a pointer and not. vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") flagNoPtr := *flagField(&vA) flagPtr := *flagField(&vPtrA) flagAddr = flagNoPtr ^ flagPtr // Check that the inferred flags tally with one of the known versions. for _, f := range okFlags { if flagRO == f.ro && flagAddr == f.addr { return } } panic("reflect.Value read-only flag has changed semantics") } ================================================ FILE: internal/spew/bypasssafe.go ================================================ // Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is running on Google App Engine, compiled by GopherJS, or // "-tags safe" is added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. //go:build js || appengine || safe || disableunsafe || !go1.4 // +build js appengine safe disableunsafe !go1.4 package spew import "reflect" const ( // UnsafeDisabled is a build-time constant which specifies whether or // not access to the unsafe package is available. UnsafeDisabled = true ) // unsafeReflectValue typically converts the passed reflect.Value into a one // that bypasses the typical safety restrictions preventing access to // unaddressable and unexported data. However, doing this relies on access to // the unsafe package. This is a stub version which simply returns the passed // reflect.Value when the unsafe package is not available. func unsafeReflectValue(v reflect.Value) reflect.Value { return v } ================================================ FILE: internal/spew/common.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew import ( "bytes" "fmt" "io" "reflect" "sort" "strconv" ) // Some constants in the form of bytes to avoid string overhead. This mirrors // the technique used in the fmt package. var ( panicBytes = []byte("(PANIC=") plusBytes = []byte("+") iBytes = []byte("i") trueBytes = []byte("true") falseBytes = []byte("false") interfaceBytes = []byte("(interface {})") commaNewlineBytes = []byte(",\n") newlineBytes = []byte("\n") openBraceBytes = []byte("{") openBraceNewlineBytes = []byte("{\n") closeBraceBytes = []byte("}") asteriskBytes = []byte("*") colonBytes = []byte(":") colonSpaceBytes = []byte(": ") openParenBytes = []byte("(") closeParenBytes = []byte(")") spaceBytes = []byte(" ") pointerChainBytes = []byte("->") nilAngleBytes = []byte("") maxNewlineBytes = []byte("\n") maxShortBytes = []byte("") circularBytes = []byte("") circularShortBytes = []byte("") invalidAngleBytes = []byte("") openBracketBytes = []byte("[") closeBracketBytes = []byte("]") percentBytes = []byte("%") precisionBytes = []byte(".") openAngleBytes = []byte("<") closeAngleBytes = []byte(">") openMapBytes = []byte("map[") closeMapBytes = []byte("]") lenEqualsBytes = []byte("len=") capEqualsBytes = []byte("cap=") ) // hexDigits is used to map a decimal value to a hex digit. var hexDigits = "0123456789abcdef" // catchPanic handles any panics that might occur during the handleMethods // calls. func catchPanic(w io.Writer, v reflect.Value) { if err := recover(); err != nil { w.Write(panicBytes) fmt.Fprintf(w, "%v", err) w.Write(closeParenBytes) } } // handleMethods attempts to call the Error and String methods on the underlying // type the passed reflect.Value represents and outputes the result to Writer w. // // It handles panics in any called methods by catching and displaying the error // as the formatted value. func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { // We need an interface to check if the type implements the error or // Stringer interface. However, the reflect package won't give us an // interface on certain things like unexported struct fields in order // to enforce visibility rules. We use unsafe, when it's available, // to bypass these restrictions since this package does not mutate the // values. if !v.CanInterface() { if UnsafeDisabled { return false } v = unsafeReflectValue(v) } // Choose whether or not to do error and Stringer interface lookups against // the base type or a pointer to the base type depending on settings. // Technically calling one of these methods with a pointer receiver can // mutate the value, however, types which choose to satisify an error or // Stringer interface with a pointer receiver should not be mutating their // state inside these interface methods. if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { v = unsafeReflectValue(v) } if v.CanAddr() { v = v.Addr() } // Is it an error or Stringer? switch iface := v.Interface().(type) { case error: defer catchPanic(w, v) if cs.ContinueOnMethod { w.Write(openParenBytes) w.Write([]byte(iface.Error())) w.Write(closeParenBytes) w.Write(spaceBytes) return false } w.Write([]byte(iface.Error())) return true case fmt.Stringer: defer catchPanic(w, v) if cs.ContinueOnMethod { w.Write(openParenBytes) w.Write([]byte(iface.String())) w.Write(closeParenBytes) w.Write(spaceBytes) return false } w.Write([]byte(iface.String())) return true } return false } // printBool outputs a boolean value as true or false to Writer w. func printBool(w io.Writer, val bool) { if val { w.Write(trueBytes) } else { w.Write(falseBytes) } } // printInt outputs a signed integer value to Writer w. func printInt(w io.Writer, val int64, base int) { w.Write([]byte(strconv.FormatInt(val, base))) } // printUint outputs an unsigned integer value to Writer w. func printUint(w io.Writer, val uint64, base int) { w.Write([]byte(strconv.FormatUint(val, base))) } // printFloat outputs a floating point value using the specified precision, // which is expected to be 32 or 64bit, to Writer w. func printFloat(w io.Writer, val float64, precision int) { w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) } // printComplex outputs a complex value using the specified float precision // for the real and imaginary parts to Writer w. func printComplex(w io.Writer, c complex128, floatPrecision int) { r := real(c) w.Write(openParenBytes) w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) i := imag(c) if i >= 0 { w.Write(plusBytes) } w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) w.Write(iBytes) w.Write(closeParenBytes) } // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' // prefix to Writer w. func printHexPtr(w io.Writer, p uintptr) { // Null pointer. num := uint64(p) if num == 0 { w.Write(nilAngleBytes) return } // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix buf := make([]byte, 18) // It's simpler to construct the hex string right to left. base := uint64(16) i := len(buf) - 1 for num >= base { buf[i] = hexDigits[num%base] num /= base i-- } buf[i] = hexDigits[num] // Add '0x' prefix. i-- buf[i] = 'x' i-- buf[i] = '0' // Strip unused leading bytes. buf = buf[i:] w.Write(buf) } // valuesSorter implements sort.Interface to allow a slice of reflect.Value // elements to be sorted. type valuesSorter struct { values []reflect.Value strings []string // either nil or same len and values cs *ConfigState } // newValuesSorter initializes a valuesSorter instance, which holds a set of // surrogate keys on which the data should be sorted. It uses flags in // ConfigState to decide if and how to populate those surrogate keys. func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { vs := &valuesSorter{values: values, cs: cs} if canSortSimply(vs.values[0].Kind()) { return vs } if !cs.DisableMethods { vs.strings = make([]string, len(values)) for i := range vs.values { b := bytes.Buffer{} if !handleMethods(cs, &b, vs.values[i]) { vs.strings = nil break } vs.strings[i] = b.String() } } if vs.strings == nil && cs.SpewKeys { vs.strings = make([]string, len(values)) for i := range vs.values { vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) } } return vs } // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted // directly, or whether it should be considered for sorting by surrogate keys // (if the ConfigState allows it). func canSortSimply(kind reflect.Kind) bool { // This switch parallels valueSortLess, except for the default case. switch kind { case reflect.Bool: return true case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: return true case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: return true case reflect.Float32, reflect.Float64: return true case reflect.String: return true case reflect.Uintptr: return true case reflect.Array: return true } return false } // Len returns the number of values in the slice. It is part of the // sort.Interface implementation. func (s *valuesSorter) Len() int { return len(s.values) } // Swap swaps the values at the passed indices. It is part of the // sort.Interface implementation. func (s *valuesSorter) Swap(i, j int) { s.values[i], s.values[j] = s.values[j], s.values[i] if s.strings != nil { s.strings[i], s.strings[j] = s.strings[j], s.strings[i] } } // valueSortLess returns whether the first value should sort before the second // value. It is used by valueSorter.Less as part of the sort.Interface // implementation. func valueSortLess(a, b reflect.Value) bool { switch a.Kind() { case reflect.Bool: return !a.Bool() && b.Bool() case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: return a.Int() < b.Int() case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: return a.Uint() < b.Uint() case reflect.Float32, reflect.Float64: return a.Float() < b.Float() case reflect.String: return a.String() < b.String() case reflect.Uintptr: return a.Uint() < b.Uint() case reflect.Array: // Compare the contents of both arrays. l := a.Len() for i := 0; i < l; i++ { av := a.Index(i) bv := b.Index(i) if av.Interface() == bv.Interface() { continue } return valueSortLess(av, bv) } } return a.String() < b.String() } // Less returns whether the value at index i should sort before the // value at index j. It is part of the sort.Interface implementation. func (s *valuesSorter) Less(i, j int) bool { if s.strings == nil { return valueSortLess(s.values[i], s.values[j]) } return s.strings[i] < s.strings[j] } // sortValues is a sort function that handles both native types and any type that // can be converted to error or Stringer. Other inputs are sorted according to // their Value.String() value to ensure display stability. func sortValues(values []reflect.Value, cs *ConfigState) { if len(values) == 0 { return } sort.Sort(newValuesSorter(values, cs)) } ================================================ FILE: internal/spew/common_test.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew_test import ( "fmt" "reflect" "testing" "github.com/stretchr/testify/internal/spew" ) // custom type to test Stinger interface on non-pointer receiver. type stringer string // String implements the Stringer interface for testing invocation of custom // stringers on types with non-pointer receivers. func (s stringer) String() string { return "stringer " + string(s) } // custom type to test Stinger interface on pointer receiver. type pstringer string // String implements the Stringer interface for testing invocation of custom // stringers on types with only pointer receivers. func (s *pstringer) String() string { return "stringer " + string(*s) } // xref1 and xref2 are cross referencing structs for testing circular reference // detection. type xref1 struct { ps2 *xref2 } type xref2 struct { ps1 *xref1 } // indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular // reference for testing detection. type indirCir1 struct { ps2 *indirCir2 } type indirCir2 struct { ps3 *indirCir3 } type indirCir3 struct { ps1 *indirCir1 } // embed is used to test embedded structures. type embed struct { a string } // embedwrap is used to test embedded structures. type embedwrap struct { *embed e *embed } // panicer is used to intentionally cause a panic for testing spew properly // handles them type panicer int func (p panicer) String() string { panic("test panic") } // customError is used to test custom error interface invocation. type customError int func (e customError) Error() string { return fmt.Sprintf("error: %d", int(e)) } // stringizeWants converts a slice of wanted test output into a format suitable // for a test error message. func stringizeWants(wants []string) string { s := "" for i, want := range wants { if i > 0 { s += fmt.Sprintf("want%d: %s", i+1, want) } else { s += "want: " + want } } return s } // testFailed returns whether or not a test failed by checking if the result // of the test is in the slice of wanted strings. func testFailed(result string, wants []string) bool { for _, want := range wants { if result == want { return false } } return true } type sortableStruct struct { x int } func (ss sortableStruct) String() string { return fmt.Sprintf("ss.%d", ss.x) } type unsortableStruct struct { x int } type sortTestCase struct { input []reflect.Value expected []reflect.Value } func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { getInterfaces := func(values []reflect.Value) []interface{} { interfaces := []interface{}{} for _, v := range values { interfaces = append(interfaces, v.Interface()) } return interfaces } for _, test := range tests { spew.SortValues(test.input, cs) // reflect.DeepEqual cannot really make sense of reflect.Value, // probably because of all the pointer tricks. For instance, // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} // instead. input := getInterfaces(test.input) expected := getInterfaces(test.expected) if !reflect.DeepEqual(input, expected) { t.Errorf("Sort mismatch:\n %v != %v", input, expected) } } } // TestSortValues ensures the sort functionality for relect.Value based sorting // works as intended. func TestSortValues(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") embedA := v(embed{"a"}) embedB := v(embed{"b"}) embedC := v(embed{"c"}) tests := []sortTestCase{ // No values. { []reflect.Value{}, []reflect.Value{}, }, // Bools. { []reflect.Value{v(false), v(true), v(false)}, []reflect.Value{v(false), v(false), v(true)}, }, // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Uints. { []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, }, // Floats. { []reflect.Value{v(2.0), v(1.0), v(3.0)}, []reflect.Value{v(1.0), v(2.0), v(3.0)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // Array { []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, }, // Uintptrs. { []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, }, // SortableStructs. { // Note: not sorted - DisableMethods is set. []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, }, // UnsortableStructs. { // Note: not sorted - SpewKeys is false. []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, }, // Invalid. { []reflect.Value{embedB, embedA, embedC}, []reflect.Value{embedB, embedA, embedC}, }, } cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} helpTestSortValues(tests, &cs, t) } // TestSortValuesWithMethods ensures the sort functionality for relect.Value // based sorting works as intended when using string methods. func TestSortValuesWithMethods(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") tests := []sortTestCase{ // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // SortableStructs. { []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, }, // UnsortableStructs. { // Note: not sorted - SpewKeys is false. []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, }, } cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} helpTestSortValues(tests, &cs, t) } // TestSortValuesWithSpew ensures the sort functionality for relect.Value // based sorting works as intended when using spew to stringify keys. func TestSortValuesWithSpew(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") tests := []sortTestCase{ // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // SortableStructs. { []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, }, // UnsortableStructs. { []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, }, } cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} helpTestSortValues(tests, &cs, t) } ================================================ FILE: internal/spew/config.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew import ( "bytes" "fmt" "io" "os" ) // ConfigState houses the configuration options used by spew to format and // display values. There is a global instance, Config, that is used to control // all top-level Formatter and Dump functionality. Each ConfigState instance // provides methods equivalent to the top-level functions. // // The zero value for ConfigState provides no indentation. You would typically // want to set it to a space or a tab. // // Alternatively, you can use NewDefaultConfig to get a ConfigState instance // with default settings. See the documentation of NewDefaultConfig for default // values. type ConfigState struct { // Indent specifies the string to use for each indentation level. The // global config instance that all top-level functions use set this to a // single space by default. If you would like more indentation, you might // set this to a tab with "\t" or perhaps two spaces with " ". Indent string // MaxDepth controls the maximum number of levels to descend into nested // data structures. The default, 0, means there is no limit. // // NOTE: Circular data structures are properly detected, so it is not // necessary to set this value unless you specifically want to limit deeply // nested data structures. MaxDepth int // DisableMethods specifies whether or not error and Stringer interfaces are // invoked for types that implement them. DisableMethods bool // DisablePointerMethods specifies whether or not to check for and invoke // error and Stringer interfaces on types which only accept a pointer // receiver when the current type is not a pointer. // // NOTE: This might be an unsafe action since calling one of these methods // with a pointer receiver could technically mutate the value, however, // in practice, types which choose to satisify an error or Stringer // interface with a pointer receiver should not be mutating their state // inside these interface methods. As a result, this option relies on // access to the unsafe package, so it will not have any effect when // running in environments without access to the unsafe package such as // Google App Engine or with the "safe" build tag specified. DisablePointerMethods bool // DisablePointerAddresses specifies whether to disable the printing of // pointer addresses. This is useful when diffing data structures in tests. DisablePointerAddresses bool // DisableCapacities specifies whether to disable the printing of capacities // for arrays, slices, maps and channels. This is useful when diffing // data structures in tests. DisableCapacities bool // ContinueOnMethod specifies whether or not recursion should continue once // a custom error or Stringer interface is invoked. The default, false, // means it will print the results of invoking the custom error or Stringer // interface and return immediately instead of continuing to recurse into // the internals of the data type. // // NOTE: This flag does not have any effect if method invocation is disabled // via the DisableMethods or DisablePointerMethods options. ContinueOnMethod bool // SortKeys specifies map keys should be sorted before being printed. Use // this to have a more deterministic, diffable output. Note that only // native types (bool, int, uint, floats, uintptr and string) and types // that support the error or Stringer interfaces (if methods are // enabled) are supported, with other types sorted according to the // reflect.Value.String() output which guarantees display stability. SortKeys bool // SpewKeys specifies that, as a last resort attempt, map keys should // be spewed to strings and sorted by those strings. This is only // considered if SortKeys is true. SpewKeys bool } // Config is the active configuration of the top-level functions. // The configuration can be changed by modifying the contents of spew.Config. var Config = ConfigState{Indent: " "} // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the formatted string as a value that satisfies error. See NewFormatter // for formatting details. // // This function is shorthand for the following syntax: // // fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { return fmt.Errorf(format, c.convertArgs(a)...) } // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprint(w, c.convertArgs(a)...) } // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(w, format, c.convertArgs(a)...) } // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it // passed with a Formatter interface returned by c.NewFormatter. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprintln(w, c.convertArgs(a)...) } // Print is a wrapper for fmt.Print that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Print(a ...interface{}) (n int, err error) { return fmt.Print(c.convertArgs(a)...) } // Printf is a wrapper for fmt.Printf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { return fmt.Printf(format, c.convertArgs(a)...) } // Println is a wrapper for fmt.Println that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Println(a ...interface{}) (n int, err error) { return fmt.Println(c.convertArgs(a)...) } // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprint(a ...interface{}) string { return fmt.Sprint(c.convertArgs(a)...) } // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprintf(format string, a ...interface{}) string { return fmt.Sprintf(format, c.convertArgs(a)...) } // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it // were passed with a Formatter interface returned by c.NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprintln(a ...interface{}) string { return fmt.Sprintln(c.convertArgs(a)...) } /* NewFormatter returns a custom formatter that satisfies the fmt.Formatter interface. As a result, it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). Typically this function shouldn't be called directly. It is much easier to make use of the custom formatter by calling one of the convenience functions such as c.Printf, c.Println, or c.Printf. */ func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { return newFormatter(c, v) } // Fdump formats and displays the passed arguments to io.Writer w. It formats // exactly the same as Dump. func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { fdump(c, w, a...) } /* Dump displays the passed parameters to standard out with newlines, customizable indentation, and additional debug information such as complete types and all pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: - Pointers are dereferenced and followed - Circular data structures are detected and handled properly - Custom Stringer/error interfaces are optionally invoked, including on unexported types - Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables - Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output The configuration options are controlled by modifying the public members of c. See ConfigState for options documentation. See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to get the formatted result as a string. */ func (c *ConfigState) Dump(a ...interface{}) { fdump(c, os.Stdout, a...) } // Sdump returns a string with the passed arguments formatted exactly the same // as Dump. func (c *ConfigState) Sdump(a ...interface{}) string { var buf bytes.Buffer fdump(c, &buf, a...) return buf.String() } // convertArgs accepts a slice of arguments and returns a slice of the same // length with each argument converted to a spew Formatter interface using // the ConfigState associated with s. func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { formatters = make([]interface{}, len(args)) for index, arg := range args { formatters[index] = newFormatter(c, arg) } return formatters } // NewDefaultConfig returns a ConfigState with the following default settings. // // Indent: " " // MaxDepth: 0 // DisableMethods: false // DisablePointerMethods: false // ContinueOnMethod: false // SortKeys: false func NewDefaultConfig() *ConfigState { return &ConfigState{Indent: " "} } ================================================ FILE: internal/spew/doc.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Package spew implements a deep pretty printer for Go data structures to aid in debugging. A quick overview of the additional features spew provides over the built-in printing facilities for Go data types are as follows: - Pointers are dereferenced and followed - Circular data structures are detected and handled properly - Custom Stringer/error interfaces are optionally invoked, including on unexported types - Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables - Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output (only when using Dump style) There are two different approaches spew allows for dumping Go data structures: - Dump style which prints with newlines, customizable indentation, and additional debug information such as types and all pointer addresses used to indirect to the final value - A custom Formatter interface that integrates cleanly with the standard fmt package and replaces %v, %+v, %#v, and %#+v to provide inline printing similar to the default %v while providing the additional functionality outlined above and passing unsupported format verbs such as %x and %q along to fmt # Quick Start This section demonstrates how to quickly get started with spew. See the sections below for further details on formatting and configuration options. To dump a variable with full newlines, indentation, type, and pointer information use Dump, Fdump, or Sdump: spew.Dump(myVar1, myVar2, ...) spew.Fdump(someWriter, myVar1, myVar2, ...) str := spew.Sdump(myVar1, myVar2, ...) Alternatively, if you would prefer to use format strings with a compacted inline printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses): spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) # Configuration Options Configuration of spew is handled by fields in the ConfigState type. For convenience, all of the top-level functions use a global state available via the spew.Config global. It is also possible to create a ConfigState instance that provides methods equivalent to the top-level functions. This allows concurrent configuration options. See the ConfigState documentation for more details. The following configuration options are available: - Indent String to use for each indentation level for Dump functions. It is a single space by default. A popular alternative is "\t". - MaxDepth Maximum number of levels to descend into nested data structures. There is no limit by default. - DisableMethods Disables invocation of error and Stringer interface methods. Method invocation is enabled by default. - DisablePointerMethods Disables invocation of error and Stringer interface methods on types which only accept pointer receivers from non-pointer variables. Pointer method invocation is enabled by default. - DisablePointerAddresses DisablePointerAddresses specifies whether to disable the printing of pointer addresses. This is useful when diffing data structures in tests. - DisableCapacities DisableCapacities specifies whether to disable the printing of capacities for arrays, slices, maps and channels. This is useful when diffing data structures in tests. - ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. - SortKeys Specifies map keys should be sorted before being printed. Use this to have a more deterministic, diffable output. Note that only native types (bool, int, uint, floats, uintptr and string) and types which implement error or Stringer interfaces are supported with other types sorted according to the reflect.Value.String() output which guarantees display stability. Natural map order is used by default. - SpewKeys Specifies that, as a last resort attempt, map keys should be spewed to strings and sorted by those strings. This is only considered if SortKeys is true. # Dump Usage Simply call spew.Dump with a list of variables you want to dump: spew.Dump(myVar1, myVar2, ...) You may also call spew.Fdump if you would prefer to output to an arbitrary io.Writer. For example, to dump to standard error: spew.Fdump(os.Stderr, myVar1, myVar2, ...) A third option is to call spew.Sdump to get the formatted output as a string: str := spew.Sdump(myVar1, myVar2, ...) # Sample Dump Output See the Dump example for details on the setup of the types and variables being shown here. (main.Foo) { unexportedField: (*main.Bar)(0xf84002e210)({ flag: (main.Flag) flagTwo, data: (uintptr) }), ExportedField: (map[interface {}]interface {}) (len=1) { (string) (len=3) "one": (bool) true } } Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C command as shown. ([]uint8) (len=32 cap=32) { 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 00000020 31 32 |12| } # Custom Formatter Spew provides a custom formatter that implements the fmt.Formatter interface so that it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). # Custom Formatter Usage The simplest way to make use of the spew custom formatter is to call one of the convenience functions such as spew.Printf, spew.Println, or spew.Printf. The functions have syntax you are most likely already familiar with: spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Println(myVar, myVar2) spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) See the Index for the full list convenience functions. # Sample Formatter Output Double pointer to a uint8: %v: <**>5 %+v: <**>(0xf8400420d0->0xf8400420c8)5 %#v: (**uint8)5 %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 Pointer to circular struct with a uint8 field and a pointer to itself: %v: <*>{1 <*>} %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} See the Printf example for details on the setup of variables being shown here. # Errors Since it is possible for custom Stringer/error interfaces to panic, spew detects them and handles them internally by printing the panic information inline with the output. Since spew is intended to provide deep pretty printing capabilities on structures, it intentionally does not return any errors. */ package spew ================================================ FILE: internal/spew/dump.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew import ( "bytes" "encoding/hex" "fmt" "io" "os" "reflect" "regexp" "strconv" "strings" ) var ( // uint8Type is a reflect.Type representing a uint8. It is used to // convert cgo types to uint8 slices for hexdumping. uint8Type = reflect.TypeOf(uint8(0)) // cCharRE is a regular expression that matches a cgo char. // It is used to detect character arrays to hexdump them. cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) // cUnsignedCharRE is a regular expression that matches a cgo unsigned // char. It is used to detect unsigned character arrays to hexdump // them. cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) // cUint8tCharRE is a regular expression that matches a cgo uint8_t. // It is used to detect uint8_t arrays to hexdump them. cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) ) // dumpState contains information about the state of a dump operation. type dumpState struct { w io.Writer depth int pointers map[uintptr]int ignoreNextType bool ignoreNextIndent bool cs *ConfigState } // indent performs indentation according to the depth level and cs.Indent // option. func (d *dumpState) indent() { if d.ignoreNextIndent { d.ignoreNextIndent = false return } d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) } // unpackValue returns values inside of non-nil interfaces when possible. // This is useful for data types like structs, arrays, slices, and maps which // can contain varying types packed inside an interface. func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { if v.Kind() == reflect.Interface && !v.IsNil() { v = v.Elem() } return v } // dumpPtr handles formatting of pointers by indirecting them as necessary. func (d *dumpState) dumpPtr(v reflect.Value) { // Remove pointers at or below the current depth from map used to detect // circular refs. for k, depth := range d.pointers { if depth >= d.depth { delete(d.pointers, k) } } // Keep list of all dereferenced pointers to show later. pointerChain := make([]uintptr, 0) // Figure out how many levels of indirection there are by dereferencing // pointers and unpacking interfaces down the chain while detecting circular // references. nilFound := false cycleFound := false indirects := 0 ve := v for ve.Kind() == reflect.Ptr { if ve.IsNil() { nilFound = true break } indirects++ addr := ve.Pointer() pointerChain = append(pointerChain, addr) if pd, ok := d.pointers[addr]; ok && pd < d.depth { cycleFound = true indirects-- break } d.pointers[addr] = d.depth ve = ve.Elem() if ve.Kind() == reflect.Interface { if ve.IsNil() { nilFound = true break } ve = ve.Elem() } } // Display type information. d.w.Write(openParenBytes) d.w.Write(bytes.Repeat(asteriskBytes, indirects)) d.w.Write([]byte(ve.Type().String())) d.w.Write(closeParenBytes) // Display pointer information. if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { d.w.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { d.w.Write(pointerChainBytes) } printHexPtr(d.w, addr) } d.w.Write(closeParenBytes) } // Display dereferenced value. d.w.Write(openParenBytes) switch { case nilFound: d.w.Write(nilAngleBytes) case cycleFound: d.w.Write(circularBytes) default: d.ignoreNextType = true d.dump(ve) } d.w.Write(closeParenBytes) } // dumpSlice handles formatting of arrays and slices. Byte (uint8 under // reflection) arrays and slices are dumped in hexdump -C fashion. func (d *dumpState) dumpSlice(v reflect.Value) { // Determine whether this type should be hex dumped or not. Also, // for types which should be hexdumped, try to use the underlying data // first, then fall back to trying to convert them to a uint8 slice. var buf []uint8 doConvert := false doHexDump := false numEntries := v.Len() if numEntries > 0 { vt := v.Index(0).Type() vts := vt.String() switch { // C types that need to be converted. case cCharRE.MatchString(vts): fallthrough case cUnsignedCharRE.MatchString(vts): fallthrough case cUint8tCharRE.MatchString(vts): doConvert = true // Try to use existing uint8 slices and fall back to converting // and copying if that fails. case vt.Kind() == reflect.Uint8: // We need an addressable interface to convert the type // to a byte slice. However, the reflect package won't // give us an interface on certain things like // unexported struct fields in order to enforce // visibility rules. We use unsafe, when available, to // bypass these restrictions since this package does not // mutate the values. vs := v if !vs.CanInterface() || !vs.CanAddr() { vs = unsafeReflectValue(vs) } if !UnsafeDisabled { vs = vs.Slice(0, numEntries) // Use the existing uint8 slice if it can be // type asserted. iface := vs.Interface() if slice, ok := iface.([]uint8); ok { buf = slice doHexDump = true break } } // The underlying data needs to be converted if it can't // be type asserted to a uint8 slice. doConvert = true } // Copy and convert the underlying type if needed. if doConvert && vt.ConvertibleTo(uint8Type) { // Convert and copy each element into a uint8 byte // slice. buf = make([]uint8, numEntries) for i := 0; i < numEntries; i++ { vv := v.Index(i) buf[i] = uint8(vv.Convert(uint8Type).Uint()) } doHexDump = true } } // Hexdump the entire slice as needed. if doHexDump { indent := strings.Repeat(d.cs.Indent, d.depth) str := indent + hex.Dump(buf) str = strings.Replace(str, "\n", "\n"+indent, -1) str = strings.TrimRight(str, d.cs.Indent) d.w.Write([]byte(str)) return } // Recursively call dump for each item. for i := 0; i < numEntries; i++ { d.dump(d.unpackValue(v.Index(i))) if i < (numEntries - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } // dump is the main workhorse for dumping a value. It uses the passed reflect // value to figure out what kind of object we are dealing with and formats it // appropriately. It is a recursive function, however circular data structures // are detected and handled properly. func (d *dumpState) dump(v reflect.Value) { // Handle invalid reflect values immediately. kind := v.Kind() if kind == reflect.Invalid { d.w.Write(invalidAngleBytes) return } // Handle pointers specially. if kind == reflect.Ptr { d.indent() d.dumpPtr(v) return } // Print type information unless already handled elsewhere. if !d.ignoreNextType { d.indent() d.w.Write(openParenBytes) d.w.Write([]byte(v.Type().String())) d.w.Write(closeParenBytes) d.w.Write(spaceBytes) } d.ignoreNextType = false // Display length and capacity if the built-in len and cap functions // work with the value's kind and the len/cap itself is non-zero. valueLen, valueCap := 0, 0 switch v.Kind() { case reflect.Array, reflect.Slice, reflect.Chan: valueLen, valueCap = v.Len(), v.Cap() case reflect.Map, reflect.String: valueLen = v.Len() } if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { d.w.Write(openParenBytes) if valueLen != 0 { d.w.Write(lenEqualsBytes) printInt(d.w, int64(valueLen), 10) } if !d.cs.DisableCapacities && valueCap != 0 { if valueLen != 0 { d.w.Write(spaceBytes) } d.w.Write(capEqualsBytes) printInt(d.w, int64(valueCap), 10) } d.w.Write(closeParenBytes) d.w.Write(spaceBytes) } // Call Stringer/error interfaces if they exist and the handle methods flag // is enabled if !d.cs.DisableMethods { if (kind != reflect.Invalid) && (kind != reflect.Interface) { if handled := handleMethods(d.cs, d.w, v); handled { return } } } switch kind { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. case reflect.Bool: printBool(d.w, v.Bool()) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: printInt(d.w, v.Int(), 10) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: printUint(d.w, v.Uint(), 10) case reflect.Float32: printFloat(d.w, v.Float(), 32) case reflect.Float64: printFloat(d.w, v.Float(), 64) case reflect.Complex64: printComplex(d.w, v.Complex(), 32) case reflect.Complex128: printComplex(d.w, v.Complex(), 64) case reflect.Slice: if v.IsNil() { d.w.Write(nilAngleBytes) break } fallthrough case reflect.Array: d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { d.dumpSlice(v) } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.String: d.w.Write([]byte(strconv.Quote(v.String()))) case reflect.Interface: // The only time we should get here is for nil interfaces due to // unpackValue calls. if v.IsNil() { d.w.Write(nilAngleBytes) } case reflect.Ptr: // Do nothing. We should never get here since pointers have already // been handled above. case reflect.Map: // nil maps should be indicated as different than empty maps if v.IsNil() { d.w.Write(nilAngleBytes) break } d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { numEntries := v.Len() keys := v.MapKeys() if d.cs.SortKeys { sortValues(keys, d.cs) } for i, key := range keys { d.dump(d.unpackValue(key)) d.w.Write(colonSpaceBytes) d.ignoreNextIndent = true d.dump(d.unpackValue(v.MapIndex(key))) if i < (numEntries - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.Struct: d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { vt := v.Type() numFields := v.NumField() for i := 0; i < numFields; i++ { d.indent() vtf := vt.Field(i) d.w.Write([]byte(vtf.Name)) d.w.Write(colonSpaceBytes) d.ignoreNextIndent = true d.dump(d.unpackValue(v.Field(i))) if i < (numFields - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.Uintptr: printHexPtr(d.w, uintptr(v.Uint())) case reflect.UnsafePointer, reflect.Chan, reflect.Func: printHexPtr(d.w, v.Pointer()) // There were not any other types at the time this code was written, but // fall back to letting the default fmt package handle it in case any new // types are added. default: if v.CanInterface() { fmt.Fprintf(d.w, "%v", v.Interface()) } else { fmt.Fprintf(d.w, "%v", v.String()) } } } // fdump is a helper function to consolidate the logic from the various public // methods which take varying writers and config states. func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { for _, arg := range a { if arg == nil { w.Write(interfaceBytes) w.Write(spaceBytes) w.Write(nilAngleBytes) w.Write(newlineBytes) continue } d := dumpState{w: w, cs: cs} d.pointers = make(map[uintptr]int) d.dump(reflect.ValueOf(arg)) d.w.Write(newlineBytes) } } // Fdump formats and displays the passed arguments to io.Writer w. It formats // exactly the same as Dump. func Fdump(w io.Writer, a ...interface{}) { fdump(&Config, w, a...) } // Sdump returns a string with the passed arguments formatted exactly the same // as Dump. func Sdump(a ...interface{}) string { var buf bytes.Buffer fdump(&Config, &buf, a...) return buf.String() } /* Dump displays the passed parameters to standard out with newlines, customizable indentation, and additional debug information such as complete types and all pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: - Pointers are dereferenced and followed - Circular data structures are detected and handled properly - Custom Stringer/error interfaces are optionally invoked, including on unexported types - Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables - Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output The configuration options are controlled by an exported package global, spew.Config. See ConfigState for options documentation. See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to get the formatted result as a string. */ func Dump(a ...interface{}) { fdump(&Config, os.Stdout, a...) } ================================================ FILE: internal/spew/dump_test.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Test Summary: NOTE: For each test, a nil pointer, a single pointer and double pointer to the base test element are also tested to ensure proper indirection across all types. - Max int8, int16, int32, int64, int - Max uint8, uint16, uint32, uint64, uint - Boolean true and false - Standard complex64 and complex128 - Array containing standard ints - Array containing type with custom formatter on pointer receiver only - Array containing interfaces - Array containing bytes - Slice containing standard float32 values - Slice containing type with custom formatter on pointer receiver only - Slice containing interfaces - Slice containing bytes - Nil slice - Standard string - Nil interface - Sub-interface - Map with string keys and int vals - Map with custom formatter type on pointer receiver only keys and vals - Map with interface keys and values - Map with nil interface value - Struct with primitives - Struct that contains another struct - Struct that contains custom type with Stringer pointer interface via both exported and unexported fields - Struct that contains embedded struct and field to same struct - Uintptr to 0 (null pointer) - Uintptr address of real variable - Unsafe.Pointer to 0 (null pointer) - Unsafe.Pointer to address of real variable - Nil channel - Standard int channel - Function with no params and no returns - Function with param and no returns - Function with multiple params and multiple returns - Struct that is circular through self referencing - Structs that are circular through cross referencing - Structs that are indirectly circular - Type that panics in its Stringer interface */ package spew_test import ( "bytes" "fmt" "testing" "unsafe" "github.com/stretchr/testify/internal/spew" ) // dumpTest is used to describe a test to be performed against the Dump method. type dumpTest struct { in interface{} wants []string } // dumpTests houses all of the tests to be performed against the Dump method. var dumpTests = make([]dumpTest, 0) // addDumpTest is a helper method to append the passed input and desired result // to dumpTests func addDumpTest(in interface{}, wants ...string) { test := dumpTest{in, wants} dumpTests = append(dumpTests, test) } func addIntDumpTests() { // Max int8. v := int8(127) nv := (*int8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "int8" vs := "127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Max int16. v2 := int16(32767) nv2 := (*int16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "int16" v2s := "32767" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Max int32. v3 := int32(2147483647) nv3 := (*int32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "int32" v3s := "2147483647" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Max int64. v4 := int64(9223372036854775807) nv4 := (*int64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "int64" v4s := "9223372036854775807" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Max int. v5 := int(2147483647) nv5 := (*int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "int" v5s := "2147483647" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addUintDumpTests() { // Max uint8. v := uint8(255) nv := (*uint8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uint8" vs := "255" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Max uint16. v2 := uint16(65535) nv2 := (*uint16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Max uint32. v3 := uint32(4294967295) nv3 := (*uint32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "uint32" v3s := "4294967295" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Max uint64. v4 := uint64(18446744073709551615) nv4 := (*uint64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "uint64" v4s := "18446744073709551615" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Max uint. v5 := uint(4294967295) nv5 := (*uint)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "uint" v5s := "4294967295" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addBoolDumpTests() { // Boolean true. v := bool(true) nv := (*bool)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "bool" vs := "true" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Boolean false. v2 := bool(false) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "bool" v2s := "false" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addFloatDumpTests() { // Standard float32. v := float32(3.1415) nv := (*float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "float32" vs := "3.1415" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Standard float64. v2 := float64(3.1415926) nv2 := (*float64)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "float64" v2s := "3.1415926" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addComplexDumpTests() { // Standard complex64. v := complex(float32(6), -2) nv := (*complex64)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "complex64" vs := "(6-2i)" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Standard complex128. v2 := complex(float64(-6), 2) nv2 := (*complex128)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "complex128" v2s := "(-6+2i)" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addArrayDumpTests() { // Array containing standard ints. v := [3]int{1, 2, 3} vLen := fmt.Sprintf("%d", len(v)) vCap := fmt.Sprintf("%d", cap(v)) nv := (*[3]int)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "int" vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + vt + ") 2,\n (" + vt + ") 3\n}" addDumpTest(v, "([3]"+vt+") "+vs+"\n") addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*[3]"+vt+")()\n") // Array containing type with custom formatter on pointer receiver only. v2i0 := pstringer("1") v2i1 := pstringer("2") v2i2 := pstringer("3") v2 := [3]pstringer{v2i0, v2i1, v2i2} v2i0Len := fmt.Sprintf("%d", len(v2i0)) v2i1Len := fmt.Sprintf("%d", len(v2i1)) v2i2Len := fmt.Sprintf("%d", len(v2i2)) v2Len := fmt.Sprintf("%d", len(v2)) v2Cap := fmt.Sprintf("%d", cap(v2)) nv2 := (*[3]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.pstringer" v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + "stringer 3\n}" v2s := v2sp if spew.UnsafeDisabled { v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" + v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len + ") " + "\"3\"\n}" } addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n") addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n") addDumpTest(nv2, "(*[3]"+v2t+")()\n") // Array containing interfaces. v3i0 := "one" v3 := [3]interface{}{v3i0, int(2), uint(3)} v3i0Len := fmt.Sprintf("%d", len(v3i0)) v3Len := fmt.Sprintf("%d", len(v3)) v3Cap := fmt.Sprintf("%d", cap(v3)) nv3 := (*[3]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[3]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 + ") 3\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Array containing bytes. v4 := [34]byte{ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, } v4Len := fmt.Sprintf("%d", len(v4)) v4Cap := fmt.Sprintf("%d", cap(v4)) nv4 := (*[34]byte)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[34]uint8" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + " |............... |\n" + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + " |!\"#$%&'()*+,-./0|\n" + " 00000020 31 32 " + " |12|\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") } func addSliceDumpTests() { // Slice containing standard float32 values. v := []float32{3.14, 6.28, 12.56} vLen := fmt.Sprintf("%d", len(v)) vCap := fmt.Sprintf("%d", cap(v)) nv := (*[]float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "float32" vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + vt + ") 6.28,\n (" + vt + ") 12.56\n}" addDumpTest(v, "([]"+vt+") "+vs+"\n") addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*[]"+vt+")()\n") // Slice containing type with custom formatter on pointer receiver only. v2i0 := pstringer("1") v2i1 := pstringer("2") v2i2 := pstringer("3") v2 := []pstringer{v2i0, v2i1, v2i2} v2i0Len := fmt.Sprintf("%d", len(v2i0)) v2i1Len := fmt.Sprintf("%d", len(v2i1)) v2i2Len := fmt.Sprintf("%d", len(v2i2)) v2Len := fmt.Sprintf("%d", len(v2)) v2Cap := fmt.Sprintf("%d", cap(v2)) nv2 := (*[]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.pstringer" v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + "stringer 3\n}" addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*[]"+v2t+")()\n") // Slice containing interfaces. v3i0 := "one" v3 := []interface{}{v3i0, int(2), uint(3), nil} v3i0Len := fmt.Sprintf("%d", len(v3i0)) v3Len := fmt.Sprintf("%d", len(v3)) v3Cap := fmt.Sprintf("%d", cap(v3)) nv3 := (*[]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3t5 := "interface {}" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 + ") 3,\n (" + v3t5 + ") \n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Slice containing bytes. v4 := []byte{ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, } v4Len := fmt.Sprintf("%d", len(v4)) v4Cap := fmt.Sprintf("%d", cap(v4)) nv4 := (*[]byte)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[]uint8" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + " |............... |\n" + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + " |!\"#$%&'()*+,-./0|\n" + " 00000020 31 32 " + " |12|\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Nil slice. v5 := []int(nil) nv5 := (*[]int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "[]int" v5s := "" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addStringDumpTests() { // Standard string. v := "test" vLen := fmt.Sprintf("%d", len(v)) nv := (*string)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "string" vs := "(len=" + vLen + ") \"test\"" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addInterfaceDumpTests() { // Nil interface. var v interface{} nv := (*interface{})(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "interface {}" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Sub-interface. v2 := interface{}(uint16(65535)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addMapDumpTests() { // Map with string keys and int vals. k := "one" kk := "two" m := map[string]int{k: 1, kk: 2} klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up kkLen := fmt.Sprintf("%d", len(kk)) mLen := fmt.Sprintf("%d", len(m)) nilMap := map[string]int(nil) nm := (*map[string]int)(nil) pm := &m mAddr := fmt.Sprintf("%p", pm) pmAddr := fmt.Sprintf("%p", &pm) mt := "map[string]int" mt1 := "string" mt2 := "int" ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + ") \"two\": (" + mt2 + ") 2\n}" ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + ") \"one\": (" + mt2 + ") 1\n}" addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", "(*"+mt+")("+mAddr+")("+ms2+")\n") addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") addDumpTest(nm, "(*"+mt+")()\n") addDumpTest(nilMap, "("+mt+") \n") // Map with custom formatter type on pointer receiver only keys and vals. k2 := pstringer("one") v2 := pstringer("1") m2 := map[pstringer]pstringer{k2: v2} k2Len := fmt.Sprintf("%d", len(k2)) v2Len := fmt.Sprintf("%d", len(v2)) m2Len := fmt.Sprintf("%d", len(m2)) nilMap2 := map[pstringer]pstringer(nil) nm2 := (*map[pstringer]pstringer)(nil) pm2 := &m2 m2Addr := fmt.Sprintf("%p", pm2) pm2Addr := fmt.Sprintf("%p", &pm2) m2t := "map[spew_test.pstringer]spew_test.pstringer" m2t1 := "spew_test.pstringer" m2t2 := "spew_test.pstringer" m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" if spew.UnsafeDisabled { m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len + ") \"1\"\n}" } addDumpTest(m2, "("+m2t+") "+m2s+"\n") addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") addDumpTest(nm2, "(*"+m2t+")()\n") addDumpTest(nilMap2, "("+m2t+") \n") // Map with interface keys and values. k3 := "one" k3Len := fmt.Sprintf("%d", len(k3)) m3 := map[interface{}]interface{}{k3: 1} m3Len := fmt.Sprintf("%d", len(m3)) nilMap3 := map[interface{}]interface{}(nil) nm3 := (*map[interface{}]interface{})(nil) pm3 := &m3 m3Addr := fmt.Sprintf("%p", pm3) pm3Addr := fmt.Sprintf("%p", &pm3) m3t := "map[interface {}]interface {}" m3t1 := "string" m3t2 := "int" m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + "\"one\": (" + m3t2 + ") 1\n}" addDumpTest(m3, "("+m3t+") "+m3s+"\n") addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") addDumpTest(nm3, "(*"+m3t+")()\n") addDumpTest(nilMap3, "("+m3t+") \n") // Map with nil interface value. k4 := "nil" k4Len := fmt.Sprintf("%d", len(k4)) m4 := map[string]interface{}{k4: nil} m4Len := fmt.Sprintf("%d", len(m4)) nilMap4 := map[string]interface{}(nil) nm4 := (*map[string]interface{})(nil) pm4 := &m4 m4Addr := fmt.Sprintf("%p", pm4) pm4Addr := fmt.Sprintf("%p", &pm4) m4t := "map[string]interface {}" m4t1 := "string" m4t2 := "interface {}" m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + " \"nil\": (" + m4t2 + ") \n}" addDumpTest(m4, "("+m4t+") "+m4s+"\n") addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") addDumpTest(nm4, "(*"+m4t+")()\n") addDumpTest(nilMap4, "("+m4t+") \n") } func addStructDumpTests() { // Struct with primitives. type s1 struct { a int8 b uint8 } v := s1{127, 255} nv := (*s1)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.s1" vt2 := "int8" vt3 := "uint8" vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Struct that contains another struct. type s2 struct { s1 s1 b bool } v2 := s2{s1{127, 255}, true} nv2 := (*s2)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.s2" v2t2 := "spew_test.s1" v2t3 := "int8" v2t4 := "uint8" v2t5 := "bool" v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Struct that contains custom type with Stringer pointer interface via both // exported and unexported fields. type s3 struct { s pstringer S pstringer } v3 := s3{"test", "test2"} nv3 := (*s3)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "spew_test.s3" v3t2 := "spew_test.pstringer" v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + ") (len=5) stringer test2\n}" v3sp := v3s if spew.UnsafeDisabled { v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + v3t2 + ") (len=5) \"test2\"\n}" v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + v3t2 + ") (len=5) stringer test2\n}" } addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Struct that contains embedded struct and field to same struct. e := embed{"embedstr"} eLen := fmt.Sprintf("%d", len("embedstr")) v4 := embedwrap{embed: &e, e: &e} nv4 := (*embedwrap)(nil) pv4 := &v4 eAddr := fmt.Sprintf("%p", &e) v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "spew_test.embedwrap" v4t2 := "spew_test.embed" v4t3 := "string" v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + " \"embedstr\"\n })\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") } func addUintptrDumpTests() { // Null pointer. v := uintptr(0) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uintptr" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") // Address of real variable. i := 1 v2 := uintptr(unsafe.Pointer(&i)) nv2 := (*uintptr)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uintptr" v2s := fmt.Sprintf("%p", &i) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addUnsafePointerDumpTests() { // Null pointer. v := unsafe.Pointer(nil) nv := (*unsafe.Pointer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "unsafe.Pointer" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Address of real variable. i := 1 v2 := unsafe.Pointer(&i) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "unsafe.Pointer" v2s := fmt.Sprintf("%p", &i) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addChanDumpTests() { // Nil channel. var v chan int pv := &v nv := (*chan int)(nil) vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "chan int" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Real channel. v2 := make(chan int) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "chan int" v2s := fmt.Sprintf("%p", v2) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addFuncDumpTests() { // Function with no params and no returns. v := addIntDumpTests nv := (*func())(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "func()" vs := fmt.Sprintf("%p", v) addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Function with param and no returns. v2 := TestDump nv2 := (*func(*testing.T))(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "func(*testing.T)" v2s := fmt.Sprintf("%p", v2) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Function with multiple params and multiple returns. var v3 = func(i int, s string) (b bool, err error) { return true, nil } nv3 := (*func(int, string) (bool, error))(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "func(int, string) (bool, error)" v3s := fmt.Sprintf("%p", v3) addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") } func addCircularDumpTests() { // Struct that is circular through self referencing. type circular struct { c *circular } v := circular{nil} v.c = &v pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.circular" vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + vAddr + ")()\n })\n}" vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") // Structs that are circular through cross referencing. v2 := xref1{nil} ts2 := xref2{&v2} v2.ps2 = &ts2 pv2 := &v2 ts2Addr := fmt.Sprintf("%p", &ts2) v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.xref1" v2t2 := "spew_test.xref2" v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")()\n })\n })\n}" v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + ")(" + v2Addr + ")()\n })\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") // Structs that are indirectly circular. v3 := indirCir1{nil} tic2 := indirCir2{nil} tic3 := indirCir3{&v3} tic2.ps3 = &tic3 v3.ps2 = &tic2 pv3 := &v3 tic2Addr := fmt.Sprintf("%p", &tic2) tic3Addr := fmt.Sprintf("%p", &tic3) v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "spew_test.indirCir1" v3t2 := "spew_test.indirCir2" v3t3 := "spew_test.indirCir3" v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")()\n })\n })\n })\n}" v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + ")()\n })\n })\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") } func addPanicDumpTests() { // Type that panics in its Stringer interface. v := panicer(127) nv := (*panicer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.panicer" vs := "(PANIC=test panic)127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addErrorDumpTests() { // Type that has a custom Error interface. v := customError(127) nv := (*customError)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.customError" vs := "error: 127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } // TestDump executes all of the tests described by dumpTests. func TestDump(t *testing.T) { // Setup tests. addIntDumpTests() addUintDumpTests() addBoolDumpTests() addFloatDumpTests() addComplexDumpTests() addArrayDumpTests() addSliceDumpTests() addStringDumpTests() addInterfaceDumpTests() addMapDumpTests() addStructDumpTests() addUintptrDumpTests() addUnsafePointerDumpTests() addChanDumpTests() addFuncDumpTests() addCircularDumpTests() addPanicDumpTests() addErrorDumpTests() addCgoDumpTests() t.Logf("Running %d tests", len(dumpTests)) for i, test := range dumpTests { buf := new(bytes.Buffer) spew.Fdump(buf, test.in) s := buf.String() if testFailed(s, test.wants) { t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) continue } } } func TestDumpSortedKeys(t *testing.T) { cfg := spew.ConfigState{SortKeys: true} s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " + "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " + "(len=1) \"3\"\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) expected = "(map[spew_test.stringer]int) (len=3) {\n" + "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" + "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" + "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) expected = "(map[spew_test.pstringer]int) (len=3) {\n" + "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" + "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" + "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" + "}\n" if spew.UnsafeDisabled { expected = "(map[spew_test.pstringer]int) (len=3) {\n" + "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" + "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" + "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" + "}\n" } if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) expected = "(map[spew_test.customError]int) (len=3) {\n" + "(spew_test.customError) error: 1: (int) 1,\n" + "(spew_test.customError) error: 2: (int) 2,\n" + "(spew_test.customError) error: 3: (int) 3\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } } ================================================ FILE: internal/spew/dumpcgo_test.go ================================================ // Copyright (c) 2013-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when both cgo is supported and "-tags testcgo" is added to the go test // command line. This means the cgo tests are only added (and hence run) when // specifially requested. This configuration is used because spew itself // does not require cgo to run even though it does handle certain cgo types // specially. Rather than forcing all clients to require cgo and an external // C compiler just to run the tests, this scheme makes them optional. // //go:build cgo && testcgo // +build cgo,testcgo package spew_test import ( "fmt" "github.com/stretchr/testify/internal/spew/testdata" ) func addCgoDumpTests() { // C char pointer. v := testdata.GetCgoCharPointer() nv := testdata.GetCgoNullCharPointer() pv := &v vcAddr := fmt.Sprintf("%p", v) vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "*testdata._Ctype_char" vs := "116" addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") addDumpTest(nv, "("+vt+")()\n") // C char array. v2, v2l, v2c := testdata.GetCgoCharArray() v2Len := fmt.Sprintf("%d", v2l) v2Cap := fmt.Sprintf("%d", v2c) v2t := "[6]testdata._Ctype_char" v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + "{\n 00000000 74 65 73 74 32 00 " + " |test2.|\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") // C unsigned char array. v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() v3Len := fmt.Sprintf("%d", v3l) v3Cap := fmt.Sprintf("%d", v3c) v3t := "[6]testdata._Ctype_unsignedchar" v3t2 := "[6]testdata._Ctype_uchar" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + "{\n 00000000 74 65 73 74 33 00 " + " |test3.|\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n") // C signed char array. v4, v4l, v4c := testdata.GetCgoSignedCharArray() v4Len := fmt.Sprintf("%d", v4l) v4Cap := fmt.Sprintf("%d", v4c) v4t := "[6]testdata._Ctype_schar" v4t2 := "testdata._Ctype_schar" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + ") 0\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") // C uint8_t array. v5, v5l, v5c := testdata.GetCgoUint8tArray() v5Len := fmt.Sprintf("%d", v5l) v5Cap := fmt.Sprintf("%d", v5c) v5t := "[6]testdata._Ctype_uint8_t" v5t2 := "[6]testdata._Ctype_uchar" v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + "{\n 00000000 74 65 73 74 35 00 " + " |test5.|\n}" addDumpTest(v5, "("+v5t+") "+v5s+"\n", "("+v5t2+") "+v5s+"\n") // C typedefed unsigned char array. v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() v6Len := fmt.Sprintf("%d", v6l) v6Cap := fmt.Sprintf("%d", v6c) v6t := "[6]testdata._Ctype_custom_uchar_t" v6t2 := "[6]testdata._Ctype_uchar" v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + "{\n 00000000 74 65 73 74 36 00 " + " |test6.|\n}" addDumpTest(v6, "("+v6t+") "+v6s+"\n", "("+v6t2+") "+v6s+"\n") } ================================================ FILE: internal/spew/dumpnocgo_test.go ================================================ // Copyright (c) 2013 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when either cgo is not supported or "-tags testcgo" is not added to the go // test command line. This file intentionally does not setup any cgo tests in // this scenario. //go:build !cgo || !testcgo // +build !cgo !testcgo package spew_test func addCgoDumpTests() { // Don't add any tests for cgo since this file is only compiled when // there should not be any cgo tests. } ================================================ FILE: internal/spew/format.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew import ( "bytes" "fmt" "reflect" "strconv" "strings" ) // supportedFlags is a list of all the character flags supported by fmt package. const supportedFlags = "0-+# " // formatState implements the fmt.Formatter interface and contains information // about the state of a formatting operation. The NewFormatter function can // be used to get a new Formatter which can be used directly as arguments // in standard fmt package printing calls. type formatState struct { value interface{} fs fmt.State depth int pointers map[uintptr]int ignoreNextType bool cs *ConfigState } // buildDefaultFormat recreates the original format string without precision // and width information to pass in to fmt.Sprintf in the case of an // unrecognized type. Unless new types are added to the language, this // function won't ever be called. func (f *formatState) buildDefaultFormat() (format string) { buf := bytes.NewBuffer(percentBytes) for _, flag := range supportedFlags { if f.fs.Flag(int(flag)) { buf.WriteRune(flag) } } buf.WriteRune('v') format = buf.String() return format } // constructOrigFormat recreates the original format string including precision // and width information to pass along to the standard fmt package. This allows // automatic deferral of all format strings this package doesn't support. func (f *formatState) constructOrigFormat(verb rune) (format string) { buf := bytes.NewBuffer(percentBytes) for _, flag := range supportedFlags { if f.fs.Flag(int(flag)) { buf.WriteRune(flag) } } if width, ok := f.fs.Width(); ok { buf.WriteString(strconv.Itoa(width)) } if precision, ok := f.fs.Precision(); ok { buf.Write(precisionBytes) buf.WriteString(strconv.Itoa(precision)) } buf.WriteRune(verb) format = buf.String() return format } // unpackValue returns values inside of non-nil interfaces when possible and // ensures that types for values which have been unpacked from an interface // are displayed when the show types flag is also set. // This is useful for data types like structs, arrays, slices, and maps which // can contain varying types packed inside an interface. func (f *formatState) unpackValue(v reflect.Value) reflect.Value { if v.Kind() == reflect.Interface { f.ignoreNextType = false if !v.IsNil() { v = v.Elem() } } return v } // formatPtr handles formatting of pointers by indirecting them as necessary. func (f *formatState) formatPtr(v reflect.Value) { // Display nil if top level pointer is nil. showTypes := f.fs.Flag('#') if v.IsNil() && (!showTypes || f.ignoreNextType) { f.fs.Write(nilAngleBytes) return } // Remove pointers at or below the current depth from map used to detect // circular refs. for k, depth := range f.pointers { if depth >= f.depth { delete(f.pointers, k) } } // Keep list of all dereferenced pointers to possibly show later. pointerChain := make([]uintptr, 0) // Figure out how many levels of indirection there are by derferencing // pointers and unpacking interfaces down the chain while detecting circular // references. nilFound := false cycleFound := false indirects := 0 ve := v for ve.Kind() == reflect.Ptr { if ve.IsNil() { nilFound = true break } indirects++ addr := ve.Pointer() pointerChain = append(pointerChain, addr) if pd, ok := f.pointers[addr]; ok && pd < f.depth { cycleFound = true indirects-- break } f.pointers[addr] = f.depth ve = ve.Elem() if ve.Kind() == reflect.Interface { if ve.IsNil() { nilFound = true break } ve = ve.Elem() } } // Display type or indirection level depending on flags. if showTypes && !f.ignoreNextType { f.fs.Write(openParenBytes) f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) f.fs.Write([]byte(ve.Type().String())) f.fs.Write(closeParenBytes) } else { if nilFound || cycleFound { indirects += strings.Count(ve.Type().String(), "*") } f.fs.Write(openAngleBytes) f.fs.Write([]byte(strings.Repeat("*", indirects))) f.fs.Write(closeAngleBytes) } // Display pointer information depending on flags. if f.fs.Flag('+') && (len(pointerChain) > 0) { f.fs.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { f.fs.Write(pointerChainBytes) } printHexPtr(f.fs, addr) } f.fs.Write(closeParenBytes) } // Display dereferenced value. switch { case nilFound: f.fs.Write(nilAngleBytes) case cycleFound: f.fs.Write(circularShortBytes) default: f.ignoreNextType = true f.format(ve) } } // format is the main workhorse for providing the Formatter interface. It // uses the passed reflect value to figure out what kind of object we are // dealing with and formats it appropriately. It is a recursive function, // however circular data structures are detected and handled properly. func (f *formatState) format(v reflect.Value) { // Handle invalid reflect values immediately. kind := v.Kind() if kind == reflect.Invalid { f.fs.Write(invalidAngleBytes) return } // Handle pointers specially. if kind == reflect.Ptr { f.formatPtr(v) return } // Print type information unless already handled elsewhere. if !f.ignoreNextType && f.fs.Flag('#') { f.fs.Write(openParenBytes) f.fs.Write([]byte(v.Type().String())) f.fs.Write(closeParenBytes) } f.ignoreNextType = false // Call Stringer/error interfaces if they exist and the handle methods // flag is enabled. if !f.cs.DisableMethods { if (kind != reflect.Invalid) && (kind != reflect.Interface) { if handled := handleMethods(f.cs, f.fs, v); handled { return } } } switch kind { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. case reflect.Bool: printBool(f.fs, v.Bool()) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: printInt(f.fs, v.Int(), 10) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: printUint(f.fs, v.Uint(), 10) case reflect.Float32: printFloat(f.fs, v.Float(), 32) case reflect.Float64: printFloat(f.fs, v.Float(), 64) case reflect.Complex64: printComplex(f.fs, v.Complex(), 32) case reflect.Complex128: printComplex(f.fs, v.Complex(), 64) case reflect.Slice: if v.IsNil() { f.fs.Write(nilAngleBytes) break } fallthrough case reflect.Array: f.fs.Write(openBracketBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { numEntries := v.Len() for i := 0; i < numEntries; i++ { if i > 0 { f.fs.Write(spaceBytes) } f.ignoreNextType = true f.format(f.unpackValue(v.Index(i))) } } f.depth-- f.fs.Write(closeBracketBytes) case reflect.String: f.fs.Write([]byte(v.String())) case reflect.Interface: // The only time we should get here is for nil interfaces due to // unpackValue calls. if v.IsNil() { f.fs.Write(nilAngleBytes) } case reflect.Ptr: // Do nothing. We should never get here since pointers have already // been handled above. case reflect.Map: // nil maps should be indicated as different than empty maps if v.IsNil() { f.fs.Write(nilAngleBytes) break } f.fs.Write(openMapBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { keys := v.MapKeys() if f.cs.SortKeys { sortValues(keys, f.cs) } for i, key := range keys { if i > 0 { f.fs.Write(spaceBytes) } f.ignoreNextType = true f.format(f.unpackValue(key)) f.fs.Write(colonBytes) f.ignoreNextType = true f.format(f.unpackValue(v.MapIndex(key))) } } f.depth-- f.fs.Write(closeMapBytes) case reflect.Struct: numFields := v.NumField() f.fs.Write(openBraceBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { vt := v.Type() for i := 0; i < numFields; i++ { if i > 0 { f.fs.Write(spaceBytes) } vtf := vt.Field(i) if f.fs.Flag('+') || f.fs.Flag('#') { f.fs.Write([]byte(vtf.Name)) f.fs.Write(colonBytes) } f.format(f.unpackValue(v.Field(i))) } } f.depth-- f.fs.Write(closeBraceBytes) case reflect.Uintptr: printHexPtr(f.fs, uintptr(v.Uint())) case reflect.UnsafePointer, reflect.Chan, reflect.Func: printHexPtr(f.fs, v.Pointer()) // There were not any other types at the time this code was written, but // fall back to letting the default fmt package handle it if any get added. default: format := f.buildDefaultFormat() if v.CanInterface() { fmt.Fprintf(f.fs, format, v.Interface()) } else { fmt.Fprintf(f.fs, format, v.String()) } } } // Format satisfies the fmt.Formatter interface. See NewFormatter for usage // details. func (f *formatState) Format(fs fmt.State, verb rune) { f.fs = fs // Use standard formatting for verbs that are not v. if verb != 'v' { format := f.constructOrigFormat(verb) fmt.Fprintf(fs, format, f.value) return } if f.value == nil { if fs.Flag('#') { fs.Write(interfaceBytes) } fs.Write(nilAngleBytes) return } f.format(reflect.ValueOf(f.value)) } // newFormatter is a helper function to consolidate the logic from the various // public methods which take varying config states. func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { fs := &formatState{value: v, cs: cs} fs.pointers = make(map[uintptr]int) return fs } /* NewFormatter returns a custom formatter that satisfies the fmt.Formatter interface. As a result, it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). Typically this function shouldn't be called directly. It is much easier to make use of the custom formatter by calling one of the convenience functions such as Printf, Println, or Fprintf. */ func NewFormatter(v interface{}) fmt.Formatter { return newFormatter(&Config, v) } ================================================ FILE: internal/spew/format_test.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Test Summary: NOTE: For each test, a nil pointer, a single pointer and double pointer to the base test element are also tested to ensure proper indirection across all types. - Max int8, int16, int32, int64, int - Max uint8, uint16, uint32, uint64, uint - Boolean true and false - Standard complex64 and complex128 - Array containing standard ints - Array containing type with custom formatter on pointer receiver only - Array containing interfaces - Slice containing standard float32 values - Slice containing type with custom formatter on pointer receiver only - Slice containing interfaces - Nil slice - Standard string - Nil interface - Sub-interface - Map with string keys and int vals - Map with custom formatter type on pointer receiver only keys and vals - Map with interface keys and values - Map with nil interface value - Struct with primitives - Struct that contains another struct - Struct that contains custom type with Stringer pointer interface via both exported and unexported fields - Struct that contains embedded struct and field to same struct - Uintptr to 0 (null pointer) - Uintptr address of real variable - Unsafe.Pointer to 0 (null pointer) - Unsafe.Pointer to address of real variable - Nil channel - Standard int channel - Function with no params and no returns - Function with param and no returns - Function with multiple params and multiple returns - Struct that is circular through self referencing - Structs that are circular through cross referencing - Structs that are indirectly circular - Type that panics in its Stringer interface - Type that has a custom Error interface - %x passthrough with uint - %#x passthrough with uint - %f passthrough with precision - %f passthrough with width and precision - %d passthrough with width - %q passthrough with string */ package spew_test import ( "bytes" "fmt" "testing" "unsafe" "github.com/stretchr/testify/internal/spew" ) // formatterTest is used to describe a test to be performed against NewFormatter. type formatterTest struct { format string in interface{} wants []string } // formatterTests houses all of the tests to be performed against NewFormatter. var formatterTests = make([]formatterTest, 0) // addFormatterTest is a helper method to append the passed input and desired // result to formatterTests. func addFormatterTest(format string, in interface{}, wants ...string) { test := formatterTest{format, in, wants} formatterTests = append(formatterTests, test) } func addIntFormatterTests() { // Max int8. v := int8(127) nv := (*int8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "int8" vs := "127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Max int16. v2 := int16(32767) nv2 := (*int16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "int16" v2s := "32767" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Max int32. v3 := int32(2147483647) nv3 := (*int32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "int32" v3s := "2147483647" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") // Max int64. v4 := int64(9223372036854775807) nv4 := (*int64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "int64" v4s := "9223372036854775807" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") // Max int. v5 := int(2147483647) nv5 := (*int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "int" v5s := "2147483647" addFormatterTest("%v", v5, v5s) addFormatterTest("%v", pv5, "<*>"+v5s) addFormatterTest("%v", &pv5, "<**>"+v5s) addFormatterTest("%v", nv5, "") addFormatterTest("%+v", v5, v5s) addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%+v", nv5, "") addFormatterTest("%#v", v5, "("+v5t+")"+v5s) addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") } func addUintFormatterTests() { // Max uint8. v := uint8(255) nv := (*uint8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uint8" vs := "255" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Max uint16. v2 := uint16(65535) nv2 := (*uint16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Max uint32. v3 := uint32(4294967295) nv3 := (*uint32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "uint32" v3s := "4294967295" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") // Max uint64. v4 := uint64(18446744073709551615) nv4 := (*uint64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "uint64" v4s := "18446744073709551615" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") // Max uint. v5 := uint(4294967295) nv5 := (*uint)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "uint" v5s := "4294967295" addFormatterTest("%v", v5, v5s) addFormatterTest("%v", pv5, "<*>"+v5s) addFormatterTest("%v", &pv5, "<**>"+v5s) addFormatterTest("%v", nv5, "") addFormatterTest("%+v", v5, v5s) addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%+v", nv5, "") addFormatterTest("%#v", v5, "("+v5t+")"+v5s) addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") } func addBoolFormatterTests() { // Boolean true. v := bool(true) nv := (*bool)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "bool" vs := "true" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Boolean false. v2 := bool(false) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "bool" v2s := "false" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addFloatFormatterTests() { // Standard float32. v := float32(3.1415) nv := (*float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "float32" vs := "3.1415" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Standard float64. v2 := float64(3.1415926) nv2 := (*float64)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "float64" v2s := "3.1415926" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") } func addComplexFormatterTests() { // Standard complex64. v := complex(float32(6), -2) nv := (*complex64)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "complex64" vs := "(6-2i)" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Standard complex128. v2 := complex(float64(-6), 2) nv2 := (*complex128)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "complex128" v2s := "(-6+2i)" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") } func addArrayFormatterTests() { // Array containing standard ints. v := [3]int{1, 2, 3} nv := (*[3]int)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "[3]int" vs := "[1 2 3]" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Array containing type with custom formatter on pointer receiver only. v2 := [3]pstringer{"1", "2", "3"} nv2 := (*[3]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "[3]spew_test.pstringer" v2sp := "[stringer 1 stringer 2 stringer 3]" v2s := v2sp if spew.UnsafeDisabled { v2s = "[1 2 3]" } addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2sp) addFormatterTest("%v", &pv2, "<**>"+v2sp) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Array containing interfaces. v3 := [3]interface{}{"one", int(2), uint(3)} nv3 := (*[3]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[3]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3s := "[one 2 3]" v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") } func addSliceFormatterTests() { // Slice containing standard float32 values. v := []float32{3.14, 6.28, 12.56} nv := (*[]float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "[]float32" vs := "[3.14 6.28 12.56]" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Slice containing type with custom formatter on pointer receiver only. v2 := []pstringer{"1", "2", "3"} nv2 := (*[]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "[]spew_test.pstringer" v2s := "[stringer 1 stringer 2 stringer 3]" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Slice containing interfaces. v3 := []interface{}{"one", int(2), uint(3), nil} nv3 := (*[]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3t5 := "interface {}" v3s := "[one 2 3 ]" v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + ")]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Nil slice. var v4 []int nv4 := (*[]int)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[]int" v4s := "" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } func addStringFormatterTests() { // Standard string. v := "test" nv := (*string)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "string" vs := "test" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addInterfaceFormatterTests() { // Nil interface. var v interface{} nv := (*interface{})(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "interface {}" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Sub-interface. v2 := interface{}(uint16(65535)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addMapFormatterTests() { // Map with string keys and int vals. v := map[string]int{"one": 1, "two": 2} nilMap := map[string]int(nil) nv := (*map[string]int)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "map[string]int" vs := "map[one:1 two:2]" vs2 := "map[two:2 one:1]" addFormatterTest("%v", v, vs, vs2) addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) addFormatterTest("%+v", nilMap, "") addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs, vs2) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, "<**>("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%+v", nilMap, "") addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) addFormatterTest("%#v", nilMap, "("+vt+")"+"") addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, "(*"+vt+")("+vAddr+")"+vs2) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%#+v", nilMap, "("+vt+")"+"") addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Map with custom formatter type on pointer receiver only keys and vals. v2 := map[pstringer]pstringer{"one": "1"} nv2 := (*map[pstringer]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "map[spew_test.pstringer]spew_test.pstringer" v2s := "map[stringer one:stringer 1]" if spew.UnsafeDisabled { v2s = "map[one:1]" } addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Map with interface keys and values. v3 := map[interface{}]interface{}{"one": 1} nv3 := (*map[interface{}]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "map[interface {}]interface {}" v3t1 := "string" v3t2 := "int" v3s := "map[one:1]" v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Map with nil interface value v4 := map[string]interface{}{"nil": nil} nv4 := (*map[string]interface{})(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "map[string]interface {}" v4t1 := "interface {}" v4s := "map[nil:]" v4s2 := "map[nil:(" + v4t1 + ")]" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } func addStructFormatterTests() { // Struct with primitives. type s1 struct { a int8 b uint8 } v := s1{127, 255} nv := (*s1)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.s1" vt2 := "int8" vt3 := "uint8" vs := "{127 255}" vs2 := "{a:127 b:255}" vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs2) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs3) addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs3) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Struct that contains another struct. type s2 struct { s1 s1 b bool } v2 := s2{s1{127, 255}, true} nv2 := (*s2)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.s2" v2t2 := "spew_test.s1" v2t3 := "int8" v2t4 := "uint8" v2t5 := "bool" v2s := "{{127 255} true}" v2s2 := "{s1:{a:127 b:255} b:true}" v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + v2t5 + ")true}" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s2) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Struct that contains custom type with Stringer pointer interface via both // exported and unexported fields. type s3 struct { s pstringer S pstringer } v3 := s3{"test", "test2"} nv3 := (*s3)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "spew_test.s3" v3t2 := "spew_test.pstringer" v3s := "{stringer test stringer test2}" v3sp := v3s v3s2 := "{s:stringer test S:stringer test2}" v3s2p := v3s2 v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" v3s3p := v3s3 if spew.UnsafeDisabled { v3s = "{test test2}" v3sp = "{test stringer test2}" v3s2 = "{s:test S:test2}" v3s2p = "{s:test S:stringer test2}" v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}" v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}" } addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3sp) addFormatterTest("%v", &pv3, "<**>"+v3sp) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s2) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Struct that contains embedded struct and field to same struct. e := embed{"embedstr"} v4 := embedwrap{embed: &e, e: &e} nv4 := (*embedwrap)(nil) pv4 := &v4 eAddr := fmt.Sprintf("%p", &e) v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "spew_test.embedwrap" v4t2 := "spew_test.embed" v4t3 := "string" v4s := "{<*>{embedstr} <*>{embedstr}}" v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + "){a:embedstr}}" v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr}}" v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s2) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } func addUintptrFormatterTests() { // Null pointer. v := uintptr(0) nv := (*uintptr)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uintptr" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Address of real variable. i := 1 v2 := uintptr(unsafe.Pointer(&i)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uintptr" v2s := fmt.Sprintf("%p", &i) addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addUnsafePointerFormatterTests() { // Null pointer. v := unsafe.Pointer(nil) nv := (*unsafe.Pointer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "unsafe.Pointer" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Address of real variable. i := 1 v2 := unsafe.Pointer(&i) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "unsafe.Pointer" v2s := fmt.Sprintf("%p", &i) addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addChanFormatterTests() { // Nil channel. var v chan int pv := &v nv := (*chan int)(nil) vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "chan int" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Real channel. v2 := make(chan int) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "chan int" v2s := fmt.Sprintf("%p", v2) addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addFuncFormatterTests() { // Function with no params and no returns. v := addIntFormatterTests nv := (*func())(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "func()" vs := fmt.Sprintf("%p", v) addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Function with param and no returns. v2 := TestFormatter nv2 := (*func(*testing.T))(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "func(*testing.T)" v2s := fmt.Sprintf("%p", v2) addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Function with multiple params and multiple returns. var v3 = func(i int, s string) (b bool, err error) { return true, nil } nv3 := (*func(int, string) (bool, error))(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "func(int, string) (bool, error)" v3s := fmt.Sprintf("%p", v3) addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") } func addCircularFormatterTests() { // Struct that is circular through self referencing. type circular struct { c *circular } v := circular{nil} v.c = &v pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.circular" vs := "{<*>{<*>}}" vs2 := "{<*>}" vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" vs4 := "{c:<*>(" + vAddr + ")}" vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" vs6 := "{c:(*" + vt + ")}" vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + ")}}" vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs2) addFormatterTest("%v", &pv, "<**>"+vs2) addFormatterTest("%+v", v, vs3) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) addFormatterTest("%#v", v, "("+vt+")"+vs5) addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) addFormatterTest("%#+v", v, "("+vt+")"+vs7) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) // Structs that are circular through cross referencing. v2 := xref1{nil} ts2 := xref2{&v2} v2.ps2 = &ts2 pv2 := &v2 ts2Addr := fmt.Sprintf("%p", &ts2) v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.xref1" v2t2 := "spew_test.xref2" v2s := "{<*>{<*>{<*>}}}" v2s2 := "{<*>{<*>}}" v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + ts2Addr + ")}}}" v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + ")}}}" v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + ")}}}" v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + ")(" + v2Addr + ")}}" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s2) addFormatterTest("%v", &pv2, "<**>"+v2s2) addFormatterTest("%+v", v2, v2s3) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) // Structs that are indirectly circular. v3 := indirCir1{nil} tic2 := indirCir2{nil} tic3 := indirCir3{&v3} tic2.ps3 = &tic3 v3.ps2 = &tic2 pv3 := &v3 tic2Addr := fmt.Sprintf("%p", &tic2) tic3Addr := fmt.Sprintf("%p", &tic3) v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "spew_test.indirCir1" v3t2 := "spew_test.indirCir2" v3t3 := "spew_test.indirCir3" v3s := "{<*>{<*>{<*>{<*>}}}}" v3s2 := "{<*>{<*>{<*>}}}" v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + v3Addr + ")}}}" v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + "){ps2:(*" + v3t2 + ")}}}}" v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + ")}}}" v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + ")(" + tic2Addr + ")}}}}" v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s2) addFormatterTest("%v", &pv3, "<**>"+v3s2) addFormatterTest("%+v", v3, v3s3) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) } func addPanicFormatterTests() { // Type that panics in its Stringer interface. v := panicer(127) nv := (*panicer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.panicer" vs := "(PANIC=test panic)127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addErrorFormatterTests() { // Type that has a custom Error interface. v := customError(127) nv := (*customError)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.customError" vs := "error: 127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addPassthroughFormatterTests() { // %x passthrough with uint. v := uint(4294967295) pv := &v vAddr := fmt.Sprintf("%x", pv) pvAddr := fmt.Sprintf("%x", &pv) vs := "ffffffff" addFormatterTest("%x", v, vs) addFormatterTest("%x", pv, vAddr) addFormatterTest("%x", &pv, pvAddr) // %#x passthrough with uint. v2 := int(2147483647) pv2 := &v2 v2Addr := fmt.Sprintf("%#x", pv2) pv2Addr := fmt.Sprintf("%#x", &pv2) v2s := "0x7fffffff" addFormatterTest("%#x", v2, v2s) addFormatterTest("%#x", pv2, v2Addr) addFormatterTest("%#x", &pv2, pv2Addr) // %f passthrough with precision. addFormatterTest("%.2f", 3.1415, "3.14") addFormatterTest("%.3f", 3.1415, "3.142") addFormatterTest("%.4f", 3.1415, "3.1415") // %f passthrough with width and precision. addFormatterTest("%5.2f", 3.1415, " 3.14") addFormatterTest("%6.3f", 3.1415, " 3.142") addFormatterTest("%7.4f", 3.1415, " 3.1415") // %d passthrough with width. addFormatterTest("%3d", 127, "127") addFormatterTest("%4d", 127, " 127") addFormatterTest("%5d", 127, " 127") // %q passthrough with string. addFormatterTest("%q", "test", "\"test\"") } // TestFormatter executes all of the tests described by formatterTests. func TestFormatter(t *testing.T) { // Setup tests. addIntFormatterTests() addUintFormatterTests() addBoolFormatterTests() addFloatFormatterTests() addComplexFormatterTests() addArrayFormatterTests() addSliceFormatterTests() addStringFormatterTests() addInterfaceFormatterTests() addMapFormatterTests() addStructFormatterTests() addUintptrFormatterTests() addUnsafePointerFormatterTests() addChanFormatterTests() addFuncFormatterTests() addCircularFormatterTests() addPanicFormatterTests() addErrorFormatterTests() addPassthroughFormatterTests() t.Logf("Running %d tests", len(formatterTests)) for i, test := range formatterTests { buf := new(bytes.Buffer) spew.Fprintf(buf, test.format, test.in) s := buf.String() if testFailed(s, test.wants) { t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, stringizeWants(test.wants)) continue } } } type testStruct struct { x int } func (ts testStruct) String() string { return fmt.Sprintf("ts.%d", ts.x) } type testStructP struct { x int } func (ts *testStructP) String() string { return fmt.Sprintf("ts.%d", ts.x) } func TestPrintSortedKeys(t *testing.T) { cfg := spew.ConfigState{SortKeys: true} s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) expected := "map[1:1 2:2 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 1:\n %v %v", s, expected) } s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 2:\n %v %v", s, expected) } s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" if spew.UnsafeDisabled { expected = "map[1:1 2:2 3:3]" } if s != expected { t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) } s = cfg.Sprint(map[testStruct]int{{1}: 1, {3}: 3, {2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) } if !spew.UnsafeDisabled { s = cfg.Sprint(map[testStructP]int{{1}: 1, {3}: 3, {2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) } } s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) expected = "map[error: 1:1 error: 2:2 error: 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 6:\n %v %v", s, expected) } } ================================================ FILE: internal/spew/internal_test.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This test file is part of the spew package rather than than the spew_test package because it needs access to internals to properly test certain cases which are not possible via the public interface since they should never happen. */ package spew import ( "bytes" "reflect" "testing" ) // dummyFmtState implements a fake fmt.State to use for testing invalid // reflect.Value handling. This is necessary because the fmt package catches // invalid values before invoking the formatter on them. type dummyFmtState struct { bytes.Buffer } func (dfs *dummyFmtState) Flag(f int) bool { return f == int('+') } func (dfs *dummyFmtState) Precision() (int, bool) { return 0, false } func (dfs *dummyFmtState) Width() (int, bool) { return 0, false } // TestInvalidReflectValue ensures the dump and formatter code handles an // invalid reflect value properly. This needs access to internal state since it // should never happen in real code and therefore can't be tested via the public // API. func TestInvalidReflectValue(t *testing.T) { i := 1 // Dump invalid reflect value. v := new(reflect.Value) buf := new(bytes.Buffer) d := dumpState{w: buf, cs: &Config} d.dump(*v) s := buf.String() want := "" if s != want { t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) } i++ // Formatter invalid reflect value. buf2 := new(dummyFmtState) f := formatState{value: *v, cs: &Config, fs: buf2} f.format(*v) s = buf2.String() want = "" if s != want { t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) } } // SortValues makes the internal sortValues function available to the test // package. func SortValues(values []reflect.Value, cs *ConfigState) { sortValues(values, cs) } ================================================ FILE: internal/spew/internalunsafe_test.go ================================================ // Copyright (c) 2013-2016 Dave Collins // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is not running on Google App Engine, compiled by GopherJS, and // "-tags safe" is not added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. //go:build !js && !appengine && !safe && !disableunsafe && go1.4 // +build !js,!appengine,!safe,!disableunsafe,go1.4 /* This test file is part of the spew package rather than than the spew_test package because it needs access to internals to properly test certain cases which are not possible via the public interface since they should never happen. */ package spew import ( "bytes" "reflect" "testing" ) // changeKind uses unsafe to intentionally change the kind of a reflect.Value to // the maximum kind value which does not exist. This is needed to test the // fallback code which punts to the standard fmt library for new types that // might get added to the language. func changeKind(v *reflect.Value, readOnly bool) { flags := flagField(v) if readOnly { *flags |= flagRO } else { *flags &^= flagRO } *flags |= flagKindMask } // TestAddedReflectValue tests functionaly of the dump and formatter code which // falls back to the standard fmt library for new types that might get added to // the language. func TestAddedReflectValue(t *testing.T) { i := 1 // Dump using a reflect.Value that is exported. v := reflect.ValueOf(int8(5)) changeKind(&v, false) buf := new(bytes.Buffer) d := dumpState{w: buf, cs: &Config} d.dump(v) s := buf.String() want := "(int8) 5" if s != want { t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want) } i++ // Dump using a reflect.Value that is not exported. changeKind(&v, true) buf.Reset() d.dump(v) s = buf.String() want = "(int8) " if s != want { t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want) } i++ // Formatter using a reflect.Value that is exported. changeKind(&v, false) buf2 := new(dummyFmtState) f := formatState{value: v, cs: &Config, fs: buf2} f.format(v) s = buf2.String() want = "5" if s != want { t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want) } i++ // Formatter using a reflect.Value that is not exported. changeKind(&v, true) buf2.Reset() f = formatState{value: v, cs: &Config, fs: buf2} f.format(v) s = buf2.String() want = "" if s != want { t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want) } } ================================================ FILE: internal/spew/spew.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew import ( "fmt" "io" ) // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the formatted string as a value that satisfies error. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Errorf(format string, a ...interface{}) (err error) { return fmt.Errorf(format, convertArgs(a)...) } // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprint(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprint(w, convertArgs(a)...) } // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(w, format, convertArgs(a)...) } // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it // passed with a default Formatter interface returned by NewFormatter. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprintln(w, convertArgs(a)...) } // Print is a wrapper for fmt.Print that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) func Print(a ...interface{}) (n int, err error) { return fmt.Print(convertArgs(a)...) } // Printf is a wrapper for fmt.Printf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Printf(format string, a ...interface{}) (n int, err error) { return fmt.Printf(format, convertArgs(a)...) } // Println is a wrapper for fmt.Println that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) func Println(a ...interface{}) (n int, err error) { return fmt.Println(convertArgs(a)...) } // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) func Sprint(a ...interface{}) string { return fmt.Sprint(convertArgs(a)...) } // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Sprintf(format string, a ...interface{}) string { return fmt.Sprintf(format, convertArgs(a)...) } // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it // were passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) func Sprintln(a ...interface{}) string { return fmt.Sprintln(convertArgs(a)...) } // convertArgs accepts a slice of arguments and returns a slice of the same // length with each argument converted to a default spew Formatter interface. func convertArgs(args []interface{}) (formatters []interface{}) { formatters = make([]interface{}, len(args)) for index, arg := range args { formatters[index] = NewFormatter(arg) } return formatters } ================================================ FILE: internal/spew/spew_test.go ================================================ /* * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ package spew_test import ( "bytes" "fmt" "io/ioutil" "os" "testing" "github.com/stretchr/testify/internal/spew" ) // spewFunc is used to identify which public function of the spew package or // ConfigState a test applies to. type spewFunc int const ( fCSFdump spewFunc = iota fCSFprint fCSFprintf fCSFprintln fCSPrint fCSPrintln fCSSdump fCSSprint fCSSprintf fCSSprintln fCSErrorf fCSNewFormatter fErrorf fFprint fFprintln fPrint fPrintln fSdump fSprint fSprintf fSprintln ) // Map of spewFunc values to names for pretty printing. var spewFuncStrings = map[spewFunc]string{ fCSFdump: "ConfigState.Fdump", fCSFprint: "ConfigState.Fprint", fCSFprintf: "ConfigState.Fprintf", fCSFprintln: "ConfigState.Fprintln", fCSSdump: "ConfigState.Sdump", fCSPrint: "ConfigState.Print", fCSPrintln: "ConfigState.Println", fCSSprint: "ConfigState.Sprint", fCSSprintf: "ConfigState.Sprintf", fCSSprintln: "ConfigState.Sprintln", fCSErrorf: "ConfigState.Errorf", fCSNewFormatter: "ConfigState.NewFormatter", fErrorf: "spew.Errorf", fFprint: "spew.Fprint", fFprintln: "spew.Fprintln", fPrint: "spew.Print", fPrintln: "spew.Println", fSdump: "spew.Sdump", fSprint: "spew.Sprint", fSprintf: "spew.Sprintf", fSprintln: "spew.Sprintln", } func (f spewFunc) String() string { if s, ok := spewFuncStrings[f]; ok { return s } return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) } // spewTest is used to describe a test to be performed against the public // functions of the spew package or ConfigState. type spewTest struct { cs *spew.ConfigState f spewFunc format string in interface{} want string } // spewTests houses the tests to be performed against the public functions of // the spew package and ConfigState. // // These tests are only intended to ensure the public functions are exercised // and are intentionally not exhaustive of types. The exhaustive type // tests are handled in the dump and format tests. var spewTests []spewTest // redirStdout is a helper function to return the standard output from f as a // byte slice. func redirStdout(f func()) ([]byte, error) { tempFile, err := ioutil.TempFile("", "ss-test") if err != nil { return nil, err } fileName := tempFile.Name() defer os.Remove(fileName) // Ignore error origStdout := os.Stdout os.Stdout = tempFile f() os.Stdout = origStdout tempFile.Close() return ioutil.ReadFile(fileName) } func initSpewTests() { // Config states with various settings. scsDefault := spew.NewDefaultConfig() scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true} scsNoCap := &spew.ConfigState{DisableCapacities: true} // Variables for tests on types which implement Stringer interface with and // without a pointer receiver. ts := stringer("test") tps := pstringer("test") type ptrTester struct { s *struct{} } tptr := &ptrTester{s: &struct{}{}} // depthTester is used to test max depth handling for structs, array, slices // and maps. type depthTester struct { ic indirCir1 arr [1]string slice []string m map[string]int } dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, map[string]int{"one": 1}} // Variable for tests on types which implement error interface. te := customError(10) spewTests = []spewTest{ {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, {scsDefault, fCSFprint, "", int16(32767), "32767"}, {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, {scsDefault, fFprint, "", float32(3.14), "3.14"}, {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, {scsDefault, fPrint, "", true, "true"}, {scsDefault, fPrintln, "", false, "false\n"}, {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, {scsNoMethods, fCSFprint, "", ts, "test"}, {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, {scsNoMethods, fCSFprint, "", tps, "test"}, {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, {scsNoPmethods, fCSFprint, "", tps, "test"}, {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + " ic: (spew_test.indirCir1) {\n \n },\n" + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + " m: (map[string]int) (len=1) {\n \n }\n}\n"}, {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + "(len=4) (stringer test) \"test\"\n"}, {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + "(error: 10) 10\n"}, {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"}, {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"}, {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"}, {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"}, } } // TestSpew executes all of the tests described by spewTests. func TestSpew(t *testing.T) { initSpewTests() t.Logf("Running %d tests", len(spewTests)) for i, test := range spewTests { buf := new(bytes.Buffer) switch test.f { case fCSFdump: test.cs.Fdump(buf, test.in) case fCSFprint: test.cs.Fprint(buf, test.in) case fCSFprintf: test.cs.Fprintf(buf, test.format, test.in) case fCSFprintln: test.cs.Fprintln(buf, test.in) case fCSPrint: b, err := redirStdout(func() { test.cs.Print(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fCSPrintln: b, err := redirStdout(func() { test.cs.Println(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fCSSdump: str := test.cs.Sdump(test.in) buf.WriteString(str) case fCSSprint: str := test.cs.Sprint(test.in) buf.WriteString(str) case fCSSprintf: str := test.cs.Sprintf(test.format, test.in) buf.WriteString(str) case fCSSprintln: str := test.cs.Sprintln(test.in) buf.WriteString(str) case fCSErrorf: err := test.cs.Errorf(test.format, test.in) buf.WriteString(err.Error()) case fCSNewFormatter: fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) case fErrorf: err := spew.Errorf(test.format, test.in) buf.WriteString(err.Error()) case fFprint: spew.Fprint(buf, test.in) case fFprintln: spew.Fprintln(buf, test.in) case fPrint: b, err := redirStdout(func() { spew.Print(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fPrintln: b, err := redirStdout(func() { spew.Println(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fSdump: str := spew.Sdump(test.in) buf.WriteString(str) case fSprint: str := spew.Sprint(test.in) buf.WriteString(str) case fSprintf: str := spew.Sprintf(test.format, test.in) buf.WriteString(str) case fSprintln: str := spew.Sprintln(test.in) buf.WriteString(str) default: t.Errorf("%v #%d unrecognized function", test.f, i) continue } s := buf.String() if test.want != s { t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) continue } } } ================================================ FILE: internal/spew/testdata/dumpcgo.go ================================================ // Copyright (c) 2013 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled // when both cgo is supported and "-tags testcgo" is added to the go test // command line. This code should really only be in the dumpcgo_test.go file, // but unfortunately Go will not allow cgo in test files, so this is a // workaround to allow cgo types to be tested. This configuration is used // because spew itself does not require cgo to run even though it does handle // certain cgo types specially. Rather than forcing all clients to require cgo // and an external C compiler just to run the tests, this scheme makes them // optional. // //go:build cgo && testcgo // +build cgo,testcgo package testdata /* #include typedef unsigned char custom_uchar_t; char *ncp = 0; char *cp = "test"; char ca[6] = {'t', 'e', 's', 't', '2', '\0'}; unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'}; signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'}; uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'}; custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'}; */ import "C" // GetCgoNullCharPointer returns a null char pointer via cgo. This is only // used for tests. func GetCgoNullCharPointer() interface{} { return C.ncp } // GetCgoCharPointer returns a char pointer via cgo. This is only used for // tests. func GetCgoCharPointer() interface{} { return C.cp } // GetCgoCharArray returns a char array via cgo and the array's len and cap. // This is only used for tests. func GetCgoCharArray() (interface{}, int, int) { return C.ca, len(C.ca), cap(C.ca) } // GetCgoUnsignedCharArray returns an unsigned char array via cgo and the // array's len and cap. This is only used for tests. func GetCgoUnsignedCharArray() (interface{}, int, int) { return C.uca, len(C.uca), cap(C.uca) } // GetCgoSignedCharArray returns a signed char array via cgo and the array's len // and cap. This is only used for tests. func GetCgoSignedCharArray() (interface{}, int, int) { return C.sca, len(C.sca), cap(C.sca) } // GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and // cap. This is only used for tests. func GetCgoUint8tArray() (interface{}, int, int) { return C.ui8ta, len(C.ui8ta), cap(C.ui8ta) } // GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via // cgo and the array's len and cap. This is only used for tests. func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) { return C.tuca, len(C.tuca), cap(C.tuca) } ================================================ FILE: mock/doc.go ================================================ // Package mock provides a system by which it is possible to mock your objects // and verify calls are happening as expected. // // # Example Usage // // The mock package provides an object, Mock, that tracks activity on another object. It is usually // embedded into a test object as shown below: // // type MyTestObject struct { // // add a Mock object instance // mock.Mock // // // other fields go here as normal // } // // When implementing the methods of an interface, you wire your functions up // to call the Mock.Called(args...) method, and return the appropriate values. // // For example, to mock a method that saves the name and age of a person and returns // the year of their birth or an error, you might write this: // // func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { // args := o.Called(firstname, lastname, age) // return args.Int(0), args.Error(1) // } // // The Int, Error and Bool methods are examples of strongly typed getters that take the argument // index position. Given this argument list: // // (12, true, "Something") // // You could read them out strongly typed like this: // // args.Int(0) // args.Bool(1) // args.String(2) // // For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: // // return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) // // This may cause a panic if the object you are getting is nil (the type assertion will fail), in those // cases you should check for nil first. package mock ================================================ FILE: mock/mock.go ================================================ package mock import ( "errors" "fmt" "path" "reflect" "regexp" "runtime" "strings" "sync" "time" "github.com/stretchr/objx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/internal/difflib" "github.com/stretchr/testify/internal/spew" ) // regex for GCCGO functions var gccgoRE = regexp.MustCompile(`\.pN\d+_`) // TestingT is an interface wrapper around *testing.T type TestingT interface { Logf(format string, args ...interface{}) Errorf(format string, args ...interface{}) FailNow() } /* Call */ // Call represents a method call and is used for setting expectations, // as well as recording activity. type Call struct { Parent *Mock // The name of the method that was or will be called. Method string // Holds the arguments of the method. Arguments Arguments // Holds the arguments that should be returned when // this method is called. ReturnArguments Arguments // Holds the caller info for the On() call callerInfo []string // The number of times to return the return arguments when setting // expectations. 0 means to always return the value. Repeatability int // Amount of times this call has been called totalCalls int // Call to this method can be optional optional bool // Holds a channel that will be used to block the Return until it either // receives a message or is closed. nil means it returns immediately. WaitFor <-chan time.Time waitTime time.Duration // Holds a handler used to manipulate arguments content that are passed by // reference. It's useful when mocking methods such as unmarshalers or // decoders. RunFn func(Arguments) // PanicMsg holds msg to be used to mock panic on the function call // if the PanicMsg is set to a non nil string the function call will panic // irrespective of other settings PanicMsg *string // Calls which must be satisfied before this call can be requires []*Call } func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments Arguments, returnArguments Arguments) *Call { return &Call{ Parent: parent, Method: methodName, Arguments: methodArguments, ReturnArguments: returnArguments, callerInfo: callerInfo, Repeatability: 0, WaitFor: nil, RunFn: nil, PanicMsg: nil, } } func (c *Call) lock() { c.Parent.mutex.Lock() } func (c *Call) unlock() { c.Parent.mutex.Unlock() } // Return specifies the return arguments for the expectation. // // Mock.On("DoSomething").Return(errors.New("failed")) func (c *Call) Return(returnArguments ...interface{}) *Call { c.lock() defer c.unlock() c.ReturnArguments = returnArguments return c } // Panic specifies if the function call should fail and the panic message // // Mock.On("DoSomething").Panic("test panic") func (c *Call) Panic(msg string) *Call { c.lock() defer c.unlock() c.PanicMsg = &msg return c } // Once indicates that the mock should only return the value once. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() func (c *Call) Once() *Call { return c.Times(1) } // Twice indicates that the mock should only return the value twice. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() func (c *Call) Twice() *Call { return c.Times(2) } // Times indicates that the mock should only return the indicated number // of times. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) func (c *Call) Times(i int) *Call { c.lock() defer c.unlock() c.Repeatability = i return c } // WaitUntil sets the channel that will block the mock's return until its closed // or a message is received. // // Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) func (c *Call) WaitUntil(w <-chan time.Time) *Call { c.lock() defer c.unlock() c.WaitFor = w return c } // After sets how long to block until the call returns // // Mock.On("MyMethod", arg1, arg2).After(time.Second) func (c *Call) After(d time.Duration) *Call { c.lock() defer c.unlock() c.waitTime = d return c } // Run sets a handler to be called before returning. It can be used when // mocking a method (such as an unmarshaler) that takes a pointer to a struct and // sets properties in such struct // // Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { // arg := args.Get(0).(*map[string]interface{}) // arg["foo"] = "bar" // }) func (c *Call) Run(fn func(args Arguments)) *Call { c.lock() defer c.unlock() c.RunFn = fn return c } // Maybe allows the method call to be optional. Not calling an optional method // will not cause an error while asserting expectations func (c *Call) Maybe() *Call { c.lock() defer c.unlock() c.optional = true return c } // On chains a new expectation description onto the mocked interface. This // allows syntax like. // // Mock. // On("MyMethod", 1).Return(nil). // On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) // //go:noinline func (c *Call) On(methodName string, arguments ...interface{}) *Call { return c.Parent.On(methodName, arguments...) } // Unset removes all mock handlers that satisfy the call instance arguments from being // called. Only supported on call instances with static input arguments. // // For example, the only handler remaining after the following would be "MyMethod(2, 2)": // // Mock. // On("MyMethod", 2, 2).Return(0). // On("MyMethod", 3, 3).Return(0). // On("MyMethod", Anything, Anything).Return(0) // Mock.On("MyMethod", 3, 3).Unset() func (c *Call) Unset() *Call { var unlockOnce sync.Once for _, arg := range c.Arguments { if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) } } c.lock() defer unlockOnce.Do(c.unlock) foundMatchingCall := false // in-place filter slice for calls to be removed - iterate from 0'th to last skipping unnecessary ones var index int // write index for _, call := range c.Parent.ExpectedCalls { if call.Method == c.Method { _, diffCount := call.Arguments.Diff(c.Arguments) if diffCount == 0 { foundMatchingCall = true // Remove from ExpectedCalls - just skip it continue } } c.Parent.ExpectedCalls[index] = call index++ } // trim slice up to last copied index c.Parent.ExpectedCalls = c.Parent.ExpectedCalls[:index] if !foundMatchingCall { unlockOnce.Do(c.unlock) c.Parent.fail("\n\nmock: Could not find expected call\n-----------------------------\n\n%s\n\n", callString(c.Method, c.Arguments, true), ) } return c } // NotBefore indicates that the mock should only be called after the referenced // calls have been called as expected. The referenced calls may be from the // same mock instance and/or other mock instances. // // Mock.On("Do").Return(nil).NotBefore( // Mock.On("Init").Return(nil) // ) func (c *Call) NotBefore(calls ...*Call) *Call { c.lock() defer c.unlock() for _, call := range calls { if call.Parent == nil { panic("not before calls must be created with Mock.On()") } } c.requires = append(c.requires, calls...) return c } // InOrder defines the order in which the calls should be made // // For example: // // InOrder( // Mock.On("init").Return(nil), // Mock.On("Do").Return(nil), // ) func InOrder(calls ...*Call) { for i := 1; i < len(calls); i++ { calls[i].NotBefore(calls[i-1]) } } // Mock is the workhorse used to track activity on another object. // For an example of its usage, refer to the "Example Usage" section at the top // of this document. type Mock struct { // Represents the calls that are expected of // an object. ExpectedCalls []*Call // Holds the calls that were made to this mocked object. Calls []Call // test is An optional variable that holds the test struct, to be used when an // invalid mock call was made. test TestingT // TestData holds any data that might be useful for testing. Testify ignores // this data completely allowing you to do whatever you like with it. testData objx.Map mutex sync.Mutex } // String provides a %v format string for Mock. // Note: this is used implicitly by Arguments.Diff if a Mock is passed. // It exists because go's default %v formatting traverses the struct // without acquiring the mutex, which is detected by go test -race. func (m *Mock) String() string { return fmt.Sprintf("%[1]T<%[1]p>", m) } // TestData holds any data that might be useful for testing. Testify ignores // this data completely allowing you to do whatever you like with it. func (m *Mock) TestData() objx.Map { if m.testData == nil { m.testData = make(objx.Map) } return m.testData } /* Setting expectations */ // Test sets the [TestingT] on which errors will be reported, otherwise errors // will cause a panic. // Test should not be called on an object that is going to be used in a // goroutine other than the one running the test function. func (m *Mock) Test(t TestingT) { m.mutex.Lock() defer m.mutex.Unlock() m.test = t } // fail fails the current test with the given formatted format and args. // In case that a test was defined, it uses the test APIs for failing a test, // otherwise it uses panic. func (m *Mock) fail(format string, args ...interface{}) { m.mutex.Lock() defer m.mutex.Unlock() if m.test == nil { panic(fmt.Sprintf(format, args...)) } m.test.Errorf(format, args...) m.test.FailNow() } // On starts a description of an expectation of the specified method // being called. // // Mock.On("MyMethod", arg1, arg2) func (m *Mock) On(methodName string, arguments ...interface{}) *Call { for _, arg := range arguments { if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) } } m.mutex.Lock() defer m.mutex.Unlock() c := newCall(m, methodName, assert.CallerInfo(), arguments, make([]interface{}, 0)) m.ExpectedCalls = append(m.ExpectedCalls, c) return c } // /* // Recording and responding to activity // */ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { var expectedCall *Call for i, call := range m.ExpectedCalls { if call.Method == method { _, diffCount := call.Arguments.Diff(arguments) if diffCount == 0 { expectedCall = call if call.Repeatability > -1 { return i, call } } } } return -1, expectedCall } type matchCandidate struct { call *Call mismatch string diffCount int } func (c matchCandidate) isBetterMatchThan(other matchCandidate) bool { if c.call == nil { return false } if other.call == nil { return true } if c.diffCount > other.diffCount { return false } if c.diffCount < other.diffCount { return true } if c.call.Repeatability > 0 && other.call.Repeatability <= 0 { return true } return false } func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) { var bestMatch matchCandidate for _, call := range m.expectedCalls() { if call.Method == method { errInfo, tempDiffCount := call.Arguments.Diff(arguments) tempCandidate := matchCandidate{ call: call, mismatch: errInfo, diffCount: tempDiffCount, } if tempCandidate.isBetterMatchThan(bestMatch) { bestMatch = tempCandidate } } } return bestMatch.call, bestMatch.mismatch } func callString(method string, arguments Arguments, includeArgumentValues bool) string { var argValsString string if includeArgumentValues { var argVals []string for argIndex, arg := range arguments { if _, ok := arg.(*FunctionalOptionsArgument); ok { argVals = append(argVals, fmt.Sprintf("%d: %s", argIndex, arg)) continue } argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) } argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) } return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString) } // Called tells the mock object that a method has been called, and gets an array // of arguments to return. Panics if the call is unexpected (i.e. not preceded by // appropriate .On .Return() calls) // If Call.WaitFor is set, blocks until the channel is closed or receives a message. func (m *Mock) Called(arguments ...interface{}) Arguments { // get the calling function's name pc, _, _, ok := runtime.Caller(1) if !ok { panic("Couldn't get the caller information") } functionPath := runtime.FuncForPC(pc).Name() // Next four lines are required to use GCCGO function naming conventions. // For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock // uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree // With GCCGO we need to remove interface information starting from pN

. if gccgoRE.MatchString(functionPath) { functionPath = gccgoRE.Split(functionPath, -1)[0] } parts := strings.Split(functionPath, ".") functionName := parts[len(parts)-1] return m.MethodCalled(functionName, arguments...) } // MethodCalled tells the mock object that the given method has been called, and gets // an array of arguments to return. Panics if the call is unexpected (i.e. not preceded // by appropriate .On .Return() calls) // If Call.WaitFor is set, blocks until the channel is closed or receives a message. func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { m.mutex.Lock() // TODO: could combine expected and closes in single loop found, call := m.findExpectedCall(methodName, arguments...) if found < 0 { // expected call found, but it has already been called with repeatable times if call != nil { m.mutex.Unlock() m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(%#v).Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo()) } // we have to fail here - because we don't know what to do // as the return arguments. This is because: // // a) this is a totally unexpected call to this method, // b) the arguments are not what was expected, or // c) the developer has forgotten to add an accompanying On...Return pair. closestCall, mismatch := m.findClosestCall(methodName, arguments...) m.mutex.Unlock() if closestCall != nil { m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s\nat: %s\n", callString(methodName, arguments, true), callString(methodName, closestCall.Arguments, true), diffArguments(closestCall.Arguments, arguments), strings.TrimSpace(mismatch), assert.CallerInfo(), ) } else { m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(%#v).Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()) } } for _, requirement := range call.requires { if satisfied, _ := requirement.Parent.checkExpectation(requirement); !satisfied { m.mutex.Unlock() m.fail("mock: Unexpected Method Call\n-----------------------------\n\n%s\n\nMust not be called before%s:\n\n%s", callString(call.Method, call.Arguments, true), func() (s string) { if requirement.totalCalls > 0 { s = " another call of" } if call.Parent != requirement.Parent { s += " method from another mock instance" } return }(), callString(requirement.Method, requirement.Arguments, true), ) } } if call.Repeatability == 1 { call.Repeatability = -1 } else if call.Repeatability > 1 { call.Repeatability-- } call.totalCalls++ // add the call m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments, call.ReturnArguments)) m.mutex.Unlock() // block if specified if call.WaitFor != nil { <-call.WaitFor } else { time.Sleep(call.waitTime) } m.mutex.Lock() panicMsg := call.PanicMsg m.mutex.Unlock() if panicMsg != nil { panic(*panicMsg) } m.mutex.Lock() runFn := call.RunFn m.mutex.Unlock() if runFn != nil { runFn(arguments) } m.mutex.Lock() returnArgs := call.ReturnArguments m.mutex.Unlock() return returnArgs } /* Assertions */ type assertExpectationiser interface { AssertExpectations(TestingT) bool } // AssertExpectationsForObjects asserts that everything specified with On and Return // of the specified objects was in fact called as expected. // // Calls may have occurred in any order. func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } for _, obj := range testObjects { m, ok := obj.(assertExpectationiser) if !ok { t.Errorf("Invalid test object type %T. Expected reference to a mock.Mock, eg: 'AssertExpectationsForObjects(t, myMock)' or 'AssertExpectationsForObjects(t, &myMock.Mock)'", obj) continue } if !m.AssertExpectations(t) { t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) return false } } return true } // AssertExpectations asserts that everything specified with On and Return was // in fact called as expected. Calls may have occurred in any order. func (m *Mock) AssertExpectations(t TestingT) bool { if s, ok := t.(interface{ Skipped() bool }); ok && s.Skipped() { return true } if h, ok := t.(tHelper); ok { h.Helper() } m.mutex.Lock() defer m.mutex.Unlock() var failedExpectations int // iterate through each expectation expectedCalls := m.expectedCalls() for _, expectedCall := range expectedCalls { satisfied, reason := m.checkExpectation(expectedCall) if !satisfied { failedExpectations++ t.Logf(reason) } } if failedExpectations != 0 { t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo()) } return failedExpectations == 0 } func (m *Mock) checkExpectation(call *Call) (bool, string) { if !call.optional && !m.methodWasCalled(call.Method, call.Arguments) && call.totalCalls == 0 { return false, fmt.Sprintf("FAIL:\t%s(%s)\n\t\tat: %s", call.Method, call.Arguments.String(), call.callerInfo) } if call.Repeatability > 0 { return false, fmt.Sprintf("FAIL:\t%s(%s)\n\t\tat: %s", call.Method, call.Arguments.String(), call.callerInfo) } return true, fmt.Sprintf("PASS:\t%s(%s)", call.Method, call.Arguments.String()) } // AssertNumberOfCalls asserts that the method was called expectedCalls times. func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { if h, ok := t.(tHelper); ok { h.Helper() } m.mutex.Lock() defer m.mutex.Unlock() var actualCalls int for _, call := range m.calls() { if call.Method == methodName { actualCalls++ } } return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) of method %s does not match the actual number of calls (%d).", expectedCalls, methodName, actualCalls)) } // AssertCalled asserts that the method was called. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } m.mutex.Lock() defer m.mutex.Unlock() if !m.methodWasCalled(methodName, arguments) { var calledWithArgs []string for _, call := range m.calls() { calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments)) } if len(calledWithArgs) == 0 { return assert.Fail(t, "Should have called with given arguments", fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments)) } return assert.Fail(t, "Should have called with given arguments", fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n"))) } return true } // AssertNotCalled asserts that the method was not called. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } m.mutex.Lock() defer m.mutex.Unlock() if m.methodWasCalled(methodName, arguments) { return assert.Fail(t, "Should not have called with given arguments", fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments)) } return true } // IsMethodCallable returns true if given methodName and arguments have an // unsatisfied expected call registered in the Mock. func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } m.mutex.Lock() defer m.mutex.Unlock() for _, v := range m.ExpectedCalls { if v.Method != methodName { continue } if len(arguments) != len(v.Arguments) { continue } if v.Repeatability < v.totalCalls { continue } if isArgsEqual(v.Arguments, arguments) { return true } } return false } // isArgsEqual compares arguments func isArgsEqual(expected Arguments, args []interface{}) bool { if len(expected) != len(args) { return false } for i, v := range args { if !reflect.DeepEqual(expected[i], v) { return false } } return true } func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { for _, call := range m.calls() { if call.Method == methodName { _, differences := Arguments(expected).Diff(call.Arguments) if differences == 0 { // found the expected call return true } } } // we didn't find the expected call return false } func (m *Mock) expectedCalls() []*Call { return append([]*Call{}, m.ExpectedCalls...) } func (m *Mock) calls() []Call { return append([]Call{}, m.Calls...) } /* Arguments */ // Arguments holds an array of method arguments or return values. type Arguments []interface{} const ( // Anything is used in Diff and Assert when the argument being tested // shouldn't be taken into consideration. Anything = "mock.Anything" ) // AnythingOfTypeArgument contains the type of an argument // for use when type checking. Used in [Arguments.Diff] and [Arguments.Assert]. // // Deprecated: this is an implementation detail that must not be used. Use the [AnythingOfType] constructor instead, example: // // m.On("Do", mock.AnythingOfType("string")) // // All explicit type declarations can be replaced with interface{} as is expected by [Mock.On], example: // // func anyString interface{} { // return mock.AnythingOfType("string") // } type AnythingOfTypeArgument = anythingOfTypeArgument // anythingOfTypeArgument is a string that contains the type of an argument // for use when type checking. Used in Diff and Assert. type anythingOfTypeArgument string // AnythingOfType returns a special value containing the // name of the type to check for. The type name will be matched against the type name returned by [reflect.Type.String]. // // Used in Diff and Assert. // // For example: // // args.Assert(t, AnythingOfType("string"), AnythingOfType("int")) func AnythingOfType(t string) AnythingOfTypeArgument { return anythingOfTypeArgument(t) } // IsTypeArgument is a struct that contains the type of an argument // for use when type checking. This is an alternative to [AnythingOfType]. // Used in [Arguments.Diff] and [Arguments.Assert]. type IsTypeArgument struct { t reflect.Type } // IsType returns an IsTypeArgument object containing the type to check for. // You can provide a zero-value of the type to check. This is an // alternative to [AnythingOfType]. Used in [Arguments.Diff] and [Arguments.Assert]. // // For example: // // args.Assert(t, IsType(""), IsType(0)) // // Mock cannot match interface types because the contained type will be passed // to both IsType and Mock.Called, for the zero value of all interfaces this // will be type. func IsType(t interface{}) *IsTypeArgument { return &IsTypeArgument{t: reflect.TypeOf(t)} } // FunctionalOptionsArgument contains a list of functional options arguments // expected for use when matching a list of arguments. type FunctionalOptionsArgument struct { values []interface{} } // String returns the string representation of FunctionalOptionsArgument func (f *FunctionalOptionsArgument) String() string { var name string if len(f.values) > 0 { name = "[]" + reflect.TypeOf(f.values[0]).String() } return strings.Replace(fmt.Sprintf("%#v", f.values), "[]interface {}", name, 1) } // FunctionalOptions returns an [FunctionalOptionsArgument] object containing // the expected functional-options to check for. // // For example: // // args.Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613))) func FunctionalOptions(values ...interface{}) *FunctionalOptionsArgument { return &FunctionalOptionsArgument{ values: values, } } // argumentMatcher performs custom argument matching, returning whether or // not the argument is matched by the expectation fixture function. type argumentMatcher struct { // fn is a function which accepts one argument, and returns a bool. fn reflect.Value } func (f argumentMatcher) Matches(argument interface{}) bool { expectType := f.fn.Type().In(0) expectTypeNilSupported := false switch expectType.Kind() { case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr: expectTypeNilSupported = true } argType := reflect.TypeOf(argument) var arg reflect.Value if argType == nil { arg = reflect.New(expectType).Elem() } else { arg = reflect.ValueOf(argument) } if argType == nil && !expectTypeNilSupported { panic(errors.New("attempting to call matcher with nil for non-nil expected type")) } if argType == nil || argType.AssignableTo(expectType) { result := f.fn.Call([]reflect.Value{arg}) return result[0].Bool() } return false } func (f argumentMatcher) String() string { return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).String()) } // MatchedBy can be used to match a mock call based on only certain properties // from a complex struct or some calculation. It takes a function that will be // evaluated with the called argument and will return true when there's a match // and false otherwise. // // Example: // // m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" })) // // fn must be a function accepting a single argument (of the expected type) // which returns a bool. If fn doesn't match the required signature, // MatchedBy() panics. func MatchedBy(fn interface{}) argumentMatcher { fnType := reflect.TypeOf(fn) if fnType.Kind() != reflect.Func { panic(fmt.Sprintf("assert: arguments: %s is not a func", fn)) } if fnType.NumIn() != 1 { panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn)) } if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool { panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn)) } return argumentMatcher{fn: reflect.ValueOf(fn)} } // Get Returns the argument at the specified index. func (args Arguments) Get(index int) interface{} { if index+1 > len(args) { panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args))) } return args[index] } // Is gets whether the objects match the arguments specified. func (args Arguments) Is(objects ...interface{}) bool { for i, obj := range args { if obj != objects[i] { return false } } return true } // Diff gets a string describing the differences between the arguments // and the specified objects. // // Returns the diff string and number of differences found. func (args Arguments) Diff(objects []interface{}) (string, int) { // TODO: could return string as error and nil for No difference output := "\n" var differences int maxArgCount := len(args) if len(objects) > maxArgCount { maxArgCount = len(objects) } for i := 0; i < maxArgCount; i++ { var actual, expected interface{} var actualFmt, expectedFmt string if len(objects) <= i { actual = "(Missing)" actualFmt = "(Missing)" } else { actual = objects[i] actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual) } if len(args) <= i { expected = "(Missing)" expectedFmt = "(Missing)" } else { expected = args[i] expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected) } if matcher, ok := expected.(argumentMatcher); ok { var matches bool func() { defer func() { if r := recover(); r != nil { actualFmt = fmt.Sprintf("panic in argument matcher: %v", r) } }() matches = matcher.Matches(actual) }() if matches { output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher) } else { differences++ output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) } } else { switch expected := expected.(type) { case anythingOfTypeArgument: // type checking if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) { // not match differences++ output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) } case *IsTypeArgument: actualT := reflect.TypeOf(actual) if actualT != expected.t { differences++ output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, safeTypeName(expected.t), safeTypeName(actualT), actualFmt) } case *FunctionalOptionsArgument: var name string if len(expected.values) > 0 { name = "[]" + reflect.TypeOf(expected.values[0]).String() } const tName = "[]interface{}" if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 { differences++ output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt) } else { if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" { // match output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName) } else { // not match differences++ output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef) } } default: if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { // match output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) } else { // not match differences++ output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) } } } } if differences == 0 { return "No differences.", differences } return output, differences } // Assert compares the arguments with the specified objects and fails if // they do not exactly match. func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } // get the differences diff, diffCount := args.Diff(objects) if diffCount == 0 { return true } // there are differences... report them... t.Logf(diff) t.Errorf("%sArguments do not match.", assert.CallerInfo()) return false } // String gets the argument at the specified index. Panics if there is no argument, or // if the argument is of the wrong type. // // If no index is provided, String() returns a complete string representation // of the arguments. func (args Arguments) String(indexOrNil ...int) string { if len(indexOrNil) == 0 { // normal String() method - return a string representation of the args var argsStr []string for _, arg := range args { argsStr = append(argsStr, fmt.Sprintf("%T", arg)) // handles nil nicely } return strings.Join(argsStr, ",") } else if len(indexOrNil) == 1 { // Index has been specified - get the argument at that index index := indexOrNil[0] var s string var ok bool if s, ok = args.Get(index).(string); !ok { panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index))) } return s } panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil))) } // Int gets the argument at the specified index. Panics if there is no argument, or // if the argument is of the wrong type. func (args Arguments) Int(index int) int { var s int var ok bool if s, ok = args.Get(index).(int); !ok { panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index))) } return s } // Error gets the argument at the specified index. Panics if there is no argument, or // if the argument is of the wrong type. func (args Arguments) Error(index int) error { obj := args.Get(index) var s error var ok bool if obj == nil { return nil } if s, ok = obj.(error); !ok { panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, obj)) } return s } // Bool gets the argument at the specified index. Panics if there is no argument, or // if the argument is of the wrong type. func (args Arguments) Bool(index int) bool { var s bool var ok bool if s, ok = args.Get(index).(bool); !ok { panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index))) } return s } // safeTypeName returns the reflect.Type's name without causing a panic. // If the provided reflect.Type is nil, it returns the placeholder string "" func safeTypeName(t reflect.Type) string { if t == nil { return "" } return t.Name() } func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { t := reflect.TypeOf(v) k := t.Kind() if k == reflect.Ptr { t = t.Elem() k = t.Kind() } return t, k } func diffArguments(expected Arguments, actual Arguments) string { if len(expected) != len(actual) { return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual)) } for x := range expected { if diffString := diff(expected[x], actual[x]); diffString != "" { return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) } } return "" } // diff returns a diff of both values as long as both are of the same type and // are a struct, map, slice or array. Otherwise it returns an empty string. func diff(expected interface{}, actual interface{}) string { if expected == nil || actual == nil { return "" } et, ek := typeAndKind(expected) at, _ := typeAndKind(actual) if et != at { return "" } if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { return "" } e := spewConfig.Sdump(expected) a := spewConfig.Sdump(actual) diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ A: difflib.SplitLines(e), B: difflib.SplitLines(a), FromFile: "Expected", FromDate: "", ToFile: "Actual", ToDate: "", Context: 1, }) return diff } var spewConfig = spew.ConfigState{ Indent: " ", DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, } type tHelper interface { Helper() } func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) { expectedOpts := reflect.ValueOf(expected) actualOpts := reflect.ValueOf(actual) var expectedFuncs []*runtime.Func var expectedNames []string for i := 0; i < expectedOpts.Len(); i++ { f := runtimeFunc(expectedOpts.Index(i).Interface()) expectedFuncs = append(expectedFuncs, f) expectedNames = append(expectedNames, funcName(f)) } var actualFuncs []*runtime.Func var actualNames []string for i := 0; i < actualOpts.Len(); i++ { f := runtimeFunc(actualOpts.Index(i).Interface()) actualFuncs = append(actualFuncs, f) actualNames = append(actualNames, funcName(f)) } if expectedOpts.Len() != actualOpts.Len() { expectedFmt = fmt.Sprintf("%v", expectedNames) actualFmt = fmt.Sprintf("%v", actualNames) return } for i := 0; i < expectedOpts.Len(); i++ { if !isFuncSame(expectedFuncs[i], actualFuncs[i]) { expectedFmt = expectedNames[i] actualFmt = actualNames[i] return } expectedOpt := expectedOpts.Index(i).Interface() actualOpt := actualOpts.Index(i).Interface() ot := reflect.TypeOf(expectedOpt) var expectedValues []reflect.Value var actualValues []reflect.Value if ot.NumIn() == 0 { return } for i := 0; i < ot.NumIn(); i++ { vt := ot.In(i).Elem() expectedValues = append(expectedValues, reflect.New(vt)) actualValues = append(actualValues, reflect.New(vt)) } reflect.ValueOf(expectedOpt).Call(expectedValues) reflect.ValueOf(actualOpt).Call(actualValues) for i := 0; i < ot.NumIn(); i++ { if expectedArg, actualArg := expectedValues[i].Interface(), actualValues[i].Interface(); !assert.ObjectsAreEqual(expectedArg, actualArg) { expectedFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], expectedArg, expectedArg) actualFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], actualArg, actualArg) return } } } return "", "" } func runtimeFunc(opt interface{}) *runtime.Func { return runtime.FuncForPC(reflect.ValueOf(opt).Pointer()) } func funcName(f *runtime.Func) string { name := f.Name() trimmed := strings.TrimSuffix(path.Base(name), path.Ext(name)) splitted := strings.Split(trimmed, ".") if len(splitted) == 0 { return trimmed } return splitted[len(splitted)-1] } func isFuncSame(f1, f2 *runtime.Func) bool { f1File, f1Loc := f1.FileLine(f1.Entry()) f2File, f2Loc := f2.FileLine(f2.Entry()) return f1File == f2File && f1Loc == f2Loc } ================================================ FILE: mock/mock_test.go ================================================ package mock import ( "context" "errors" "fmt" "regexp" "runtime" "strconv" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) /* Test objects */ // ExampleInterface represents an example interface. type ExampleInterface interface { TheExampleMethod(a, b, c int) (int, error) } // TestExampleImplementation is a test implementation of ExampleInterface type TestExampleImplementation struct { Mock } func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) { args := i.Called(a, b, c) return args.Int(0), errors.New("Whoops") } type options struct { num int str string } type OptionFn func(*options) func OpNum(n int) OptionFn { return func(o *options) { o.num = n } } func OpStr(s string) OptionFn { return func(o *options) { o.str = s } } func OpBytes(b []byte) OptionFn { return func(m *options) { m.str = string(b) } } func (i *TestExampleImplementation) TheExampleMethodFunctionalOptions(x string, opts ...OptionFn) error { args := i.Called(x, opts) return args.Error(0) } func TheExampleMethodFunctionalOptionsIndirect(i *TestExampleImplementation) { i.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo")) } //go:noinline func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) { i.Called(yesorno) } type ExampleType struct { ran bool } func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error { args := i.Called(et) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethod4(v ExampleInterface) error { args := i.Called(v) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethod5(ch chan struct{}) error { args := i.Called(ch) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethod6(m map[string]bool) error { args := i.Called(m) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethod7(slice []bool) error { args := i.Called(slice) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error { args := i.Called(fn) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error { args := i.Called(a) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...interface{}) error { args := i.Called(a) return args.Error(0) } func (i *TestExampleImplementation) TheExampleMethodMixedVariadic(a int, b ...int) error { args := i.Called(a, b) return args.Error(0) } type ExampleFuncType func(string) error func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { args := i.Called(fn) return args.Error(0) } // MockTestingT mocks a test struct type MockTestingT struct { logfCount, errorfCount, failNowCount int } // Helper is like [testing.T.Helper] but does nothing. func (MockTestingT) Helper() {} const mockTestingTFailNowCalled = "FailNow was called" func (m *MockTestingT) Logf(string, ...interface{}) { m.logfCount++ } func (m *MockTestingT) Errorf(string, ...interface{}) { m.errorfCount++ } // FailNow mocks the FailNow call. // It panics in order to mimic the FailNow behavior in the sense that // the execution stops. // When expecting this method, the call that invokes it should use the following code: // // assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...}) func (m *MockTestingT) FailNow() { m.failNowCount++ // this function should panic now to stop the execution as expected panic(mockTestingTFailNowCalled) } /* Mock */ func Test_Mock_TestData(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) if assert.NotNil(t, mockedService.TestData()) { mockedService.TestData().Set("something", 123) assert.Equal(t, 123, mockedService.TestData().Get("something").Data()) } } func Test_Mock_On(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService.On("TheExampleMethod") assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, "TheExampleMethod", c.Method) } func Test_Mock_Chained_On(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) // determine our current line number so we can assert the expected calls callerInfo properly _, filename, line, _ := runtime.Caller(0) mockedService. On("TheExampleMethod", 1, 2, 3). Return(0). On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). Return(nil) expectedCalls := []*Call{ { Parent: &mockedService.Mock, Method: "TheExampleMethod", Arguments: []interface{}{1, 2, 3}, ReturnArguments: []interface{}{0}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+2)}, }, { Parent: &mockedService.Mock, Method: "TheExampleMethod3", Arguments: []interface{}{AnythingOfType("*mock.ExampleType")}, ReturnArguments: []interface{}{nil}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+4)}, }, } assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) } func Test_Mock_On_WithArgs(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService.On("TheExampleMethod", 1, 2, 3, 4) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, "TheExampleMethod", c.Method) assert.Equal(t, Arguments{1, 2, 3, 4}, c.Arguments) } func Test_Mock_On_WithFuncArg(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethodFunc", AnythingOfType("func(string) error")). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, "TheExampleMethodFunc", c.Method) assert.Equal(t, 1, len(c.Arguments)) assert.Equal(t, AnythingOfType("func(string) error"), c.Arguments[0]) fn := func(string) error { return nil } assert.NotPanics(t, func() { mockedService.TheExampleMethodFunc(fn) }) } func Test_Mock_On_WithIntArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod", MatchedBy(func(a int) bool { return a == 1 }), MatchedBy(func(b int) bool { return b == 2 }), MatchedBy(func(c int) bool { return c == 3 })).Return(0, nil) assert.Panics(t, func() { mockedService.TheExampleMethod(1, 2, 4) }) assert.Panics(t, func() { mockedService.TheExampleMethod(2, 2, 3) }) assert.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) } func Test_Mock_On_WithArgMatcherThatPanics(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod2", MatchedBy(func(_ interface{}) bool { panic("try to lock mockedService") })).Return() defer func() { assertedExpectations := make(chan struct{}) go func() { tt := new(testing.T) mockedService.AssertExpectations(tt) close(assertedExpectations) }() select { case <-assertedExpectations: case <-time.After(time.Second): t.Fatal("AssertExpectations() deadlocked, did the panic leave mockedService locked?") } }() assert.Panics(t, func() { mockedService.TheExampleMethod2(false) }) } func TestMock_WithTest(t *testing.T) { t.Parallel() var ( mockedService TestExampleImplementation mockedTest MockTestingT ) mockedService.Test(&mockedTest) mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil) // Test that on an expected call, the test was not failed mockedService.TheExampleMethod(1, 2, 3) // Assert that Errorf and FailNow were not called assert.Equal(t, 0, mockedTest.errorfCount) assert.Equal(t, 0, mockedTest.failNowCount) // Test that on unexpected call, the mocked test was called to fail the test assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() { mockedService.TheExampleMethod(1, 1, 1) }) // Assert that Errorf and FailNow were called once assert.Equal(t, 1, mockedTest.errorfCount) assert.Equal(t, 1, mockedTest.failNowCount) } func Test_Mock_On_WithPtrArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod3", MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == true }), ).Return(nil) mockedService.On("TheExampleMethod3", MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == false }), ).Return(errors.New("error")) mockedService.On("TheExampleMethod3", MatchedBy(func(a *ExampleType) bool { return a == nil }), ).Return(errors.New("error2")) assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil) assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error") assert.EqualError(t, mockedService.TheExampleMethod3(nil), "error2") } func Test_Mock_On_WithFuncArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2") mockedService.On("TheExampleMethodFunc", MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture1 }), ).Return(errors.New("fixture1")) mockedService.On("TheExampleMethodFunc", MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture2 }), ).Return(errors.New("fixture2")) mockedService.On("TheExampleMethodFunc", MatchedBy(func(a func(string) error) bool { return a == nil }), ).Return(errors.New("fixture3")) assert.EqualError(t, mockedService.TheExampleMethodFunc( func(string) error { return fixture1 }), "fixture1") assert.EqualError(t, mockedService.TheExampleMethodFunc( func(string) error { return fixture2 }), "fixture2") assert.EqualError(t, mockedService.TheExampleMethodFunc(nil), "fixture3") } func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod4", MatchedBy(func(a ExampleInterface) bool { return a == nil }), ).Return(errors.New("fixture1")) assert.EqualError(t, mockedService.TheExampleMethod4(nil), "fixture1") } func Test_Mock_On_WithChannelArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod5", MatchedBy(func(ch chan struct{}) bool { return ch == nil }), ).Return(errors.New("fixture1")) assert.EqualError(t, mockedService.TheExampleMethod5(nil), "fixture1") } func Test_Mock_On_WithMapArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod6", MatchedBy(func(m map[string]bool) bool { return m == nil }), ).Return(errors.New("fixture1")) assert.EqualError(t, mockedService.TheExampleMethod6(nil), "fixture1") } func Test_Mock_On_WithSliceArgMatcher(t *testing.T) { t.Parallel() var mockedService TestExampleImplementation mockedService.On("TheExampleMethod7", MatchedBy(func(slice []bool) bool { return slice == nil }), ).Return(errors.New("fixture1")) assert.EqualError(t, mockedService.TheExampleMethod7(nil), "fixture1") } func Test_Mock_On_WithVariadicFunc(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethodVariadic", []int{1, 2, 3}). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, 1, len(c.Arguments)) assert.Equal(t, []int{1, 2, 3}, c.Arguments[0]) assert.NotPanics(t, func() { mockedService.TheExampleMethodVariadic(1, 2, 3) }) assert.Panics(t, func() { mockedService.TheExampleMethodVariadic(1, 2) }) } func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethodMixedVariadic", 1, []int{2, 3, 4}). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, 2, len(c.Arguments)) assert.Equal(t, 1, c.Arguments[0]) assert.Equal(t, []int{2, 3, 4}, c.Arguments[1]) assert.NotPanics(t, func() { mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 4) }) assert.Panics(t, func() { mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 5) }) } func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, 1, len(c.Arguments)) assert.Equal(t, []interface{}{1, 2, 3}, c.Arguments[0]) assert.NotPanics(t, func() { mockedService.TheExampleMethodVariadicInterface(1, 2, 3) }) assert.Panics(t, func() { mockedService.TheExampleMethodVariadicInterface(1, 2) }) } func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) var expected []interface{} c := mockedService. On("TheExampleMethodVariadicInterface", expected). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, 1, len(c.Arguments)) assert.Equal(t, expected, c.Arguments[0]) assert.NotPanics(t, func() { mockedService.TheExampleMethodVariadicInterface() }) assert.Panics(t, func() { mockedService.TheExampleMethodVariadicInterface(1, 2) }) } func Test_Mock_On_WithFuncPanics(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) assert.Panics(t, func() { mockedService.On("TheExampleMethodFunc", func(string) error { return nil }) }) } func Test_Mock_On_WithFuncTypeArg(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")). Return(nil) assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) assert.Equal(t, 1, len(c.Arguments)) assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), c.Arguments[0]) fn := func(string) error { return nil } assert.NotPanics(t, func() { mockedService.TheExampleMethodFuncType(fn) }) } func Test_Mock_Unset(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) call := mockedService. On("TheExampleMethodFuncType", "argA"). Return("blah") found, foundCall := mockedService.findExpectedCall("TheExampleMethodFuncType", "argA") require.NotEqual(t, -1, found) require.Equal(t, foundCall, call) call.Unset() found, foundCall = mockedService.findExpectedCall("TheExampleMethodFuncType", "argA") require.Equal(t, -1, found) var expectedCall *Call require.Equal(t, expectedCall, foundCall) fn := func(string) error { return nil } assert.Panics(t, func() { mockedService.TheExampleMethodFuncType(fn) }) } // Since every time you call On it creates a new object // the last time you call Unset it will only unset the last call func Test_Mock_Chained_UnsetOnlyUnsetsLastCall(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) // determine our current line number so we can assert the expected calls callerInfo properly _, filename, line, _ := runtime.Caller(0) mockedService. On("TheExampleMethod1", 1, 1). Return(0). On("TheExampleMethod2", 2, 2). On("TheExampleMethod3", 3, 3, 3). Return(nil). Unset() expectedCalls := []*Call{ { Parent: &mockedService.Mock, Method: "TheExampleMethod1", Arguments: []interface{}{1, 1}, ReturnArguments: []interface{}{0}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+2)}, }, { Parent: &mockedService.Mock, Method: "TheExampleMethod2", Arguments: []interface{}{2, 2}, ReturnArguments: []interface{}{}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+4)}, }, } assert.Equal(t, 2, len(expectedCalls)) assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) } func Test_Mock_UnsetIfAlreadyUnsetFails(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) mock1 := mockedService. On("TheExampleMethod1", 1, 1). Return(1) assert.Equal(t, 1, len(mockedService.ExpectedCalls)) mock1.Unset() assert.Equal(t, 0, len(mockedService.ExpectedCalls)) assert.Panics(t, func() { mock1.Unset() }) assert.Equal(t, 0, len(mockedService.ExpectedCalls)) } func Test_Mock_UnsetByOnMethodSpec(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) mock1 := mockedService. On("TheExampleMethod", 1, 2, 3). Return(0, nil) assert.Equal(t, 1, len(mockedService.ExpectedCalls)) mock1.On("TheExampleMethod", 1, 2, 3). Return(0, nil).Unset() assert.Equal(t, 0, len(mockedService.ExpectedCalls)) assert.Panics(t, func() { mock1.Unset() }) assert.Equal(t, 0, len(mockedService.ExpectedCalls)) } func Test_Mock_UnsetByOnMethodSpecAmongOthers(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) _, filename, line, _ := runtime.Caller(0) mock1 := mockedService. On("TheExampleMethod", 1, 2, 3). Return(0, nil). On("TheExampleMethodVariadic", 1, 2, 3, 4, 5).Once(). Return(nil) mock1. On("TheExampleMethodFuncType", Anything). Return(nil) assert.Equal(t, 3, len(mockedService.ExpectedCalls)) mock1.On("TheExampleMethod", 1, 2, 3). Return(0, nil).Unset() assert.Equal(t, 2, len(mockedService.ExpectedCalls)) expectedCalls := []*Call{ { Parent: &mockedService.Mock, Method: "TheExampleMethodVariadic", Repeatability: 1, Arguments: []interface{}{1, 2, 3, 4, 5}, ReturnArguments: []interface{}{nil}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+4)}, }, { Parent: &mockedService.Mock, Method: "TheExampleMethodFuncType", Arguments: []interface{}{Anything}, ReturnArguments: []interface{}{nil}, callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+7)}, }, } assert.Equal(t, 2, len(mockedService.ExpectedCalls)) assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) } func Test_Mock_Unset_WithFuncPanics(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) mock1 := mockedService.On("TheExampleMethod", 1) mock1.Arguments = append(mock1.Arguments, func(string) error { return nil }) assert.Panics(t, func() { mock1.Unset() }) } func Test_Mock_Return(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethod", "A", "B", true). Return(1, "two", true) require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 0, call.Repeatability) assert.Nil(t, call.WaitFor) } func Test_Mock_Panic(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethod", "A", "B", true). Panic("panic message for example method") require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 0, call.Repeatability) assert.Equal(t, 0, call.Repeatability) assert.Equal(t, "panic message for example method", *call.PanicMsg) assert.Nil(t, call.WaitFor) } func Test_Mock_Return_WaitUntil(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) ch := time.After(time.Second) c := mockedService.Mock. On("TheExampleMethod", "A", "B", true). WaitUntil(ch). Return(1, "two", true) // assert that the call was created require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 0, call.Repeatability) assert.Equal(t, ch, call.WaitFor) } func Test_Mock_Return_After(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService.Mock. On("TheExampleMethod", "A", "B", true). Return(1, "two", true). After(time.Second) require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.Mock.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 0, call.Repeatability) assert.NotEqual(t, nil, call.WaitFor) } func Test_Mock_Return_Run(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) fn := func(args Arguments) { arg := args.Get(0).(*ExampleType) arg.ran = true } c := mockedService.Mock. On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). Return(nil). Run(fn) require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.Mock.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod3", call.Method) assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0]) assert.Equal(t, nil, call.ReturnArguments[0]) assert.Equal(t, 0, call.Repeatability) assert.NotEqual(t, nil, call.WaitFor) assert.NotNil(t, call.Run) et := ExampleType{} assert.Equal(t, false, et.ran) mockedService.TheExampleMethod3(&et) assert.Equal(t, true, et.ran) } func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) f := func(args Arguments) { arg := args.Get(0).(*ExampleType) arg.ran = true } c := mockedService.Mock. On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). Run(f). Return(nil) require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.Mock.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod3", call.Method) assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0]) assert.Equal(t, nil, call.ReturnArguments[0]) assert.Equal(t, 0, call.Repeatability) assert.NotEqual(t, nil, call.WaitFor) assert.NotNil(t, call.Run) } func Test_Mock_Return_Once(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService.On("TheExampleMethod", "A", "B", true). Return(1, "two", true). Once() require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 1, call.Repeatability) assert.Nil(t, call.WaitFor) } func Test_Mock_Return_Twice(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethod", "A", "B", true). Return(1, "two", true). Twice() require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 2, call.Repeatability) assert.Nil(t, call.WaitFor) } func Test_Mock_Return_Times(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethod", "A", "B", true). Return(1, "two", true). Times(5) require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 1, call.ReturnArguments[0]) assert.Equal(t, "two", call.ReturnArguments[1]) assert.Equal(t, true, call.ReturnArguments[2]) assert.Equal(t, 5, call.Repeatability) assert.Nil(t, call.WaitFor) } func Test_Mock_Return_Nothing(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) c := mockedService. On("TheExampleMethod", "A", "B", true). Return() require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) call := mockedService.ExpectedCalls[0] assert.Equal(t, "TheExampleMethod", call.Method) assert.Equal(t, "A", call.Arguments[0]) assert.Equal(t, "B", call.Arguments[1]) assert.Equal(t, true, call.Arguments[2]) assert.Equal(t, 0, len(call.ReturnArguments)) } func Test_Mock_Return_NotBefore_In_Order(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) b := mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil) c := mockedService. On("TheExampleMethod2", true). Return(). NotBefore(b) require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) require.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) require.NotPanics(t, func() { mockedService.TheExampleMethod2(true) }) } func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) InOrder( mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil), mockedService. On("TheExampleMethod2", true). Return(), ) require.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) require.NotPanics(t, func() { mockedService.TheExampleMethod2(true) }) } func Test_Mock_Return_NotBefore_Out_Of_Order(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) b := mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil).Twice() c := mockedService. On("TheExampleMethod2", true). Return(). NotBefore(b) require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) expectedPanicString := `mock: Unexpected Method Call ----------------------------- TheExampleMethod2(bool) 0: true Must not be called before: TheExampleMethod(int,int,int) 0: 1 1: 2 2: 3` require.PanicsWithValue(t, expectedPanicString, func() { mockedService.TheExampleMethod2(true) }) } func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) InOrder( mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil).Twice(), mockedService. On("TheExampleMethod2", true). Return(), ) expectedPanicString := `mock: Unexpected Method Call ----------------------------- TheExampleMethod2(bool) 0: true Must not be called before: TheExampleMethod(int,int,int) 0: 1 1: 2 2: 3` require.PanicsWithValue(t, expectedPanicString, func() { mockedService.TheExampleMethod2(true) }) } func Test_Mock_Return_NotBefore_Not_Enough_Times(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) b := mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil).Twice() c := mockedService. On("TheExampleMethod2", true). Return(). NotBefore(b) require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) require.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) expectedPanicString := `mock: Unexpected Method Call ----------------------------- TheExampleMethod2(bool) 0: true Must not be called before another call of: TheExampleMethod(int,int,int) 0: 1 1: 2 2: 3` require.PanicsWithValue(t, expectedPanicString, func() { mockedService.TheExampleMethod2(true) }) } func Test_Mock_Return_NotBefore_Different_Mock_In_Order(t *testing.T) { t.Parallel() var ( mockedService1 = new(TestExampleImplementation) mockedService2 = new(TestExampleImplementation) ) b := mockedService1. On("TheExampleMethod", 1, 2, 3). Return(4, nil) c := mockedService2. On("TheExampleMethod2", true). Return(). NotBefore(b) require.Equal(t, []*Call{c}, mockedService2.ExpectedCalls) require.NotPanics(t, func() { mockedService1.TheExampleMethod(1, 2, 3) }) require.NotPanics(t, func() { mockedService2.TheExampleMethod2(true) }) } func Test_Mock_Return_NotBefore_Different_Mock_Out_Of_Order(t *testing.T) { t.Parallel() var ( mockedService1 = new(TestExampleImplementation) mockedService2 = new(TestExampleImplementation) ) b := mockedService1. On("TheExampleMethod", 1, 2, 3). Return(4, nil) c := mockedService2. On("TheExampleMethod2", true). Return(). NotBefore(b) require.Equal(t, []*Call{c}, mockedService2.ExpectedCalls) expectedPanicString := `mock: Unexpected Method Call ----------------------------- TheExampleMethod2(bool) 0: true Must not be called before method from another mock instance: TheExampleMethod(int,int,int) 0: 1 1: 2 2: 3` require.PanicsWithValue(t, expectedPanicString, func() { mockedService2.TheExampleMethod2(true) }) } func Test_Mock_Return_NotBefore_In_Order_With_Non_Dependant(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) a := mockedService. On("TheExampleMethod", 1, 2, 3). Return(4, nil) b := mockedService. On("TheExampleMethod", 4, 5, 6). Return(4, nil) c := mockedService. On("TheExampleMethod2", true). Return(). NotBefore(a, b) d := mockedService. On("TheExampleMethod7", []bool{}).Return(nil) require.Equal(t, []*Call{a, b, c, d}, mockedService.ExpectedCalls) require.NotPanics(t, func() { mockedService.TheExampleMethod7([]bool{}) }) require.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) require.NotPanics(t, func() { mockedService.TheExampleMethod7([]bool{}) }) require.NotPanics(t, func() { mockedService.TheExampleMethod(4, 5, 6) }) require.NotPanics(t, func() { mockedService.TheExampleMethod7([]bool{}) }) require.NotPanics(t, func() { mockedService.TheExampleMethod2(true) }) require.NotPanics(t, func() { mockedService.TheExampleMethod7([]bool{}) }) } func Test_Mock_Return_NotBefore_Orphan_Call(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) require.PanicsWithValue(t, "not before calls must be created with Mock.On()", func() { mockedService. On("TheExampleMethod2", true). Return(). NotBefore(&Call{Method: "Not", Arguments: Arguments{"how", "it's"}, ReturnArguments: Arguments{"done"}}) }) } func Test_Mock_findExpectedCall(t *testing.T) { t.Parallel() m := new(Mock) m.On("One", 1).Return("one") m.On("Two", 2).Return("two") m.On("Two", 3).Return("three") f, c := m.findExpectedCall("Two", 3) if assert.Equal(t, 2, f) { if assert.NotNil(t, c) { assert.Equal(t, "Two", c.Method) assert.Equal(t, 3, c.Arguments[0]) assert.Equal(t, "three", c.ReturnArguments[0]) } } } func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) { t.Parallel() m := new(Mock) m.On("One", 1).Return("one") m.On("Two", 2).Return("two") m.On("Two", 3).Return("three") f, _ := m.findExpectedCall("Two") assert.Equal(t, -1, f) } func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) { t.Parallel() m := new(Mock) m.On("One", 1).Return("one") m.On("Two", 2).Return("two").Once() m.On("Two", 3).Return("three").Twice() m.On("Two", 3).Return("three").Times(8) f, c := m.findExpectedCall("Two", 3) if assert.Equal(t, 2, f) { if assert.NotNil(t, c) { assert.Equal(t, "Two", c.Method) assert.Equal(t, 3, c.Arguments[0]) assert.Equal(t, "three", c.ReturnArguments[0]) } } c = m.On("Once", 1).Return("one").Once() c.Repeatability = -1 f, c = m.findExpectedCall("Once", 1) if assert.Equal(t, -1, f) { if assert.NotNil(t, c) { assert.Equal(t, "Once", c.Method) assert.Equal(t, 1, c.Arguments[0]) assert.Equal(t, "one", c.ReturnArguments[0]) } } } func Test_callString(t *testing.T) { t.Parallel() assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false)) assert.Equal(t, `Method()`, callString("Method", []interface{}{nil}, false)) } func Test_Mock_Called(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true) returnArguments := mockedService.Called(1, 2, 3) if assert.Equal(t, 1, len(mockedService.Calls)) { assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method) assert.Equal(t, 1, mockedService.Calls[0].Arguments[0]) assert.Equal(t, 2, mockedService.Calls[0].Arguments[1]) assert.Equal(t, 3, mockedService.Calls[0].Arguments[2]) } if assert.Equal(t, 3, len(returnArguments)) { assert.Equal(t, 5, returnArguments[0]) assert.Equal(t, "6", returnArguments[1]) assert.Equal(t, true, returnArguments[2]) } } func asyncCall(m *Mock, ch chan Arguments) { ch <- m.Called(1, 2, 3) } func Test_Mock_Called_blocks(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(20 * time.Millisecond) ch := make(chan Arguments) go asyncCall(&mockedService.Mock, ch) select { case <-ch: t.Fatal("should have waited") case <-time.After(10 * time.Millisecond): } returnArguments := <-ch if assert.Equal(t, 1, len(mockedService.Mock.Calls)) { assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method) assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0]) assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1]) assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2]) } if assert.Equal(t, 3, len(returnArguments)) { assert.Equal(t, 5, returnArguments[0]) assert.Equal(t, "6", returnArguments[1]) assert.Equal(t, true, returnArguments[2]) } } func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService. On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3). Return(5, "6", true). Once() mockedService. On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3). Return(-1, "hi", false) returnArguments1 := mockedService.Called(1, 2, 3) returnArguments2 := mockedService.Called(1, 2, 3) if assert.Equal(t, 2, len(mockedService.Calls)) { assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method) assert.Equal(t, 1, mockedService.Calls[0].Arguments[0]) assert.Equal(t, 2, mockedService.Calls[0].Arguments[1]) assert.Equal(t, 3, mockedService.Calls[0].Arguments[2]) assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method) assert.Equal(t, 1, mockedService.Calls[1].Arguments[0]) assert.Equal(t, 2, mockedService.Calls[1].Arguments[1]) assert.Equal(t, 3, mockedService.Calls[1].Arguments[2]) } if assert.Equal(t, 3, len(returnArguments1)) { assert.Equal(t, 5, returnArguments1[0]) assert.Equal(t, "6", returnArguments1[1]) assert.Equal(t, true, returnArguments1[2]) } if assert.Equal(t, 3, len(returnArguments2)) { assert.Equal(t, -1, returnArguments2[0]) assert.Equal(t, "hi", returnArguments2[1]) assert.Equal(t, false, returnArguments2[2]) } } func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4) mockedService.TheExampleMethod(1, 2, 3) mockedService.TheExampleMethod(1, 2, 3) mockedService.TheExampleMethod(1, 2, 3) mockedService.TheExampleMethod(1, 2, 3) assert.Panics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) } func Test_Mock_Called_Unexpected(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) // make sure it panics if no expectation was made assert.Panics(t, func() { mockedService.Called(1, 2, 3) }, "Calling unexpected method should panic") } func Test_AssertExpectationsForObjects_Helper(t *testing.T) { t.Parallel() var mockedService1 = new(TestExampleImplementation) var mockedService2 = new(TestExampleImplementation) var mockedService3 = new(TestExampleImplementation) var mockedService4 = new(TestExampleImplementation) // No expectations does not cause a panic mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return() mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return() mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return() mockedService1.Called(1) mockedService2.Called(2) mockedService3.Called(3) assert.True(t, AssertExpectationsForObjects(t, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock, &mockedService4.Mock)) assert.True(t, AssertExpectationsForObjects(t, mockedService1, mockedService2, mockedService3, mockedService4)) } func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) { t.Parallel() var mockedService1 = new(TestExampleImplementation) var mockedService2 = new(TestExampleImplementation) var mockedService3 = new(TestExampleImplementation) mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return() mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return() mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return() mockedService1.Called(1) mockedService3.Called(3) tt := new(testing.T) assert.False(t, AssertExpectationsForObjects(tt, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock)) assert.False(t, AssertExpectationsForObjects(tt, mockedService1, mockedService2, mockedService3)) } func Test_Mock_AssertExpectations(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7) tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.Called(1, 2, 3) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectations_Placeholder_NoArgs(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(5, 6, 7).Once() mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(7, 6, 5) tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.Called() // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectations_Placeholder(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations_Placeholder", 1, 2, 3).Return(5, 6, 7).Once() mockedService.On("Test_Mock_AssertExpectations_Placeholder", 3, 2, 1).Return(7, 6, 5) tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.Called(1, 2, 3) // now assert expectations assert.False(t, mockedService.AssertExpectations(tt)) // make call to the second expectation mockedService.Called(3, 2, 1) // now assert expectations again assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectations_With_Pointers(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{1}).Return(1) mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{2}).Return(2) tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) s := struct{ Foo int }{1} // make the calls now mockedService.Called(&s) s.Foo = 2 mockedService.Called(&s) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectationsCustomType(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.TheExampleMethod3(&ExampleType{}) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectationsFunctionalOptionsType(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo")) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions()).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.TheExampleMethodFunctionalOptions("test") // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectationsFunctionalOptionsType_Indirectly(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now TheExampleMethodFunctionalOptionsIndirect(mockedService) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Func(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) assert.Panics(t, func() { mockedService.TheExampleMethodFunctionalOptions("test", OpBytes([]byte("this"))) }) } func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Arg(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) assert.Panics(t, func() { mockedService.TheExampleMethodFunctionalOptions("test", OpStr("that")) }) } func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice() tt := new(testing.T) assert.False(t, mockedService.AssertExpectations(tt)) // make the call now mockedService.Called(1, 2, 3) assert.False(t, mockedService.AssertExpectations(tt)) mockedService.Called(1, 2, 3) // now assert expectations assert.True(t, mockedService.AssertExpectations(tt)) } func Test_Mock_AssertExpectations_Skipped_Test(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertExpectations_Skipped_Test", 1, 2, 3).Return(5, 6, 7) defer mockedService.AssertExpectations(t) t.Skip("skipping test to ensure AssertExpectations does not fail") } func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7) mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7) args1 := mockedService.Called(1, 2, 3) assert.Equal(t, 5, args1.Int(0)) assert.Equal(t, 6, args1.Int(1)) assert.Equal(t, 7, args1.Int(2)) args2 := mockedService.Called(4, 5, 6) assert.Equal(t, 5, args2.Int(0)) assert.Equal(t, 6, args2.Int(1)) assert.Equal(t, 7, args2.Int(2)) } func Test_Mock_AssertNumberOfCalls(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7) mockedService.Called(1, 2, 3) assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1)) mockedService.Called(1, 2, 3) assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2)) } func Test_Mock_AssertCalled(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7) mockedService.Called(1, 2, 3) assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3)) } func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService. On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything). Return() mockedService.Called(1, "two", []uint8("three")) assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8"))) } func Test_Mock_AssertCalled_WithArguments(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7) mockedService.Called(1, 2, 3) tt := new(testing.T) assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3)) assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4)) } func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once() mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once() mockedService.Called(1, 2, 3) mockedService.Called(2, 3, 4) tt := new(testing.T) assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3)) assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4)) assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5)) } func Test_Mock_AssertNotCalled(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7) mockedService.Called(1, 2, 3) assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled")) } func Test_Mock_IsMethodCallable(t *testing.T) { t.Parallel() var mockedService = new(TestExampleImplementation) arg := []Call{{Repeatability: 1}, {Repeatability: 2}} arg2 := []Call{{Repeatability: 1}, {Repeatability: 1}} arg3 := []Call{{Repeatability: 1}, {Repeatability: 1}} mockedService.On("Test_Mock_IsMethodCallable", arg2).Return(true).Twice() assert.False(t, mockedService.IsMethodCallable(t, "Test_Mock_IsMethodCallable", arg)) assert.True(t, mockedService.IsMethodCallable(t, "Test_Mock_IsMethodCallable", arg2)) assert.True(t, mockedService.IsMethodCallable(t, "Test_Mock_IsMethodCallable", arg3)) mockedService.MethodCalled("Test_Mock_IsMethodCallable", arg2) mockedService.MethodCalled("Test_Mock_IsMethodCallable", arg2) assert.False(t, mockedService.IsMethodCallable(t, "Test_Mock_IsMethodCallable", arg2)) } func TestIsArgsEqual(t *testing.T) { t.Parallel() var expected = Arguments{5, 3, 4, 6, 7, 2} // Copy elements 1 to 5 args := append(([]interface{})(nil), expected[1:]...) args[2] = expected[1] assert.False(t, isArgsEqual(expected, args)) // Clone arr := append(([]interface{})(nil), expected...) assert.True(t, isArgsEqual(expected, arr)) } func Test_Mock_AssertOptional(t *testing.T) { t.Parallel() // Optional called var ms1 = new(TestExampleImplementation) ms1.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil) ms1.TheExampleMethod(1, 2, 3) tt1 := new(testing.T) assert.Equal(t, true, ms1.AssertExpectations(tt1)) // Optional not called var ms2 = new(TestExampleImplementation) ms2.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil) tt2 := new(testing.T) assert.Equal(t, true, ms2.AssertExpectations(tt2)) // Non-optional called var ms3 = new(TestExampleImplementation) ms3.On("TheExampleMethod", 1, 2, 3).Return(4, nil) ms3.TheExampleMethod(1, 2, 3) tt3 := new(testing.T) assert.Equal(t, true, ms3.AssertExpectations(tt3)) } /* Arguments helper methods */ func Test_Arguments_Get(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.Equal(t, "string", args.Get(0).(string)) assert.Equal(t, 123, args.Get(1).(int)) assert.Equal(t, true, args.Get(2).(bool)) } func Test_Arguments_Is(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.True(t, args.Is("string", 123, true)) assert.False(t, args.Is("wrong", 456, false)) } func Test_Arguments_Diff(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"Hello World", 123, true}) var diff string var count int diff, count = args.Diff([]interface{}{"Hello World", 456, "false"}) assert.Equal(t, 2, count) assert.Contains(t, diff, `(int=456) != (int=123)`) assert.Contains(t, diff, `(string=false) != (bool=true)`) } func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) var diff string var count int diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"}) assert.Equal(t, 3, count) assert.Contains(t, diff, `(string=extra) != (Missing)`) } func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) var count int _, count = args.Diff([]interface{}{"string", Anything, true}) assert.Equal(t, 0, count) } func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", Anything, true}) var count int _, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 0, count) } func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", AnythingOfType("int"), true}) var count int _, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 0, count) } func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", AnythingOfType("string"), true}) var count int var diff string diff, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 1, count) assert.Contains(t, diff, `string != type int - (int=123)`) } func Test_Arguments_Diff_WithIsTypeArgument(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", IsType(0), true}) var count int _, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 0, count) } func Test_Arguments_Diff_WithIsTypeArgument_Failing(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", IsType(""), true}) var count int var diff string diff, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 1, count) assert.Contains(t, diff, `string != type int - (int=123)`) } func Test_Arguments_Diff_WithIsTypeArgument_InterfaceType(t *testing.T) { t.Parallel() var ctx = context.Background() args := Arguments([]interface{}{IsType(ctx)}) _, count := args.Diff([]interface{}{context.Background()}) assert.Equal(t, 0, count) } func Test_Arguments_Diff_WithIsTypeArgument_InterfaceType_Failing(t *testing.T) { t.Parallel() var ctx context.Context var args = Arguments([]interface{}{IsType(ctx)}) diff, count := args.Diff([]interface{}{context.Background()}) assert.Equal(t, 1, count) assert.Contains(t, diff, `type != type `) } func Test_Arguments_Diff_WithArgMatcher(t *testing.T) { t.Parallel() matchFn := func(a int) bool { return a == 123 } var args = Arguments([]interface{}{"string", MatchedBy(matchFn), true}) diff, count := args.Diff([]interface{}{"string", 124, true}) assert.Equal(t, 1, count) assert.Contains(t, diff, `(int=124) not matched by func(int) bool`) diff, count = args.Diff([]interface{}{"string", false, true}) assert.Equal(t, 1, count) assert.Contains(t, diff, `(bool=false) not matched by func(int) bool`) diff, count = args.Diff([]interface{}{"string", 123, false}) assert.Equal(t, 1, count) assert.Contains(t, diff, `(int=123) matched by func(int) bool`) diff, count = args.Diff([]interface{}{"string", 123, true}) assert.Equal(t, 0, count) assert.Contains(t, diff, `No differences.`) } func Test_Arguments_Assert(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.True(t, args.Assert(t, "string", 123, true)) } func Test_Arguments_String_Representation(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.Equal(t, `string,int,bool`, args.String()) } func Test_Arguments_String(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.Equal(t, "string", args.String(0)) } func Test_Arguments_Error(t *testing.T) { t.Parallel() var err = errors.New("An Error") var args = Arguments([]interface{}{"string", 123, true, err}) assert.Equal(t, err, args.Error(3)) } func Test_Arguments_Error_Nil(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true, nil}) assert.Equal(t, nil, args.Error(3)) } func Test_Arguments_Int(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.Equal(t, 123, args.Int(1)) } func Test_Arguments_Bool(t *testing.T) { t.Parallel() var args = Arguments([]interface{}{"string", 123, true}) assert.Equal(t, true, args.Bool(2)) } func Test_WaitUntil_Parallel(t *testing.T) { t.Parallel() // make a test impl object var mockedService = new(TestExampleImplementation) ch1 := make(chan time.Time) ch2 := make(chan time.Time) mockedService.Mock.On("TheExampleMethod2", true).Return().WaitUntil(ch2).Run(func(args Arguments) { ch1 <- time.Now() }) mockedService.Mock.On("TheExampleMethod2", false).Return().WaitUntil(ch1) // Lock both goroutines on the .WaitUntil method go func() { mockedService.TheExampleMethod2(false) }() go func() { mockedService.TheExampleMethod2(true) }() // Allow the first call to execute, so the second one executes afterwards ch2 <- time.Now() } func Test_MockMethodCalled(t *testing.T) { t.Parallel() m := new(Mock) m.On("foo", "hello").Return("world") retArgs := m.MethodCalled("foo", "hello") require.True(t, len(retArgs) == 1) require.Equal(t, "world", retArgs[0]) m.AssertExpectations(t) } func Test_MockMethodCalled_Panic(t *testing.T) { t.Parallel() m := new(Mock) m.On("foo", "hello").Panic("world panics") require.PanicsWithValue(t, "world panics", func() { m.MethodCalled("foo", "hello") }) m.AssertExpectations(t) } // Test to validate fix for racy concurrent call access in MethodCalled() func Test_MockReturnAndCalledConcurrent(t *testing.T) { t.Parallel() iterations := 1000 m := &Mock{} call := m.On("ConcurrencyTestMethod") wg := sync.WaitGroup{} wg.Add(2) go func() { for i := 0; i < iterations; i++ { call.Return(10) } wg.Done() }() go func() { for i := 0; i < iterations; i++ { ConcurrencyTestMethod(m) } wg.Done() }() wg.Wait() } type timer struct{ Mock } func (s *timer) GetTime(i int) string { return s.Called(i).Get(0).(string) } func (s *timer) GetTimes(times []int) string { return s.Called(times).Get(0).(string) } type tCustomLogger struct { *testing.T logs []string errs []string } func (tc *tCustomLogger) Logf(format string, args ...interface{}) { tc.T.Logf(format, args...) tc.logs = append(tc.logs, fmt.Sprintf(format, args...)) } func (tc *tCustomLogger) Errorf(format string, args ...interface{}) { tc.errs = append(tc.errs, fmt.Sprintf(format, args...)) } func (tc *tCustomLogger) FailNow() {} func TestLoggingAssertExpectations(t *testing.T) { t.Parallel() m := new(timer) m.On("GetTime", 0).Return("") tcl := &tCustomLogger{t, []string{}, []string{}} AssertExpectationsForObjects(tcl, m, new(TestExampleImplementation)) require.Equal(t, 1, len(tcl.errs)) assert.Regexp(t, regexp.MustCompile("(?s)FAIL: 0 out of 1 expectation\\(s\\) were met.*The code you are testing needs to make 1 more call\\(s\\).*"), tcl.errs[0]) require.Equal(t, 2, len(tcl.logs)) assert.Regexp(t, regexp.MustCompile("(?s)FAIL:\tGetTime\\(int\\).*"), tcl.logs[0]) require.Equal(t, "Expectations didn't match for Mock: *mock.timer", tcl.logs[1]) } func TestAfterTotalWaitTimeWhileExecution(t *testing.T) { t.Parallel() waitDuration := 1 total, waitMs := 5, time.Millisecond*time.Duration(waitDuration) aTimer := new(timer) for i := 0; i < total; i++ { aTimer.On("GetTime", i).After(waitMs).Return(fmt.Sprintf("Time%d", i)).Once() } time.Sleep(waitMs) start := time.Now() var results []string for i := 0; i < total; i++ { results = append(results, aTimer.GetTime(i)) } end := time.Now() elapsedTime := end.Sub(start) assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be at least greater than %v", elapsedTime, waitMs)) assert.Equal(t, total, len(results)) for i := range results { assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same") } } func TestArgumentMatcherToPrintMismatch(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { matchingExp := regexp.MustCompile( `\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool\nat: \[[^\]]+mock\/mock_test.go`) assert.Regexp(t, matchingExp, r) } }() m := new(timer) m.On("GetTime", MatchedBy(func(i int) bool { return false })).Return("SomeTime").Once() res := m.GetTime(1) require.Equal(t, "SomeTime", res) m.AssertExpectations(t) } func TestArgumentMatcherToPrintMismatchWithReferenceType(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { matchingExp := regexp.MustCompile( `\s+mock: Unexpected Method Call\s+-*\s+GetTimes\(\[\]int\)\s+0: \[\]int\{1\}\s+The closest call I have is:\s+GetTimes\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(\[\]int=\[1\]\) not matched by func\(\[\]int\) bool\nat: \[[^\]]+mock\/mock_test.go`) assert.Regexp(t, matchingExp, r) } }() m := new(timer) m.On("GetTimes", MatchedBy(func(_ []int) bool { return false })).Return("SomeTime").Once() res := m.GetTimes([]int{1}) require.Equal(t, "SomeTime", res) m.AssertExpectations(t) } func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `Diff: 0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`)) assert.Regexp(t, matchingExp, r) } }() m := new(TestExampleImplementation) m.On("TheExampleMethod", 1, 1, 1).Return(1, nil).Once() m.On("TheExampleMethod", 2, 2, 2).Return(2, nil).Once() m.TheExampleMethod(1, 1, 2) } func TestClosestCallFavorsFirstMock(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -2,4 \+2,4 @@\s+\(bool\) true,\s+- \(bool\) true,\s+- \(bool\) true\s+\+ \(bool\) false,\s+\+ \(bool\) false\s+}\s+Diff: 0: FAIL: \(\[\]bool=\[(true\s?|false\s?){3}]\) != \(\[\]bool=\[(true\s?|false\s?){3}\]\)` matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, false, false}`, `0: \[\]bool{true, true, true}`, diffRegExp)) assert.Regexp(t, matchingExp, r) } }() m := new(TestExampleImplementation) m.On("TheExampleMethod7", []bool{true, true, true}).Return(nil).Once() m.On("TheExampleMethod7", []bool{false, false, false}).Return(nil).Once() m.TheExampleMethod7([]bool{true, false, false}) } func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -1,4 \+1,4 @@\s+\(\[\]bool\) \(len=3\) {\s+- \(bool\) false,\s+- \(bool\) false,\s+\+ \(bool\) true,\s+\+ \(bool\) true,\s+\(bool\) false\s+Diff: 0: FAIL: \(\[\]bool=\[(true\s?|false\s?){3}]\) != \(\[\]bool=\[(true\s?|false\s?){3}\]\)` matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, true, false}`, `0: \[\]bool{false, false, false}`, diffRegExp)) assert.Regexp(t, matchingExp, r) } }() m := new(TestExampleImplementation) m.On("TheExampleMethod7", []bool{true, true, true}).Return(nil).Once() m.On("TheExampleMethod7", []bool{false, false, false}).Return(nil).Once() m.TheExampleMethod7([]bool{true, true, true}) // Since the first mocked call has already been used, it now has no repeatability, // thus the second mock should be shown as the closest match m.TheExampleMethod7([]bool{true, true, false}) } func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) { t.Parallel() defer func() { if r := recover(); r != nil { matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `Diff: 0: FAIL: \(int=1\) != \(int=999\)`)) assert.Regexp(t, matchingExp, r) } }() m := new(timer) m.On("GetTime", 999).Return("SomeTime").Once() _ = m.GetTime(1) } func Test_isBetterMatchThanReturnsFalseIfCandidateCallIsNil(t *testing.T) { t.Parallel() assert.False(t, matchCandidate{}.isBetterMatchThan(matchCandidate{})) } func Test_isBetterMatchThanReturnsTrueIfOtherCandidateCallIsNil(t *testing.T) { t.Parallel() assert.True(t, matchCandidate{call: &Call{}}.isBetterMatchThan(matchCandidate{})) } func Test_isBetterMatchThanReturnsFalseIfDiffCountIsGreaterThanOther(t *testing.T) { t.Parallel() assert.False(t, matchCandidate{call: &Call{}, diffCount: 2}.isBetterMatchThan(matchCandidate{call: &Call{}, diffCount: 1})) } func Test_isBetterMatchThanReturnsTrueIfDiffCountIsLessThanOther(t *testing.T) { t.Parallel() assert.True(t, matchCandidate{call: &Call{}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{}, diffCount: 2})) } func Test_isBetterMatchThanReturnsTrueIfRepeatabilityIsGreaterThanOther(t *testing.T) { t.Parallel() assert.True(t, matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{Repeatability: -1}, diffCount: 1})) } func Test_isBetterMatchThanReturnsFalseIfRepeatabilityIsLessThanOrEqualToOther(t *testing.T) { t.Parallel() assert.False(t, matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1})) } func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string { rMethod := regexp.QuoteMeta(method) return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+%s\nat: \[[^\]]+mock\/mock_test.go`, rMethod, calledArg, rMethod, expectedArg, diff) } //go:noinline func ConcurrencyTestMethod(m *Mock) { m.Called() } func TestConcurrentArgumentRead(t *testing.T) { t.Parallel() methodUnderTest := func(c caller, u user) { go u.Use(c) c.Call() } c := &mockCaller{} defer c.AssertExpectations(t) u := &mockUser{} defer u.AssertExpectations(t) done := make(chan struct{}) c.On("Call").Return().Once() u.On("Use", c).Return().Once().Run(func(args Arguments) { close(done) }) methodUnderTest(c, u) <-done // wait until Use is called or assertions will fail } type caller interface { Call() } type mockCaller struct{ Mock } func (m *mockCaller) Call() { m.Called() } type user interface { Use(caller) } type mockUser struct{ Mock } func (m *mockUser) Use(c caller) { m.Called(c) } type mutatingStringer struct { N int s string } func (m *mutatingStringer) String() string { m.s = strconv.Itoa(m.N) return m.s } func TestIssue1785ArgumentWithMutatingStringer(t *testing.T) { m := &Mock{} m.On("Method", &mutatingStringer{N: 2}) m.On("Method", &mutatingStringer{N: 1}) m.MethodCalled("Method", &mutatingStringer{N: 1}) m.MethodCalled("Method", &mutatingStringer{N: 2}) m.AssertExpectations(t) } func TestIssue1227AssertExpectationsForObjectsWithMock(t *testing.T) { mockT := &MockTestingT{} AssertExpectationsForObjects(mockT, Mock{}) assert.Equal(t, 1, mockT.errorfCount) } ================================================ FILE: package_test.go ================================================ package testify import ( "testing" "github.com/stretchr/testify/assert" ) func TestImports(t *testing.T) { if assert.Equal(t, 1, 1) != true { t.Error("Something is wrong.") } } ================================================ FILE: require/doc.go ================================================ // Package require implements the same assertions as the assert package but // stops test execution when a test fails. // // # Example Usage // // The following is a complete example using require in a standard test function: // // import ( // "testing" // "github.com/stretchr/testify/require" // ) // // func TestSomething(t *testing.T) { // // var a string = "Hello" // var b string = "Hello" // // require.Equal(t, a, b, "The two words should be the same.") // // } // // # Assertions // // The require package have same global functions as in the assert package, // but instead of returning a boolean result they call [testing.T.FailNow]. // A consequence of this is that it must be called from the goroutine running // the test function, not from other goroutines created during the test. // // Every assertion function also takes an optional string message as the final argument, // allowing custom error messages to be appended to the message the assertion method outputs. package require ================================================ FILE: require/forward_requirements.go ================================================ package require // Assertions provides assertion methods around the // TestingT interface. type Assertions struct { t TestingT } // New makes a new Assertions object for the specified TestingT. func New(t TestingT) *Assertions { return &Assertions{ t: t, } } //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" ================================================ FILE: require/forward_requirements_test.go ================================================ package require import ( "errors" "testing" "time" ) func TestImplementsWrapper(t *testing.T) { t.Parallel() require := New(t) require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestIsNotTypeWrapper(t *testing.T) { t.Parallel() require := New(t) require.IsNotType(new(AssertionTesterNonConformingObject), new(AssertionTesterConformingObject)) mockT := new(MockT) mockRequire := New(mockT) mockRequire.IsNotType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestIsTypeWrapper(t *testing.T) { t.Parallel() require := New(t) require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) mockT := new(MockT) mockRequire := New(mockT) mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestEqualWrapper(t *testing.T) { t.Parallel() require := New(t) require.Equal(1, 1) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Equal(1, 2) if !mockT.Failed { t.Error("Check should fail") } } func TestNotEqualWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotEqual(1, 2) mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotEqual(2, 2) if !mockT.Failed { t.Error("Check should fail") } } func TestExactlyWrapper(t *testing.T) { t.Parallel() require := New(t) a := float32(1) b := float32(1) c := float64(1) require.Exactly(a, b) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Exactly(a, c) if !mockT.Failed { t.Error("Check should fail") } } func TestNotNilWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotNil(t, new(AssertionTesterConformingObject)) mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotNil(nil) if !mockT.Failed { t.Error("Check should fail") } } func TestNilWrapper(t *testing.T) { t.Parallel() require := New(t) require.Nil(nil) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Nil(new(AssertionTesterConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestTrueWrapper(t *testing.T) { t.Parallel() require := New(t) require.True(true) mockT := new(MockT) mockRequire := New(mockT) mockRequire.True(false) if !mockT.Failed { t.Error("Check should fail") } } func TestFalseWrapper(t *testing.T) { t.Parallel() require := New(t) require.False(false) mockT := new(MockT) mockRequire := New(mockT) mockRequire.False(true) if !mockT.Failed { t.Error("Check should fail") } } func TestContainsWrapper(t *testing.T) { t.Parallel() require := New(t) require.Contains("Hello World", "Hello") mockT := new(MockT) mockRequire := New(mockT) mockRequire.Contains("Hello World", "Salut") if !mockT.Failed { t.Error("Check should fail") } } func TestNotContainsWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotContains("Hello World", "Hello!") mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotContains("Hello World", "Hello") if !mockT.Failed { t.Error("Check should fail") } } func TestPanicsWrapper(t *testing.T) { t.Parallel() require := New(t) require.Panics(func() { panic("Panic!") }) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Panics(func() {}) if !mockT.Failed { t.Error("Check should fail") } } func TestNotPanicsWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotPanics(func() {}) mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotPanics(func() { panic("Panic!") }) if !mockT.Failed { t.Error("Check should fail") } } func TestNoErrorWrapper(t *testing.T) { t.Parallel() require := New(t) require.NoError(nil) mockT := new(MockT) mockRequire := New(mockT) mockRequire.NoError(errors.New("some error")) if !mockT.Failed { t.Error("Check should fail") } } func TestErrorWrapper(t *testing.T) { t.Parallel() require := New(t) require.Error(errors.New("some error")) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Error(nil) if !mockT.Failed { t.Error("Check should fail") } } func TestErrorContainsWrapper(t *testing.T) { t.Parallel() require := New(t) require.ErrorContains(errors.New("some error: another error"), "some error") mockT := new(MockT) mockRequire := New(mockT) mockRequire.ErrorContains(errors.New("some error: another error"), "different error") if !mockT.Failed { t.Error("Check should fail") } } func TestEqualErrorWrapper(t *testing.T) { t.Parallel() require := New(t) require.EqualError(errors.New("some error"), "some error") mockT := new(MockT) mockRequire := New(mockT) mockRequire.EqualError(errors.New("some error"), "Not some error") if !mockT.Failed { t.Error("Check should fail") } } func TestEmptyWrapper(t *testing.T) { t.Parallel() require := New(t) require.Empty("") mockT := new(MockT) mockRequire := New(mockT) mockRequire.Empty("x") if !mockT.Failed { t.Error("Check should fail") } } func TestNotEmptyWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotEmpty("x") mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotEmpty("") if !mockT.Failed { t.Error("Check should fail") } } func TestWithinDurationWrapper(t *testing.T) { t.Parallel() require := New(t) a := time.Now() b := a.Add(10 * time.Second) require.WithinDuration(a, b, 15*time.Second) mockT := new(MockT) mockRequire := New(mockT) mockRequire.WithinDuration(a, b, 5*time.Second) if !mockT.Failed { t.Error("Check should fail") } } func TestInDeltaWrapper(t *testing.T) { t.Parallel() require := New(t) require.InDelta(1.001, 1, 0.01) mockT := new(MockT) mockRequire := New(mockT) mockRequire.InDelta(1, 2, 0.5) if !mockT.Failed { t.Error("Check should fail") } } func TestZeroWrapper(t *testing.T) { t.Parallel() require := New(t) require.Zero(0) mockT := new(MockT) mockRequire := New(mockT) mockRequire.Zero(1) if !mockT.Failed { t.Error("Check should fail") } } func TestNotZeroWrapper(t *testing.T) { t.Parallel() require := New(t) require.NotZero(1) mockT := new(MockT) mockRequire := New(mockT) mockRequire.NotZero(0) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_EqualSONString(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") if mockT.Failed { t.Error("Check should pass") } } func TestJSONEqWrapper_Array(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON") if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq("Not JSON", "Not JSON") if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEqWrapper_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) expected := ` numeric: 1.5 array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] hash: nested: hash nested_slice: [this, is, nested] string: "foo" ` actual := ` numeric: 1.5 hash: nested: hash nested_slice: [this, is, nested] string: "foo" array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] ` mockRequire.YAMLEq(expected, actual) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEqWrapper_Array(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`{"foo": "bar"}`, "Simple String") if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq("Simple String", `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq("Simple String", "Simple String") if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEqWrapper_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(MockT) mockRequire := New(mockT) mockRequire.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) if !mockT.Failed { t.Error("Check should fail") } } ================================================ FILE: require/require.go ================================================ // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package require import ( assert "github.com/stretchr/testify/assert" http "net/http" url "net/url" time "time" ) // Condition uses a Comparison to assert a complex condition. func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Condition(t, comp, msgAndArgs...) { return } t.FailNow() } // Conditionf uses a Comparison to assert a complex condition. func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Conditionf(t, comp, msg, args...) { return } t.FailNow() } // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // require.Contains(t, "Hello World", "World") // require.Contains(t, ["Hello", "World"], "World") // require.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Contains(t, s, contains, msgAndArgs...) { return } t.FailNow() } // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // require.Containsf(t, "Hello World", "World", "error message %s", "formatted") // require.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") // require.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Containsf(t, s, contains, msg, args...) { return } t.FailNow() } // DirExists checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.DirExists(t, path, msgAndArgs...) { return } t.FailNow() } // DirExistsf checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func DirExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.DirExistsf(t, path, msg, args...) { return } t.FailNow() } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // require.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ElementsMatch(t, listA, listB, msgAndArgs...) { return } t.FailNow() } // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // require.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ElementsMatchf(t, listA, listB, msg, args...) { return } t.FailNow() } // Empty asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // require.Empty(t, obj) // // [Zero values]: https://go.dev/ref/spec#The_zero_value func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Empty(t, object, msgAndArgs...) { return } t.FailNow() } // Emptyf asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // require.Emptyf(t, obj, "error message %s", "formatted") // // [Zero values]: https://go.dev/ref/spec#The_zero_value func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Emptyf(t, object, msg, args...) { return } t.FailNow() } // Equal asserts that two objects are equal. // // require.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Equal(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // require.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualError(t, theError, errString, msgAndArgs...) { return } t.FailNow() } // EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // require.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualErrorf(t, theError, errString, msg, args...) { return } t.FailNow() } // EqualExportedValues asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // require.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true // require.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // EqualExportedValuesf asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // require.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true // require.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualExportedValuesf(t, expected, actual, msg, args...) { return } t.FailNow() } // EqualValues asserts that two objects are equal or convertible to the larger // type and equal. // // require.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualValues(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // EqualValuesf asserts that two objects are equal or convertible to the larger // type and equal. // // require.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EqualValuesf(t, expected, actual, msg, args...) { return } t.FailNow() } // Equalf asserts that two objects are equal. // // require.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Equalf(t, expected, actual, msg, args...) { return } t.FailNow() } // Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Error(t, err) func Error(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Error(t, err, msgAndArgs...) { return } t.FailNow() } // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorAs(t, err, target, msgAndArgs...) { return } t.FailNow() } // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorAsf(t, err, target, msg, args...) { return } t.FailNow() } // ErrorContains asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorContains(t, theError, contains, msgAndArgs...) { return } t.FailNow() } // ErrorContainsf asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorContainsf(t, theError, contains, msg, args...) { return } t.FailNow() } // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorIs(t, err, target, msgAndArgs...) { return } t.FailNow() } // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.ErrorIsf(t, err, target, msg, args...) { return } t.FailNow() } // Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Errorf(t, err, "error message %s", "formatted") func Errorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Errorf(t, err, msg, args...) { return } t.FailNow() } // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // require.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { return } t.FailNow() } // EventuallyWithT asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // require.EventuallyWithT(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) { return } t.FailNow() } // EventuallyWithTf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // require.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) { return } t.FailNow() } // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // require.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { return } t.FailNow() } // Exactly asserts that two objects are equal in value and type. // // require.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Exactly(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // Exactlyf asserts that two objects are equal in value and type. // // require.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Exactlyf(t, expected, actual, msg, args...) { return } t.FailNow() } // Fail reports a failure through func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Fail(t, failureMessage, msgAndArgs...) { return } t.FailNow() } // FailNow fails test func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.FailNow(t, failureMessage, msgAndArgs...) { return } t.FailNow() } // FailNowf fails test func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.FailNowf(t, failureMessage, msg, args...) { return } t.FailNow() } // Failf reports a failure through func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Failf(t, failureMessage, msg, args...) { return } t.FailNow() } // False asserts that the specified value is false. // // require.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.False(t, value, msgAndArgs...) { return } t.FailNow() } // Falsef asserts that the specified value is false. // // require.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Falsef(t, value, msg, args...) { return } t.FailNow() } // FileExists checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.FileExists(t, path, msgAndArgs...) { return } t.FailNow() } // FileExistsf checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.FileExistsf(t, path, msg, args...) { return } t.FailNow() } // Greater asserts that the first element is greater than the second // // require.Greater(t, 2, 1) // require.Greater(t, float64(2), float64(1)) // require.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Greater(t, e1, e2, msgAndArgs...) { return } t.FailNow() } // GreaterOrEqual asserts that the first element is greater than or equal to the second // // require.GreaterOrEqual(t, 2, 1) // require.GreaterOrEqual(t, 2, 2) // require.GreaterOrEqual(t, "b", "a") // require.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) { return } t.FailNow() } // GreaterOrEqualf asserts that the first element is greater than or equal to the second // // require.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") // require.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") // require.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") // require.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.GreaterOrEqualf(t, e1, e2, msg, args...) { return } t.FailNow() } // Greaterf asserts that the first element is greater than the second // // require.Greaterf(t, 2, 1, "error message %s", "formatted") // require.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") // require.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Greaterf(t, e1, e2, msg, args...) { return } t.FailNow() } // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // // require.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { return } t.FailNow() } // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // // require.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) { return } t.FailNow() } // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // // require.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { return } t.FailNow() } // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // // require.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) { return } t.FailNow() } // HTTPError asserts that a specified handler returns an error status code. // // require.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) { return } t.FailNow() } // HTTPErrorf asserts that a specified handler returns an error status code. // // require.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) { return } t.FailNow() } // HTTPRedirect asserts that a specified handler returns a redirect status code. // // require.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { return } t.FailNow() } // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // require.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) { return } t.FailNow() } // HTTPStatusCode asserts that a specified handler returns a specified status code. // // require.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { return } t.FailNow() } // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // require.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) { return } t.FailNow() } // HTTPSuccess asserts that a specified handler returns a success status code. // // require.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { return } t.FailNow() } // HTTPSuccessf asserts that a specified handler returns a success status code. // // require.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) { return } t.FailNow() } // Implements asserts that an object is implemented by the specified interface. // // require.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Implements(t, interfaceObject, object, msgAndArgs...) { return } t.FailNow() } // Implementsf asserts that an object is implemented by the specified interface. // // require.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Implementsf(t, interfaceObject, object, msg, args...) { return } t.FailNow() } // InDelta asserts that the two numerals are within delta of each other. // // require.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDelta(t, expected, actual, delta, msgAndArgs...) { return } t.FailNow() } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { return } t.FailNow() } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) { return } t.FailNow() } // InDeltaSlice is the same as InDelta, except it compares two slices. func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { return } t.FailNow() } // InDeltaSlicef is the same as InDelta, except it compares two slices. func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) { return } t.FailNow() } // InDeltaf asserts that the two numerals are within delta of each other. // // require.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InDeltaf(t, expected, actual, delta, msg, args...) { return } t.FailNow() } // InEpsilon asserts that expected and actual have a relative error less than epsilon func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { return } t.FailNow() } // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { return } t.FailNow() } // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) { return } t.FailNow() } // InEpsilonf asserts that expected and actual have a relative error less than epsilon func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) { return } t.FailNow() } // IsDecreasing asserts that the collection is decreasing // // require.IsDecreasing(t, []int{2, 1, 0}) // require.IsDecreasing(t, []float{2, 1}) // require.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsDecreasing(t, object, msgAndArgs...) { return } t.FailNow() } // IsDecreasingf asserts that the collection is decreasing // // require.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") // require.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") // require.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsDecreasingf(t, object, msg, args...) { return } t.FailNow() } // IsIncreasing asserts that the collection is increasing // // require.IsIncreasing(t, []int{1, 2, 3}) // require.IsIncreasing(t, []float{1, 2}) // require.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsIncreasing(t, object, msgAndArgs...) { return } t.FailNow() } // IsIncreasingf asserts that the collection is increasing // // require.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") // require.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") // require.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsIncreasingf(t, object, msg, args...) { return } t.FailNow() } // IsNonDecreasing asserts that the collection is not decreasing // // require.IsNonDecreasing(t, []int{1, 1, 2}) // require.IsNonDecreasing(t, []float{1, 2}) // require.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNonDecreasing(t, object, msgAndArgs...) { return } t.FailNow() } // IsNonDecreasingf asserts that the collection is not decreasing // // require.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") // require.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") // require.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNonDecreasingf(t, object, msg, args...) { return } t.FailNow() } // IsNonIncreasing asserts that the collection is not increasing // // require.IsNonIncreasing(t, []int{2, 1, 1}) // require.IsNonIncreasing(t, []float{2, 1}) // require.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNonIncreasing(t, object, msgAndArgs...) { return } t.FailNow() } // IsNonIncreasingf asserts that the collection is not increasing // // require.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") // require.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") // require.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNonIncreasingf(t, object, msg, args...) { return } t.FailNow() } // IsNotType asserts that the specified objects are not of the same type. // // require.IsNotType(t, &NotMyStruct{}, &MyStruct{}) func IsNotType(t TestingT, theType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNotType(t, theType, object, msgAndArgs...) { return } t.FailNow() } // IsNotTypef asserts that the specified objects are not of the same type. // // require.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted") func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsNotTypef(t, theType, object, msg, args...) { return } t.FailNow() } // IsType asserts that the specified objects are of the same type. // // require.IsType(t, &MyStruct{}, &MyStruct{}) func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsType(t, expectedType, object, msgAndArgs...) { return } t.FailNow() } // IsTypef asserts that the specified objects are of the same type. // // require.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted") func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.IsTypef(t, expectedType, object, msg, args...) { return } t.FailNow() } // JSONEq asserts that two JSON strings are equivalent. // // require.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.JSONEq(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // JSONEqf asserts that two JSON strings are equivalent. // // require.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.JSONEqf(t, expected, actual, msg, args...) { return } t.FailNow() } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // // require.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Len(t, object, length, msgAndArgs...) { return } t.FailNow() } // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // // require.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Lenf(t, object, length, msg, args...) { return } t.FailNow() } // Less asserts that the first element is less than the second // // require.Less(t, 1, 2) // require.Less(t, float64(1), float64(2)) // require.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Less(t, e1, e2, msgAndArgs...) { return } t.FailNow() } // LessOrEqual asserts that the first element is less than or equal to the second // // require.LessOrEqual(t, 1, 2) // require.LessOrEqual(t, 2, 2) // require.LessOrEqual(t, "a", "b") // require.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.LessOrEqual(t, e1, e2, msgAndArgs...) { return } t.FailNow() } // LessOrEqualf asserts that the first element is less than or equal to the second // // require.LessOrEqualf(t, 1, 2, "error message %s", "formatted") // require.LessOrEqualf(t, 2, 2, "error message %s", "formatted") // require.LessOrEqualf(t, "a", "b", "error message %s", "formatted") // require.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.LessOrEqualf(t, e1, e2, msg, args...) { return } t.FailNow() } // Lessf asserts that the first element is less than the second // // require.Lessf(t, 1, 2, "error message %s", "formatted") // require.Lessf(t, float64(1), float64(2), "error message %s", "formatted") // require.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Lessf(t, e1, e2, msg, args...) { return } t.FailNow() } // Negative asserts that the specified element is negative // // require.Negative(t, -1) // require.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Negative(t, e, msgAndArgs...) { return } t.FailNow() } // Negativef asserts that the specified element is negative // // require.Negativef(t, -1, "error message %s", "formatted") // require.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Negativef(t, e, msg, args...) { return } t.FailNow() } // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // require.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Never(t, condition, waitFor, tick, msgAndArgs...) { return } t.FailNow() } // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // require.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Neverf(t, condition, waitFor, tick, msg, args...) { return } t.FailNow() } // Nil asserts that the specified object is nil. // // require.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Nil(t, object, msgAndArgs...) { return } t.FailNow() } // Nilf asserts that the specified object is nil. // // require.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Nilf(t, object, msg, args...) { return } t.FailNow() } // NoDirExists checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoDirExists(t, path, msgAndArgs...) { return } t.FailNow() } // NoDirExistsf checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoDirExistsf(t, path, msg, args...) { return } t.FailNow() } // NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // require.NoError(t, err) // require.Equal(t, expectedObj, actualObj) func NoError(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoError(t, err, msgAndArgs...) { return } t.FailNow() } // NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // require.NoErrorf(t, err, "error message %s", "formatted") // require.Equal(t, expectedObj, actualObj) func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoErrorf(t, err, msg, args...) { return } t.FailNow() } // NoFileExists checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoFileExists(t, path, msgAndArgs...) { return } t.FailNow() } // NoFileExistsf checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NoFileExistsf(t, path, msg, args...) { return } t.FailNow() } // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // require.NotContains(t, "Hello World", "Earth") // require.NotContains(t, ["Hello", "World"], "Earth") // require.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotContains(t, s, contains, msgAndArgs...) { return } t.FailNow() } // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // require.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") // require.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") // require.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotContainsf(t, s, contains, msg, args...) { return } t.FailNow() } // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // require.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false // // require.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true // // require.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true func NotElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotElementsMatch(t, listA, listB, msgAndArgs...) { return } t.FailNow() } // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false // // require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true // // require.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotElementsMatchf(t, listA, listB, msg, args...) { return } t.FailNow() } // NotEmpty asserts that the specified object is NOT [Empty]. // // require.NotEmpty(t, obj) // require.Equal(t, "two", obj[1]) func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEmpty(t, object, msgAndArgs...) { return } t.FailNow() } // NotEmptyf asserts that the specified object is NOT [Empty]. // // require.NotEmptyf(t, obj, "error message %s", "formatted") // require.Equal(t, "two", obj[1]) func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEmptyf(t, object, msg, args...) { return } t.FailNow() } // NotEqual asserts that the specified values are NOT equal. // // require.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEqual(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // NotEqualValues asserts that two objects are not equal even when converted to the same type // // require.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEqualValues(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // // require.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEqualValuesf(t, expected, actual, msg, args...) { return } t.FailNow() } // NotEqualf asserts that the specified values are NOT equal. // // require.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotEqualf(t, expected, actual, msg, args...) { return } t.FailNow() } // NotErrorAs asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotErrorAs(t, err, target, msgAndArgs...) { return } t.FailNow() } // NotErrorAsf asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotErrorAsf(t, err, target, msg, args...) { return } t.FailNow() } // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotErrorIs(t, err, target, msgAndArgs...) { return } t.FailNow() } // NotErrorIsf asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotErrorIsf(t, err, target, msg, args...) { return } t.FailNow() } // NotImplements asserts that an object does not implement the specified interface. // // require.NotImplements(t, (*MyInterface)(nil), new(MyObject)) func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) { return } t.FailNow() } // NotImplementsf asserts that an object does not implement the specified interface. // // require.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotImplementsf(t, interfaceObject, object, msg, args...) { return } t.FailNow() } // NotNil asserts that the specified object is not nil. // // require.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotNil(t, object, msgAndArgs...) { return } t.FailNow() } // NotNilf asserts that the specified object is not nil. // // require.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotNilf(t, object, msg, args...) { return } t.FailNow() } // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // // require.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotPanics(t, f, msgAndArgs...) { return } t.FailNow() } // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // // require.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotPanicsf(t, f, msg, args...) { return } t.FailNow() } // NotRegexp asserts that a specified regexp does not match a string. // // require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") // require.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotRegexp(t, rx, str, msgAndArgs...) { return } t.FailNow() } // NotRegexpf asserts that a specified regexp does not match a string. // // require.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // require.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotRegexpf(t, rx, str, msg, args...) { return } t.FailNow() } // NotSame asserts that two pointers do not reference the same object. // // require.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotSame(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // NotSamef asserts that two pointers do not reference the same object. // // require.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotSamef(t, expected, actual, msg, args...) { return } t.FailNow() } // NotSubset asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // require.NotSubset(t, [1, 3, 4], [1, 2]) // require.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) // require.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"}) // require.NotSubset(t, {"x": 1, "y": 2}, ["z"]) func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotSubset(t, list, subset, msgAndArgs...) { return } t.FailNow() } // NotSubsetf asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // require.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") // require.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") // require.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted") // require.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotSubsetf(t, list, subset, msg, args...) { return } t.FailNow() } // NotZero asserts that i is not the zero value for its type. func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotZero(t, i, msgAndArgs...) { return } t.FailNow() } // NotZerof asserts that i is not the zero value for its type. func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.NotZerof(t, i, msg, args...) { return } t.FailNow() } // Panics asserts that the code inside the specified PanicTestFunc panics. // // require.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Panics(t, f, msgAndArgs...) { return } t.FailNow() } // PanicsWithError asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // require.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.PanicsWithError(t, errString, f, msgAndArgs...) { return } t.FailNow() } // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // require.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.PanicsWithErrorf(t, errString, f, msg, args...) { return } t.FailNow() } // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // require.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.PanicsWithValue(t, expected, f, msgAndArgs...) { return } t.FailNow() } // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // require.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.PanicsWithValuef(t, expected, f, msg, args...) { return } t.FailNow() } // Panicsf asserts that the code inside the specified PanicTestFunc panics. // // require.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Panicsf(t, f, msg, args...) { return } t.FailNow() } // Positive asserts that the specified element is positive // // require.Positive(t, 1) // require.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Positive(t, e, msgAndArgs...) { return } t.FailNow() } // Positivef asserts that the specified element is positive // // require.Positivef(t, 1, "error message %s", "formatted") // require.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Positivef(t, e, msg, args...) { return } t.FailNow() } // Regexp asserts that a specified regexp matches a string. // // require.Regexp(t, regexp.MustCompile("start"), "it's starting") // require.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Regexp(t, rx, str, msgAndArgs...) { return } t.FailNow() } // Regexpf asserts that a specified regexp matches a string. // // require.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // require.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Regexpf(t, rx, str, msg, args...) { return } t.FailNow() } // Same asserts that two pointers reference the same object. // // require.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Same(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // Samef asserts that two pointers reference the same object. // // require.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Samef(t, expected, actual, msg, args...) { return } t.FailNow() } // Subset asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // require.Subset(t, [1, 2, 3], [1, 2]) // require.Subset(t, {"x": 1, "y": 2}, {"x": 1}) // require.Subset(t, [1, 2, 3], {1: "one", 2: "two"}) // require.Subset(t, {"x": 1, "y": 2}, ["x"]) func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Subset(t, list, subset, msgAndArgs...) { return } t.FailNow() } // Subsetf asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // require.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") // require.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") // require.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted") // require.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Subsetf(t, list, subset, msg, args...) { return } t.FailNow() } // True asserts that the specified value is true. // // require.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.True(t, value, msgAndArgs...) { return } t.FailNow() } // Truef asserts that the specified value is true. // // require.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Truef(t, value, msg, args...) { return } t.FailNow() } // WithinDuration asserts that the two times are within duration delta of each other. // // require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { return } t.FailNow() } // WithinDurationf asserts that the two times are within duration delta of each other. // // require.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.WithinDurationf(t, expected, actual, delta, msg, args...) { return } t.FailNow() } // WithinRange asserts that a time is within a time range (inclusive). // // require.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.WithinRange(t, actual, start, end, msgAndArgs...) { return } t.FailNow() } // WithinRangef asserts that a time is within a time range (inclusive). // // require.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.WithinRangef(t, actual, start, end, msg, args...) { return } t.FailNow() } // YAMLEq asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // require.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.YAMLEq(t, expected, actual, msgAndArgs...) { return } t.FailNow() } // YAMLEqf asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // require.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.YAMLEqf(t, expected, actual, msg, args...) { return } t.FailNow() } // Zero asserts that i is the zero value for its type. func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Zero(t, i, msgAndArgs...) { return } t.FailNow() } // Zerof asserts that i is the zero value for its type. func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.Zerof(t, i, msg, args...) { return } t.FailNow() } ================================================ FILE: require/require.go.tmpl ================================================ {{.CommentRequire}} func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } t.FailNow() } ================================================ FILE: require/require_forward.go ================================================ // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package require import ( assert "github.com/stretchr/testify/assert" http "net/http" url "net/url" time "time" ) // Condition uses a Comparison to assert a complex condition. func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Condition(a.t, comp, msgAndArgs...) } // Conditionf uses a Comparison to assert a complex condition. func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Conditionf(a.t, comp, msg, args...) } // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // a.Contains("Hello World", "World") // a.Contains(["Hello", "World"], "World") // a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Contains(a.t, s, contains, msgAndArgs...) } // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // a.Containsf("Hello World", "World", "error message %s", "formatted") // a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") // a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Containsf(a.t, s, contains, msg, args...) } // DirExists checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } DirExists(a.t, path, msgAndArgs...) } // DirExistsf checks whether a directory exists in the given path. It also fails // if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } DirExistsf(a.t, path, msg, args...) } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ElementsMatch(a.t, listA, listB, msgAndArgs...) } // ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should match. // // a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ElementsMatchf(a.t, listA, listB, msg, args...) } // Empty asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // a.Empty(obj) // // [Zero values]: https://go.dev/ref/spec#The_zero_value func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Empty(a.t, object, msgAndArgs...) } // Emptyf asserts that the given value is "empty". // // [Zero values] are "empty". // // Arrays are "empty" if every element is the zero value of the type (stricter than "empty"). // // Slices, maps and channels with zero length are "empty". // // Pointer values are "empty" if the pointer is nil or if the pointed value is "empty". // // a.Emptyf(obj, "error message %s", "formatted") // // [Zero values]: https://go.dev/ref/spec#The_zero_value func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Emptyf(a.t, object, msg, args...) } // Equal asserts that two objects are equal. // // a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Equal(a.t, expected, actual, msgAndArgs...) } // EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualError(a.t, theError, errString, msgAndArgs...) } // EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() // a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualErrorf(a.t, theError, errString, msg, args...) } // EqualExportedValues asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // a.EqualExportedValues(S{1, 2}, S{1, 3}) => true // a.EqualExportedValues(S{1, 2}, S{2, 3}) => false func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualExportedValues(a.t, expected, actual, msgAndArgs...) } // EqualExportedValuesf asserts that the types of two objects are equal and their public // fields are also equal. This is useful for comparing structs that have private fields // that could potentially differ. // // type S struct { // Exported int // notExported int // } // a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true // a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualExportedValuesf(a.t, expected, actual, msg, args...) } // EqualValues asserts that two objects are equal or convertible to the larger // type and equal. // // a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualValues(a.t, expected, actual, msgAndArgs...) } // EqualValuesf asserts that two objects are equal or convertible to the larger // type and equal. // // a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EqualValuesf(a.t, expected, actual, msg, args...) } // Equalf asserts that two objects are equal. // // a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality // cannot be determined and will always fail. func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Equalf(a.t, expected, actual, msg, args...) } // Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Error(a.t, err, msgAndArgs...) } // ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorAs(a.t, err, target, msgAndArgs...) } // ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. // This is a wrapper for errors.As. func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorAsf(a.t, err, target, msg, args...) } // ErrorContains asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorContains(a.t, theError, contains, msgAndArgs...) } // ErrorContainsf asserts that a function returned a non-nil error (i.e. an // error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorContainsf(a.t, theError, contains, msg, args...) } // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorIs(a.t, err, target, msgAndArgs...) } // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } ErrorIsf(a.t, err, target, msg, args...) } // Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Errorf(a.t, err, msg, args...) } // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } // EventuallyWithT asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // a.EventuallyWithT(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) } // EventuallyWithTf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. In contrast to Eventually, // it supplies a CollectT to the condition function, so that the condition // function can use the CollectT to call other assertions. // The condition is considered "met" if no errors are raised in a tick. // The supplied CollectT collects all errors from one tick (if there are any). // If the condition is not met before waitFor, the collected errors of // the last tick are copied to t. // // externalValue := false // go func() { // time.Sleep(8*time.Second) // externalValue = true // }() // a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) } // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // // a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Eventuallyf(a.t, condition, waitFor, tick, msg, args...) } // Exactly asserts that two objects are equal in value and type. // // a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Exactly(a.t, expected, actual, msgAndArgs...) } // Exactlyf asserts that two objects are equal in value and type. // // a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Exactlyf(a.t, expected, actual, msg, args...) } // Fail reports a failure through func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Fail(a.t, failureMessage, msgAndArgs...) } // FailNow fails test func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } FailNow(a.t, failureMessage, msgAndArgs...) } // FailNowf fails test func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } FailNowf(a.t, failureMessage, msg, args...) } // Failf reports a failure through func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Failf(a.t, failureMessage, msg, args...) } // False asserts that the specified value is false. // // a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } False(a.t, value, msgAndArgs...) } // Falsef asserts that the specified value is false. // // a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Falsef(a.t, value, msg, args...) } // FileExists checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } FileExists(a.t, path, msgAndArgs...) } // FileExistsf checks whether a file exists in the given path. It also fails if // the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } FileExistsf(a.t, path, msg, args...) } // Greater asserts that the first element is greater than the second // // a.Greater(2, 1) // a.Greater(float64(2), float64(1)) // a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Greater(a.t, e1, e2, msgAndArgs...) } // GreaterOrEqual asserts that the first element is greater than or equal to the second // // a.GreaterOrEqual(2, 1) // a.GreaterOrEqual(2, 2) // a.GreaterOrEqual("b", "a") // a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } GreaterOrEqual(a.t, e1, e2, msgAndArgs...) } // GreaterOrEqualf asserts that the first element is greater than or equal to the second // // a.GreaterOrEqualf(2, 1, "error message %s", "formatted") // a.GreaterOrEqualf(2, 2, "error message %s", "formatted") // a.GreaterOrEqualf("b", "a", "error message %s", "formatted") // a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } GreaterOrEqualf(a.t, e1, e2, msg, args...) } // Greaterf asserts that the first element is greater than the second // // a.Greaterf(2, 1, "error message %s", "formatted") // a.Greaterf(float64(2), float64(1), "error message %s", "formatted") // a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Greaterf(a.t, e1, e2, msg, args...) } // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) } // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) } // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) } // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) } // HTTPError asserts that a specified handler returns an error status code. // // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPError(a.t, handler, method, url, values, msgAndArgs...) } // HTTPErrorf asserts that a specified handler returns an error status code. // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPErrorf(a.t, handler, method, url, values, msg, args...) } // HTTPRedirect asserts that a specified handler returns a redirect status code. // // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) } // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPRedirectf(a.t, handler, method, url, values, msg, args...) } // HTTPStatusCode asserts that a specified handler returns a specified status code. // // a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) } // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) } // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) } // HTTPSuccessf asserts that a specified handler returns a success status code. // // a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } HTTPSuccessf(a.t, handler, method, url, values, msg, args...) } // Implements asserts that an object is implemented by the specified interface. // // a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Implements(a.t, interfaceObject, object, msgAndArgs...) } // Implementsf asserts that an object is implemented by the specified interface. // // a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Implementsf(a.t, interfaceObject, object, msg, args...) } // InDelta asserts that the two numerals are within delta of each other. // // a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDelta(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) } // InDeltaSlice is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) } // InDeltaSlicef is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDeltaSlicef(a.t, expected, actual, delta, msg, args...) } // InDeltaf asserts that the two numerals are within delta of each other. // // a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InDeltaf(a.t, expected, actual, delta, msg, args...) } // InEpsilon asserts that expected and actual have a relative error less than epsilon func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) } // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) } // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) } // InEpsilonf asserts that expected and actual have a relative error less than epsilon func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } // IsDecreasing asserts that the collection is decreasing // // a.IsDecreasing([]int{2, 1, 0}) // a.IsDecreasing([]float{2, 1}) // a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsDecreasing(a.t, object, msgAndArgs...) } // IsDecreasingf asserts that the collection is decreasing // // a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") // a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") // a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsDecreasingf(a.t, object, msg, args...) } // IsIncreasing asserts that the collection is increasing // // a.IsIncreasing([]int{1, 2, 3}) // a.IsIncreasing([]float{1, 2}) // a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsIncreasing(a.t, object, msgAndArgs...) } // IsIncreasingf asserts that the collection is increasing // // a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") // a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") // a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsIncreasingf(a.t, object, msg, args...) } // IsNonDecreasing asserts that the collection is not decreasing // // a.IsNonDecreasing([]int{1, 1, 2}) // a.IsNonDecreasing([]float{1, 2}) // a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNonDecreasing(a.t, object, msgAndArgs...) } // IsNonDecreasingf asserts that the collection is not decreasing // // a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") // a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") // a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNonDecreasingf(a.t, object, msg, args...) } // IsNonIncreasing asserts that the collection is not increasing // // a.IsNonIncreasing([]int{2, 1, 1}) // a.IsNonIncreasing([]float{2, 1}) // a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNonIncreasing(a.t, object, msgAndArgs...) } // IsNonIncreasingf asserts that the collection is not increasing // // a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") // a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") // a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNonIncreasingf(a.t, object, msg, args...) } // IsNotType asserts that the specified objects are not of the same type. // // a.IsNotType(&NotMyStruct{}, &MyStruct{}) func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNotType(a.t, theType, object, msgAndArgs...) } // IsNotTypef asserts that the specified objects are not of the same type. // // a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted") func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsNotTypef(a.t, theType, object, msg, args...) } // IsType asserts that the specified objects are of the same type. // // a.IsType(&MyStruct{}, &MyStruct{}) func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsType(a.t, expectedType, object, msgAndArgs...) } // IsTypef asserts that the specified objects are of the same type. // // a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted") func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } IsTypef(a.t, expectedType, object, msg, args...) } // JSONEq asserts that two JSON strings are equivalent. // // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } JSONEq(a.t, expected, actual, msgAndArgs...) } // JSONEqf asserts that two JSON strings are equivalent. // // a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } JSONEqf(a.t, expected, actual, msg, args...) } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // // a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Len(a.t, object, length, msgAndArgs...) } // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // // a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Lenf(a.t, object, length, msg, args...) } // Less asserts that the first element is less than the second // // a.Less(1, 2) // a.Less(float64(1), float64(2)) // a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Less(a.t, e1, e2, msgAndArgs...) } // LessOrEqual asserts that the first element is less than or equal to the second // // a.LessOrEqual(1, 2) // a.LessOrEqual(2, 2) // a.LessOrEqual("a", "b") // a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } LessOrEqual(a.t, e1, e2, msgAndArgs...) } // LessOrEqualf asserts that the first element is less than or equal to the second // // a.LessOrEqualf(1, 2, "error message %s", "formatted") // a.LessOrEqualf(2, 2, "error message %s", "formatted") // a.LessOrEqualf("a", "b", "error message %s", "formatted") // a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } LessOrEqualf(a.t, e1, e2, msg, args...) } // Lessf asserts that the first element is less than the second // // a.Lessf(1, 2, "error message %s", "formatted") // a.Lessf(float64(1), float64(2), "error message %s", "formatted") // a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Lessf(a.t, e1, e2, msg, args...) } // Negative asserts that the specified element is negative // // a.Negative(-1) // a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Negative(a.t, e, msgAndArgs...) } // Negativef asserts that the specified element is negative // // a.Negativef(-1, "error message %s", "formatted") // a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Negativef(a.t, e, msg, args...) } // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Never(a.t, condition, waitFor, tick, msgAndArgs...) } // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // // a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Neverf(a.t, condition, waitFor, tick, msg, args...) } // Nil asserts that the specified object is nil. // // a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Nil(a.t, object, msgAndArgs...) } // Nilf asserts that the specified object is nil. // // a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Nilf(a.t, object, msg, args...) } // NoDirExists checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoDirExists(a.t, path, msgAndArgs...) } // NoDirExistsf checks whether a directory does not exist in the given path. // It fails if the path points to an existing _directory_ only. func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoDirExistsf(a.t, path, msg, args...) } // NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // a.NoError(err) // a.Equal(expectedObj, actualObj) func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoError(a.t, err, msgAndArgs...) } // NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // a.NoErrorf(err, "error message %s", "formatted") // a.Equal(expectedObj, actualObj) func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoErrorf(a.t, err, msg, args...) } // NoFileExists checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoFileExists(a.t, path, msgAndArgs...) } // NoFileExistsf checks whether a file does not exist in a given path. It fails // if the path points to an existing _file_ only. func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NoFileExistsf(a.t, path, msg, args...) } // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // a.NotContains("Hello World", "Earth") // a.NotContains(["Hello", "World"], "Earth") // a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotContains(a.t, s, contains, msgAndArgs...) } // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") // a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") // a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotContainsf(a.t, s, contains, msg, args...) } // NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false // // a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true // // a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotElementsMatch(a.t, listA, listB, msgAndArgs...) } // NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // the number of appearances of each of them in both lists should not match. // This is an inverse of ElementsMatch. // // a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false // // a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true // // a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotElementsMatchf(a.t, listA, listB, msg, args...) } // NotEmpty asserts that the specified object is NOT [Empty]. // // a.NotEmpty(obj) // a.Equal("two", obj[1]) func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEmpty(a.t, object, msgAndArgs...) } // NotEmptyf asserts that the specified object is NOT [Empty]. // // a.NotEmptyf(obj, "error message %s", "formatted") // a.Equal("two", obj[1]) func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEmptyf(a.t, object, msg, args...) } // NotEqual asserts that the specified values are NOT equal. // // a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEqual(a.t, expected, actual, msgAndArgs...) } // NotEqualValues asserts that two objects are not equal even when converted to the same type // // a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEqualValues(a.t, expected, actual, msgAndArgs...) } // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // // a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEqualValuesf(a.t, expected, actual, msg, args...) } // NotEqualf asserts that the specified values are NOT equal. // // a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotEqualf(a.t, expected, actual, msg, args...) } // NotErrorAs asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotErrorAs(a.t, err, target, msgAndArgs...) } // NotErrorAsf asserts that none of the errors in err's chain matches target, // but if so, sets target to that error value. func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotErrorAsf(a.t, err, target, msg, args...) } // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotErrorIs(a.t, err, target, msgAndArgs...) } // NotErrorIsf asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotErrorIsf(a.t, err, target, msg, args...) } // NotImplements asserts that an object does not implement the specified interface. // // a.NotImplements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotImplements(a.t, interfaceObject, object, msgAndArgs...) } // NotImplementsf asserts that an object does not implement the specified interface. // // a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotImplementsf(a.t, interfaceObject, object, msg, args...) } // NotNil asserts that the specified object is not nil. // // a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotNil(a.t, object, msgAndArgs...) } // NotNilf asserts that the specified object is not nil. // // a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotNilf(a.t, object, msg, args...) } // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // // a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotPanics(a.t, f, msgAndArgs...) } // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // // a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotPanicsf(a.t, f, msg, args...) } // NotRegexp asserts that a specified regexp does not match a string. // // a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotRegexp(a.t, rx, str, msgAndArgs...) } // NotRegexpf asserts that a specified regexp does not match a string. // // a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotRegexpf(a.t, rx, str, msg, args...) } // NotSame asserts that two pointers do not reference the same object. // // a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotSame(a.t, expected, actual, msgAndArgs...) } // NotSamef asserts that two pointers do not reference the same object. // // a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotSamef(a.t, expected, actual, msg, args...) } // NotSubset asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.NotSubset([1, 3, 4], [1, 2]) // a.NotSubset({"x": 1, "y": 2}, {"z": 3}) // a.NotSubset([1, 3, 4], {1: "one", 2: "two"}) // a.NotSubset({"x": 1, "y": 2}, ["z"]) func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotSubset(a.t, list, subset, msgAndArgs...) } // NotSubsetf asserts that the list (array, slice, or map) does NOT contain all // elements given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") // a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") // a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted") // a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotSubsetf(a.t, list, subset, msg, args...) } // NotZero asserts that i is not the zero value for its type. func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotZero(a.t, i, msgAndArgs...) } // NotZerof asserts that i is not the zero value for its type. func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } NotZerof(a.t, i, msg, args...) } // Panics asserts that the code inside the specified PanicTestFunc panics. // // a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Panics(a.t, f, msgAndArgs...) } // PanicsWithError asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } PanicsWithError(a.t, errString, f, msgAndArgs...) } // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // // a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } PanicsWithErrorf(a.t, errString, f, msg, args...) } // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } PanicsWithValue(a.t, expected, f, msgAndArgs...) } // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // // a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } PanicsWithValuef(a.t, expected, f, msg, args...) } // Panicsf asserts that the code inside the specified PanicTestFunc panics. // // a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Panicsf(a.t, f, msg, args...) } // Positive asserts that the specified element is positive // // a.Positive(1) // a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Positive(a.t, e, msgAndArgs...) } // Positivef asserts that the specified element is positive // // a.Positivef(1, "error message %s", "formatted") // a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Positivef(a.t, e, msg, args...) } // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Regexp(a.t, rx, str, msgAndArgs...) } // Regexpf asserts that a specified regexp matches a string. // // a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Regexpf(a.t, rx, str, msg, args...) } // Same asserts that two pointers reference the same object. // // a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Same(a.t, expected, actual, msgAndArgs...) } // Samef asserts that two pointers reference the same object. // // a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Samef(a.t, expected, actual, msg, args...) } // Subset asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.Subset([1, 2, 3], [1, 2]) // a.Subset({"x": 1, "y": 2}, {"x": 1}) // a.Subset([1, 2, 3], {1: "one", 2: "two"}) // a.Subset({"x": 1, "y": 2}, ["x"]) func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Subset(a.t, list, subset, msgAndArgs...) } // Subsetf asserts that the list (array, slice, or map) contains all elements // given in the subset (array, slice, or map). // Map elements are key-value pairs unless compared with an array or slice where // only the map key is evaluated. // // a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") // a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") // a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted") // a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Subsetf(a.t, list, subset, msg, args...) } // True asserts that the specified value is true. // // a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } True(a.t, value, msgAndArgs...) } // Truef asserts that the specified value is true. // // a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Truef(a.t, value, msg, args...) } // WithinDuration asserts that the two times are within duration delta of each other. // // a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } WithinDuration(a.t, expected, actual, delta, msgAndArgs...) } // WithinDurationf asserts that the two times are within duration delta of each other. // // a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } WithinDurationf(a.t, expected, actual, delta, msg, args...) } // WithinRange asserts that a time is within a time range (inclusive). // // a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } WithinRange(a.t, actual, start, end, msgAndArgs...) } // WithinRangef asserts that a time is within a time range (inclusive). // // a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } WithinRangef(a.t, actual, start, end, msg, args...) } // YAMLEq asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } YAMLEq(a.t, expected, actual, msgAndArgs...) } // YAMLEqf asserts that the first documents in the two YAML strings are equivalent. // // expected := `--- // key: value // --- // key: this is a second document, it is not evaluated // ` // actual := `--- // key: value // --- // key: this is a subsequent document, it is not evaluated // ` // a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } YAMLEqf(a.t, expected, actual, msg, args...) } // Zero asserts that i is the zero value for its type. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Zero(a.t, i, msgAndArgs...) } // Zerof asserts that i is the zero value for its type. func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() } Zerof(a.t, i, msg, args...) } ================================================ FILE: require/require_forward.go.tmpl ================================================ {{.CommentRequireWithoutT "a"}} func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { if h, ok := a.t.(tHelper); ok { h.Helper() } {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) } ================================================ FILE: require/requirements.go ================================================ package require // TestingT is an interface wrapper around *testing.T type TestingT interface { Errorf(format string, args ...interface{}) FailNow() } type tHelper = interface { Helper() } // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. type BoolAssertionFunc func(TestingT, bool, ...interface{}) // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. type ErrorAssertionFunc func(TestingT, error, ...interface{}) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" ================================================ FILE: require/requirements_test.go ================================================ package require import ( "encoding/json" "errors" "testing" "time" "github.com/stretchr/testify/assert" ) // AssertionTesterInterface defines an interface to be used for testing assertion methods type AssertionTesterInterface interface { TestMethod() } // AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface type AssertionTesterConformingObject struct { } func (a *AssertionTesterConformingObject) TestMethod() { } // AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface type AssertionTesterNonConformingObject struct { } type MockT struct { Failed bool } // Helper is like [testing.T.Helper] but does nothing. func (MockT) Helper() {} func (t *MockT) FailNow() { t.Failed = true } func (t *MockT) Errorf(format string, args ...interface{}) { _, _ = format, args } func TestImplements(t *testing.T) { t.Parallel() Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) mockT := new(MockT) Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestIsType(t *testing.T) { t.Parallel() IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) mockT := new(MockT) IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestEqual(t *testing.T) { t.Parallel() Equal(t, 1, 1) mockT := new(MockT) Equal(mockT, 1, 2) if !mockT.Failed { t.Error("Check should fail") } } func TestNotEqual(t *testing.T) { t.Parallel() NotEqual(t, 1, 2) mockT := new(MockT) NotEqual(mockT, 2, 2) if !mockT.Failed { t.Error("Check should fail") } } func TestExactly(t *testing.T) { t.Parallel() a := float32(1) b := float32(1) c := float64(1) Exactly(t, a, b) mockT := new(MockT) Exactly(mockT, a, c) if !mockT.Failed { t.Error("Check should fail") } } func TestNotNil(t *testing.T) { t.Parallel() NotNil(t, new(AssertionTesterConformingObject)) mockT := new(MockT) NotNil(mockT, nil) if !mockT.Failed { t.Error("Check should fail") } } func TestNil(t *testing.T) { t.Parallel() Nil(t, nil) mockT := new(MockT) Nil(mockT, new(AssertionTesterConformingObject)) if !mockT.Failed { t.Error("Check should fail") } } func TestTrue(t *testing.T) { t.Parallel() True(t, true) mockT := new(MockT) True(mockT, false) if !mockT.Failed { t.Error("Check should fail") } } func TestFalse(t *testing.T) { t.Parallel() False(t, false) mockT := new(MockT) False(mockT, true) if !mockT.Failed { t.Error("Check should fail") } } func TestContains(t *testing.T) { t.Parallel() Contains(t, "Hello World", "Hello") mockT := new(MockT) Contains(mockT, "Hello World", "Salut") if !mockT.Failed { t.Error("Check should fail") } } func TestNotContains(t *testing.T) { t.Parallel() NotContains(t, "Hello World", "Hello!") mockT := new(MockT) NotContains(mockT, "Hello World", "Hello") if !mockT.Failed { t.Error("Check should fail") } } func TestPanics(t *testing.T) { t.Parallel() Panics(t, func() { panic("Panic!") }) mockT := new(MockT) Panics(mockT, func() {}) if !mockT.Failed { t.Error("Check should fail") } } func TestNotPanics(t *testing.T) { t.Parallel() NotPanics(t, func() {}) mockT := new(MockT) NotPanics(mockT, func() { panic("Panic!") }) if !mockT.Failed { t.Error("Check should fail") } } func TestNoError(t *testing.T) { t.Parallel() NoError(t, nil) mockT := new(MockT) NoError(mockT, errors.New("some error")) if !mockT.Failed { t.Error("Check should fail") } } func TestError(t *testing.T) { t.Parallel() Error(t, errors.New("some error")) mockT := new(MockT) Error(mockT, nil) if !mockT.Failed { t.Error("Check should fail") } } func TestErrorContains(t *testing.T) { t.Parallel() ErrorContains(t, errors.New("some error: another error"), "some error") mockT := new(MockT) ErrorContains(mockT, errors.New("some error"), "different error") if !mockT.Failed { t.Error("Check should fail") } } func TestEqualError(t *testing.T) { t.Parallel() EqualError(t, errors.New("some error"), "some error") mockT := new(MockT) EqualError(mockT, errors.New("some error"), "Not some error") if !mockT.Failed { t.Error("Check should fail") } } func TestEmpty(t *testing.T) { t.Parallel() Empty(t, "") mockT := new(MockT) Empty(mockT, "x") if !mockT.Failed { t.Error("Check should fail") } } func TestNotEmpty(t *testing.T) { t.Parallel() NotEmpty(t, "x") mockT := new(MockT) NotEmpty(mockT, "") if !mockT.Failed { t.Error("Check should fail") } } func TestWithinDuration(t *testing.T) { t.Parallel() a := time.Now() b := a.Add(10 * time.Second) WithinDuration(t, a, b, 15*time.Second) mockT := new(MockT) WithinDuration(mockT, a, b, 5*time.Second) if !mockT.Failed { t.Error("Check should fail") } } func TestInDelta(t *testing.T) { t.Parallel() InDelta(t, 1.001, 1, 0.01) mockT := new(MockT) InDelta(mockT, 1, 2, 0.5) if !mockT.Failed { t.Error("Check should fail") } } func TestZero(t *testing.T) { t.Parallel() Zero(t, "") mockT := new(MockT) Zero(mockT, "x") if !mockT.Failed { t.Error("Check should fail") } } func TestNotZero(t *testing.T) { t.Parallel() NotZero(t, "x") mockT := new(MockT) NotZero(mockT, "") if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_EqualSONString(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEq_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") if mockT.Failed { t.Error("Check should pass") } } func TestJSONEq_Array(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) if mockT.Failed { t.Error("Check should pass") } } func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_ActualIsNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `{"foo": "bar"}`, "Not JSON") if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, "Not JSON", "Not JSON") if !mockT.Failed { t.Error("Check should fail") } } func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(MockT) JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEq_EqualYAMLString(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEq_EquivalentButNotEqual(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEq_HashOfArraysAndHashes(t *testing.T) { t.Parallel() mockT := new(MockT) expected := ` numeric: 1.5 array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] hash: nested: hash nested_slice: [this, is, nested] string: "foo" ` actual := ` numeric: 1.5 hash: nested: hash nested_slice: [this, is, nested] string: "foo" array: - foo: bar - 1 - "string" - ["nested", "array", 5.5] ` YAMLEq(mockT, expected, actual) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEq_Array(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEq_HashAndArrayNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEq_HashesNotEquivalent(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEq_ActualIsSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `{"foo": "bar"}`, "Simple String") if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEq_ExpectedIsSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, "Simple String", `{"foo": "bar", "hello": "world"}`) if !mockT.Failed { t.Error("Check should fail") } } func TestYAMLEq_ExpectedAndActualSimpleString(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, "Simple String", "Simple String") if mockT.Failed { t.Error("Check should pass") } } func TestYAMLEq_ArraysOfDifferentOrder(t *testing.T) { t.Parallel() mockT := new(MockT) YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) if !mockT.Failed { t.Error("Check should fail") } } func ExampleComparisonAssertionFunc() { t := &testing.T{} // provided by test adder := func(x, y int) int { return x + y } type args struct { x int y int } tests := []struct { name string args args expect int assertion ComparisonAssertionFunc }{ {"2+2=4", args{2, 2}, 4, Equal}, {"2+2!=5", args{2, 2}, 5, NotEqual}, {"2+3==5", args{2, 3}, 5, Exactly}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y)) }) } } func TestComparisonAssertionFunc(t *testing.T) { t.Parallel() type iface interface { Name() string } tests := []struct { name string expect interface{} got interface{} assertion ComparisonAssertionFunc }{ {"implements", (*iface)(nil), t, Implements}, {"isType", (*testing.T)(nil), t, IsType}, {"equal", t, t, Equal}, {"equalValues", t, t, EqualValues}, {"exactly", t, t, Exactly}, {"notEqual", t, nil, NotEqual}, {"NotEqualValues", t, nil, NotEqualValues}, {"notContains", []int{1, 2, 3}, 4, NotContains}, {"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset}, {"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset}, {"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch}, {"regexp", "^t.*y$", "testify", Regexp}, {"notRegexp", "^t.*y$", "Testify", NotRegexp}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.expect, tt.got) }) } } func ExampleValueAssertionFunc() { t := &testing.T{} // provided by test dumbParse := func(input string) interface{} { var x interface{} json.Unmarshal([]byte(input), &x) return x } tests := []struct { name string arg string assertion ValueAssertionFunc }{ {"true is not nil", "true", NotNil}, {"empty string is nil", "", Nil}, {"zero is not nil", "0", NotNil}, {"zero is zero", "0", Zero}, {"false is zero", "false", Zero}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, dumbParse(tt.arg)) }) } } func TestValueAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string value interface{} assertion ValueAssertionFunc }{ {"notNil", true, NotNil}, {"nil", nil, Nil}, {"empty", []int{}, Empty}, {"notEmpty", []int{1}, NotEmpty}, {"zero", false, Zero}, {"notZero", 42, NotZero}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.value) }) } } func ExampleBoolAssertionFunc() { t := &testing.T{} // provided by test isOkay := func(x int) bool { return x >= 42 } tests := []struct { name string arg int assertion BoolAssertionFunc }{ {"-1 is bad", -1, False}, {"42 is good", 42, True}, {"41 is bad", 41, False}, {"45 is cool", 45, True}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, isOkay(tt.arg)) }) } } func TestBoolAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string value bool assertion BoolAssertionFunc }{ {"true", true, True}, {"false", false, False}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.value) }) } } func ExampleErrorAssertionFunc() { t := &testing.T{} // provided by test dumbParseNum := func(input string, v interface{}) error { return json.Unmarshal([]byte(input), v) } tests := []struct { name string arg string assertion ErrorAssertionFunc }{ {"1.2 is number", "1.2", NoError}, {"1.2.3 not number", "1.2.3", Error}, {"true is not number", "true", Error}, {"3 is number", "3", NoError}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var x float64 tt.assertion(t, dumbParseNum(tt.arg, &x)) }) } } func TestErrorAssertionFunc(t *testing.T) { t.Parallel() tests := []struct { name string err error assertion ErrorAssertionFunc }{ {"noError", nil, NoError}, {"error", errors.New("whoops"), Error}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.assertion(t, tt.err) }) } } func TestEventuallyWithTFalse(t *testing.T) { t.Parallel() mockT := new(MockT) condition := func(collect *assert.CollectT) { True(collect, false) } EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond) True(t, mockT.Failed, "Check should fail") } func TestEventuallyWithTTrue(t *testing.T) { t.Parallel() mockT := new(MockT) counter := 0 condition := func(collect *assert.CollectT) { defer func() { counter += 1 }() True(collect, counter == 1) } EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond) False(t, mockT.Failed, "Check should pass") Equal(t, 2, counter, "Condition is expected to be called 2 times") } ================================================ FILE: suite/doc.go ================================================ // Package suite contains logic for creating testing suite structs // and running the methods on those structs as tests. The most useful // piece of this package is that you can create setup/teardown methods // on your testing suites, which will run before/after the whole suite // or individual tests (depending on which interface(s) you // implement). // // The suite package does not support parallel tests. See [issue 934]. // // A testing suite is usually built by first extending the built-in // suite functionality from suite.Suite in testify. Alternatively, // you could reproduce that logic on your own if you wanted (you // just need to implement the TestingSuite interface from // suite/interfaces.go). // // After that, you can implement any of the interfaces in // suite/interfaces.go to add setup/teardown functionality to your // suite, and add any methods that start with "Test" to add tests. // Methods that do not match any suite interfaces and do not begin // with "Test" will not be run by testify, and can safely be used as // helper methods. // // Once you've built your testing suite, you need to run the suite // (using suite.Run from testify) inside any function that matches the // identity that "go test" is already looking for (i.e. // func(*testing.T)). // // Regular expression to select test suites specified command-line // argument "-run". Regular expression to select the methods // of test suites specified command-line argument "-m". // Suite object has assertion methods. // // A crude example: // // // Basic imports // import ( // "testing" // "github.com/stretchr/testify/assert" // "github.com/stretchr/testify/suite" // ) // // // Define the suite, and absorb the built-in basic suite // // functionality from testify - including a T() method which // // returns the current testing context // type ExampleTestSuite struct { // suite.Suite // VariableThatShouldStartAtFive int // } // // // Make sure that VariableThatShouldStartAtFive is set to five // // before each test // func (suite *ExampleTestSuite) SetupTest() { // suite.VariableThatShouldStartAtFive = 5 // } // // // All methods that begin with "Test" are run as tests within a // // suite. // func (suite *ExampleTestSuite) TestExample() { // assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) // suite.Equal(5, suite.VariableThatShouldStartAtFive) // } // // // In order for 'go test' to run this suite, we need to create // // a normal test function and pass our suite to suite.Run // func TestExampleTestSuite(t *testing.T) { // suite.Run(t, new(ExampleTestSuite)) // } // // [issue 934]: https://github.com/stretchr/testify/issues/934 package suite ================================================ FILE: suite/interfaces.go ================================================ package suite import "testing" // TestingSuite can store and return the current *testing.T context // generated by 'go test'. type TestingSuite interface { T() *testing.T SetT(*testing.T) SetS(suite TestingSuite) } // SetupAllSuite has a SetupSuite method, which will run before the // tests in the suite are run. type SetupAllSuite interface { SetupSuite() } // SetupTestSuite has a SetupTest method, which will run before each // test in the suite. type SetupTestSuite interface { SetupTest() } // TearDownAllSuite has a TearDownSuite method, which will run after // all the tests in the suite have been run. type TearDownAllSuite interface { TearDownSuite() } // TearDownTestSuite has a TearDownTest method, which will run after // each test in the suite. type TearDownTestSuite interface { TearDownTest() } // BeforeTest has a function to be executed right before the test // starts and receives the suite and test names as input type BeforeTest interface { BeforeTest(suiteName, testName string) } // AfterTest has a function to be executed right after the test // finishes and receives the suite and test names as input type AfterTest interface { AfterTest(suiteName, testName string) } // WithStats implements HandleStats, a function that will be executed // when a test suite is finished. The stats contain information about // the execution of that suite and its tests. type WithStats interface { HandleStats(suiteName string, stats *SuiteInformation) } // SetupSubTest has a SetupSubTest method, which will run before each // subtest in the suite. type SetupSubTest interface { SetupSubTest() } // TearDownSubTest has a TearDownSubTest method, which will run after // each subtest in the suite have been run. type TearDownSubTest interface { TearDownSubTest() } ================================================ FILE: suite/stats.go ================================================ package suite import "time" // SuiteInformation stats stores stats for the whole suite execution. type SuiteInformation struct { Start, End time.Time TestStats map[string]*TestInformation } // TestInformation stores information about the execution of each test. type TestInformation struct { TestName string Start, End time.Time Passed bool } func newSuiteInformation() *SuiteInformation { return &SuiteInformation{ TestStats: make(map[string]*TestInformation), } } func (s *SuiteInformation) start(testName string) { if s == nil { return } s.TestStats[testName] = &TestInformation{ TestName: testName, Start: time.Now(), } } func (s *SuiteInformation) end(testName string, passed bool) { if s == nil { return } s.TestStats[testName].End = time.Now() s.TestStats[testName].Passed = passed } func (s *SuiteInformation) Passed() bool { for _, stats := range s.TestStats { if !stats.Passed { return false } } return true } ================================================ FILE: suite/stats_test.go ================================================ package suite import ( "testing" "github.com/stretchr/testify/assert" ) func TestPassedReturnsTrueWhenAllTestsPass(t *testing.T) { sinfo := newSuiteInformation() sinfo.TestStats = map[string]*TestInformation{ "Test1": {TestName: "Test1", Passed: true}, "Test2": {TestName: "Test2", Passed: true}, "Test3": {TestName: "Test3", Passed: true}, } assert.True(t, sinfo.Passed()) } func TestPassedReturnsFalseWhenSomeTestFails(t *testing.T) { sinfo := newSuiteInformation() sinfo.TestStats = map[string]*TestInformation{ "Test1": {TestName: "Test1", Passed: true}, "Test2": {TestName: "Test2", Passed: false}, "Test3": {TestName: "Test3", Passed: true}, } assert.False(t, sinfo.Passed()) } func TestPassedReturnsFalseWhenAllTestsFail(t *testing.T) { sinfo := newSuiteInformation() sinfo.TestStats = map[string]*TestInformation{ "Test1": {TestName: "Test1", Passed: false}, "Test2": {TestName: "Test2", Passed: false}, "Test3": {TestName: "Test3", Passed: false}, } assert.False(t, sinfo.Passed()) } ================================================ FILE: suite/suite.go ================================================ package suite import ( "flag" "fmt" "os" "reflect" "regexp" "runtime/debug" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") // Suite is a basic testing suite with methods for storing and // retrieving the current *testing.T context. type Suite struct { *assert.Assertions mu sync.RWMutex require *require.Assertions t *testing.T // Parent suite to have access to the implemented methods of parent struct s TestingSuite } // T retrieves the current *testing.T context. func (suite *Suite) T() *testing.T { suite.mu.RLock() defer suite.mu.RUnlock() return suite.t } // SetT sets the current *testing.T context. func (suite *Suite) SetT(t *testing.T) { suite.mu.Lock() defer suite.mu.Unlock() suite.t = t suite.Assertions = assert.New(t) suite.require = require.New(t) } // SetS needs to set the current test suite as parent // to get access to the parent methods func (suite *Suite) SetS(s TestingSuite) { suite.s = s } // Require returns a require context for suite. func (suite *Suite) Require() *require.Assertions { suite.mu.Lock() defer suite.mu.Unlock() if suite.require == nil { panic("'Require' must not be called before 'Run' or 'SetT'") } return suite.require } // Assert returns an assert context for suite. Normally, you can call: // // suite.NoError(err) // // But for situations where the embedded methods are overridden (for example, // you might want to override assert.Assertions with require.Assertions), this // method is provided so you can call: // // suite.Assert().NoError(err) func (suite *Suite) Assert() *assert.Assertions { suite.mu.Lock() defer suite.mu.Unlock() if suite.Assertions == nil { panic("'Assert' must not be called before 'Run' or 'SetT'") } return suite.Assertions } func recoverAndFailOnPanic(t *testing.T) { t.Helper() r := recover() failOnPanic(t, r) } func failOnPanic(t *testing.T, r interface{}) { t.Helper() if r != nil { t.Errorf("test panicked: %v\n%s", r, debug.Stack()) t.FailNow() } } // Run provides suite functionality around golang subtests. It should be // called in place of t.Run(name, func(t *testing.T)) in test suite code. // The passed-in func will be executed as a subtest with a fresh instance of t. // Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName. func (suite *Suite) Run(name string, subtest func()) bool { oldT := suite.T() return oldT.Run(name, func(t *testing.T) { suite.SetT(t) defer suite.SetT(oldT) defer recoverAndFailOnPanic(t) if setupSubTest, ok := suite.s.(SetupSubTest); ok { setupSubTest.SetupSubTest() } if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok { defer tearDownSubTest.TearDownSubTest() } subtest() }) } type test = struct { name string run func(t *testing.T) } // Run takes a testing suite and runs all of the tests attached // to it. func Run(t *testing.T, suite TestingSuite) { defer recoverAndFailOnPanic(t) suite.SetT(t) suite.SetS(suite) var stats *SuiteInformation if _, ok := suite.(WithStats); ok { stats = newSuiteInformation() } var tests []test methodFinder := reflect.TypeOf(suite) suiteName := methodFinder.Elem().Name() var matchMethodRE *regexp.Regexp if *matchMethod != "" { var err error matchMethodRE, err = regexp.Compile(*matchMethod) if err != nil { fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) os.Exit(1) } } for i := 0; i < methodFinder.NumMethod(); i++ { method := methodFinder.Method(i) if !strings.HasPrefix(method.Name, "Test") { continue } // Apply -testify.m filter if matchMethodRE != nil && !matchMethodRE.MatchString(method.Name) { continue } // Check method signature if method.Type.NumIn() > 1 || method.Type.NumOut() > 0 { tests = append(tests, test{ name: method.Name, run: func(t *testing.T) { t.Errorf( "testify: suite method %q has invalid signature: expected no input or output parameters, method has %d input parameters and %d output parameters", method.Name, method.Type.NumIn()-1, method.Type.NumOut(), ) }, }) continue } test := test{ name: method.Name, run: func(t *testing.T) { parentT := suite.T() suite.SetT(t) defer recoverAndFailOnPanic(t) defer func() { t.Helper() r := recover() stats.end(method.Name, !t.Failed() && r == nil) if afterTestSuite, ok := suite.(AfterTest); ok { afterTestSuite.AfterTest(suiteName, method.Name) } if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { tearDownTestSuite.TearDownTest() } suite.SetT(parentT) failOnPanic(t, r) }() if setupTestSuite, ok := suite.(SetupTestSuite); ok { setupTestSuite.SetupTest() } if beforeTestSuite, ok := suite.(BeforeTest); ok { beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name) } stats.start(method.Name) method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) }, } tests = append(tests, test) } if len(tests) == 0 { return } if stats != nil { stats.Start = time.Now() } if setupAllSuite, ok := suite.(SetupAllSuite); ok { setupAllSuite.SetupSuite() } defer func() { if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { tearDownAllSuite.TearDownSuite() } if suiteWithStats, measureStats := suite.(WithStats); measureStats { stats.End = time.Now() suiteWithStats.HandleStats(suiteName, stats) } }() runTests(t, tests) } func runTests(t *testing.T, tests []test) { if len(tests) == 0 { t.Log("warning: no tests to run") return } for _, test := range tests { t.Run(test.name, test.run) } } ================================================ FILE: suite/suite_test.go ================================================ package suite import ( "bytes" "errors" "flag" "io" "math/rand" "os" "os/exec" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // allTestsFilter is a yes filter for testing.RunTests func allTestsFilter(pat, str string) (bool, error) { return true, nil } // SuiteRequireTwice is intended to test the usage of suite.Require in two // different tests type SuiteRequireTwice struct{ Suite } // TestSuiteRequireTwice checks for regressions of issue #149 where // suite.requirements was not initialized in suite.SetT() // A regression would result on these tests panicking rather than failing. func TestSuiteRequireTwice(t *testing.T) { ok := testing.RunTests( allTestsFilter, []testing.InternalTest{{ Name: t.Name() + "/SuiteRequireTwice", F: func(t *testing.T) { suite := new(SuiteRequireTwice) Run(t, suite) }, }}, ) assert.False(t, ok) } func (s *SuiteRequireTwice) TestRequireOne() { r := s.Require() r.Equal(1, 2) } func (s *SuiteRequireTwice) TestRequireTwo() { r := s.Require() r.Equal(1, 2) } type panickingSuite struct { Suite panicInSetupSuite bool panicInSetupTest bool panicInBeforeTest bool panicInTest bool panicInAfterTest bool panicInTearDownTest bool panicInTearDownSuite bool } func (s *panickingSuite) SetupSuite() { if s.panicInSetupSuite { panic("oops in setup suite") } } func (s *panickingSuite) SetupTest() { if s.panicInSetupTest { panic("oops in setup test") } } func (s *panickingSuite) BeforeTest(_, _ string) { if s.panicInBeforeTest { panic("oops in before test") } } func (s *panickingSuite) Test() { if s.panicInTest { panic("oops in test") } } func (s *panickingSuite) AfterTest(_, _ string) { if s.panicInAfterTest { panic("oops in after test") } } func (s *panickingSuite) TearDownTest() { if s.panicInTearDownTest { panic("oops in tear down test") } } func (s *panickingSuite) TearDownSuite() { if s.panicInTearDownSuite { panic("oops in tear down suite") } } func TestSuiteRecoverPanic(t *testing.T) { ok := true panickingTests := []testing.InternalTest{ { Name: t.Name() + "/InSetupSuite", F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) }, }, { Name: t.Name() + "/InSetupTest", F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) }, }, { Name: t.Name() + "InBeforeTest", F: func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) }, }, { Name: t.Name() + "/InTest", F: func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) }, }, { Name: t.Name() + "/InAfterTest", F: func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) }, }, { Name: t.Name() + "/InTearDownTest", F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) }, }, { Name: t.Name() + "/InTearDownSuite", F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) }, }, } require.NotPanics(t, func() { ok = testing.RunTests(allTestsFilter, panickingTests) }) assert.False(t, ok) } // This suite is intended to store values to make sure that only // testing-suite-related methods are run. It's also a fully // functional example of a testing suite, using setup/teardown methods // and a helper method that is ignored by testify. To make this look // more like a real world example, all tests in the suite perform some // type of assertion. type SuiteTester struct { // Include our basic suite logic. Suite // Keep counts of how many times each method is run. SetupSuiteRunCount int TearDownSuiteRunCount int SetupTestRunCount int TearDownTestRunCount int TestOneRunCount int TestTwoRunCount int TestSubtestRunCount int NonTestMethodRunCount int SetupSubTestRunCount int TearDownSubTestRunCount int SetupSubTestNames []string TearDownSubTestNames []string SuiteNameBefore []string TestNameBefore []string SuiteNameAfter []string TestNameAfter []string TimeBefore []time.Time TimeAfter []time.Time } // The SetupSuite method will be run by testify once, at the very // start of the testing suite, before any tests are run. func (suite *SuiteTester) SetupSuite() { suite.SetupSuiteRunCount++ } func (suite *SuiteTester) BeforeTest(suiteName, testName string) { suite.SuiteNameBefore = append(suite.SuiteNameBefore, suiteName) suite.TestNameBefore = append(suite.TestNameBefore, testName) suite.TimeBefore = append(suite.TimeBefore, time.Now()) } func (suite *SuiteTester) AfterTest(suiteName, testName string) { suite.SuiteNameAfter = append(suite.SuiteNameAfter, suiteName) suite.TestNameAfter = append(suite.TestNameAfter, testName) suite.TimeAfter = append(suite.TimeAfter, time.Now()) } // The TearDownSuite method will be run by testify once, at the very // end of the testing suite, after all tests have been run. func (suite *SuiteTester) TearDownSuite() { suite.TearDownSuiteRunCount++ } // The SetupTest method will be run before every test in the suite. func (suite *SuiteTester) SetupTest() { suite.SetupTestRunCount++ } // The TearDownTest method will be run after every test in the suite. func (suite *SuiteTester) TearDownTest() { suite.TearDownTestRunCount++ } // Every method in a testing suite that begins with "Test" will be run // as a test. TestOne is an example of a test. For the purposes of // this example, we've included assertions in the tests, since most // tests will issue assertions. func (suite *SuiteTester) TestOne() { beforeCount := suite.TestOneRunCount suite.TestOneRunCount++ assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1) suite.Equal(suite.TestOneRunCount, beforeCount+1) } // TestTwo is another example of a test. func (suite *SuiteTester) TestTwo() { beforeCount := suite.TestTwoRunCount suite.TestTwoRunCount++ assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount) suite.NotEqual(suite.TestTwoRunCount, beforeCount) } func (suite *SuiteTester) TestSkip() { suite.T().Skip() } // NonTestMethod does not begin with "Test", so it will not be run by // testify as a test in the suite. This is useful for creating helper // methods for your tests. func (suite *SuiteTester) NonTestMethod() { suite.NonTestMethodRunCount++ } func (suite *SuiteTester) TestSubtest() { suite.TestSubtestRunCount++ for _, t := range []struct { testName string }{ {"first"}, {"second"}, } { suiteT := suite.T() suite.Run(t.testName, func() { // We should get a different *testing.T for subtests, so that // go test recognizes them as proper subtests for output formatting // and running individual subtests subTestT := suite.T() suite.NotEqual(subTestT, suiteT) }) suite.Equal(suiteT, suite.T()) } } func (suite *SuiteTester) TearDownSubTest() { suite.TearDownSubTestNames = append(suite.TearDownSubTestNames, suite.T().Name()) suite.TearDownSubTestRunCount++ } func (suite *SuiteTester) SetupSubTest() { suite.SetupSubTestNames = append(suite.SetupSubTestNames, suite.T().Name()) suite.SetupSubTestRunCount++ } type SuiteSkipTester struct { // Include our basic suite logic. Suite // Keep counts of how many times each method is run. SetupSuiteRunCount int TearDownSuiteRunCount int } func (suite *SuiteSkipTester) SetupSuite() { suite.SetupSuiteRunCount++ suite.T().Skip() } func (suite *SuiteSkipTester) TestNothing() { // SetupSuite is only called when at least one test satisfies // test filter. For this suite to be set up (and then tore down) // it is necessary to add at least one test method. } func (suite *SuiteSkipTester) TearDownSuite() { suite.TearDownSuiteRunCount++ } // TestRunSuite will be run by the 'go test' command, so within it, we // can run our suite using the Run(*testing.T, TestingSuite) function. func TestRunSuite(t *testing.T) { suiteTester := new(SuiteTester) Run(t, suiteTester) // Normally, the test would end here. The following are simply // some assertions to ensure that the Run function is working as // intended - they are not part of the example. // The suite was only run once, so the SetupSuite and TearDownSuite // methods should have each been run only once. assert.Equal(t, 1, suiteTester.SetupSuiteRunCount) assert.Equal(t, 1, suiteTester.TearDownSuiteRunCount) assert.Len(t, suiteTester.SuiteNameAfter, 4) assert.Len(t, suiteTester.SuiteNameBefore, 4) assert.Len(t, suiteTester.TestNameAfter, 4) assert.Len(t, suiteTester.TestNameBefore, 4) assert.Contains(t, suiteTester.TestNameAfter, "TestOne") assert.Contains(t, suiteTester.TestNameAfter, "TestTwo") assert.Contains(t, suiteTester.TestNameAfter, "TestSkip") assert.Contains(t, suiteTester.TestNameAfter, "TestSubtest") assert.Contains(t, suiteTester.TestNameBefore, "TestOne") assert.Contains(t, suiteTester.TestNameBefore, "TestTwo") assert.Contains(t, suiteTester.TestNameBefore, "TestSkip") assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest") assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/first") assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/second") assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/first") assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/second") for _, suiteName := range suiteTester.SuiteNameAfter { assert.Equal(t, "SuiteTester", suiteName) } for _, suiteName := range suiteTester.SuiteNameBefore { assert.Equal(t, "SuiteTester", suiteName) } for _, when := range suiteTester.TimeAfter { assert.False(t, when.IsZero()) } for _, when := range suiteTester.TimeBefore { assert.False(t, when.IsZero()) } // There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so // the SetupTest and TearDownTest methods (which should be run once for // each test) should have been run four times. assert.Equal(t, 4, suiteTester.SetupTestRunCount) assert.Equal(t, 4, suiteTester.TearDownTestRunCount) // Each test should have been run once. assert.Equal(t, 1, suiteTester.TestOneRunCount) assert.Equal(t, 1, suiteTester.TestTwoRunCount) assert.Equal(t, 1, suiteTester.TestSubtestRunCount) assert.Equal(t, 2, suiteTester.TearDownSubTestRunCount) assert.Equal(t, 2, suiteTester.SetupSubTestRunCount) // Methods that don't match the test method identifier shouldn't // have been run at all. assert.Equal(t, 0, suiteTester.NonTestMethodRunCount) suiteSkipTester := new(SuiteSkipTester) Run(t, suiteSkipTester) // The suite was only run once, so the SetupSuite and TearDownSuite // methods should have each been run only once, even though SetupSuite // called Skip() assert.Equal(t, 1, suiteSkipTester.SetupSuiteRunCount) assert.Equal(t, 1, suiteSkipTester.TearDownSuiteRunCount) } // This suite has no Test... methods. It's setup and teardown must be skipped. type SuiteSetupSkipTester struct { Suite setUp bool toreDown bool } func (s *SuiteSetupSkipTester) SetupSuite() { s.setUp = true } func (s *SuiteSetupSkipTester) NonTestMethod() { } func (s *SuiteSetupSkipTester) TearDownSuite() { s.toreDown = true } func TestSkippingSuiteSetup(t *testing.T) { suiteTester := new(SuiteSetupSkipTester) Run(t, suiteTester) assert.False(t, suiteTester.setUp) assert.False(t, suiteTester.toreDown) } func TestSuiteGetters(t *testing.T) { suite := new(SuiteTester) suite.SetT(t) assert.NotNil(t, suite.Assert()) assert.Equal(t, suite.Assertions, suite.Assert()) assert.NotNil(t, suite.Require()) assert.Equal(t, suite.require, suite.Require()) } type SuiteLoggingTester struct { Suite } func (s *SuiteLoggingTester) TestLoggingPass() { s.T().Log("TESTLOGPASS") } func (s *SuiteLoggingTester) TestLoggingFail() { s.T().Log("TESTLOGFAIL") assert.NotNil(s.T(), nil) // expected to fail } type StdoutCapture struct { oldStdout *os.File readPipe *os.File } func (sc *StdoutCapture) StartCapture() { sc.oldStdout = os.Stdout sc.readPipe, os.Stdout, _ = os.Pipe() } func (sc *StdoutCapture) StopCapture() (string, error) { if sc.oldStdout == nil || sc.readPipe == nil { return "", errors.New("StartCapture not called before StopCapture") } os.Stdout.Close() os.Stdout = sc.oldStdout bytes, err := io.ReadAll(sc.readPipe) if err != nil { return "", err } return string(bytes), nil } func TestSuiteLogging(t *testing.T) { suiteLoggingTester := new(SuiteLoggingTester) capture := StdoutCapture{} internalTest := testing.InternalTest{ Name: t.Name() + "/SuiteLoggingTester", F: func(subT *testing.T) { Run(subT, suiteLoggingTester) }, } capture.StartCapture() testing.RunTests(allTestsFilter, []testing.InternalTest{internalTest}) output, err := capture.StopCapture() require.NoError(t, err, "Got an error trying to capture stdout and stderr!") require.NotEmpty(t, output, "output content must not be empty") // Failed tests' output is always printed assert.Contains(t, output, "TESTLOGFAIL") if testing.Verbose() { // In verbose mode, output from successful tests is also printed assert.Contains(t, output, "TESTLOGPASS") } else { assert.NotContains(t, output, "TESTLOGPASS") } } type CallOrderSuite struct { Suite callOrder []string } func (s *CallOrderSuite) call(method string) { time.Sleep(time.Duration(rand.Intn(300)) * time.Millisecond) s.callOrder = append(s.callOrder, method) } func TestSuiteCallOrder(t *testing.T) { Run(t, new(CallOrderSuite)) } func (s *CallOrderSuite) SetupSuite() { s.call("SetupSuite") } func (s *CallOrderSuite) TearDownSuite() { s.call("TearDownSuite") assert.Equal(s.T(), "SetupSuite;SetupTest;Test A;SetupSubTest;SubTest A1;TearDownSubTest;SetupSubTest;SubTest A2;TearDownSubTest;TearDownTest;SetupTest;Test B;SetupSubTest;SubTest B1;TearDownSubTest;SetupSubTest;SubTest B2;TearDownSubTest;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";")) } func (s *CallOrderSuite) SetupTest() { s.call("SetupTest") } func (s *CallOrderSuite) TearDownTest() { s.call("TearDownTest") } func (s *CallOrderSuite) SetupSubTest() { s.call("SetupSubTest") } func (s *CallOrderSuite) TearDownSubTest() { s.call("TearDownSubTest") } func (s *CallOrderSuite) Test_A() { s.call("Test A") s.Run("SubTest A1", func() { s.call("SubTest A1") }) s.Run("SubTest A2", func() { s.call("SubTest A2") }) } func (s *CallOrderSuite) Test_B() { s.call("Test B") s.Run("SubTest B1", func() { s.call("SubTest B1") }) s.Run("SubTest B2", func() { s.call("SubTest B2") }) } type suiteWithStats struct { Suite wasCalled bool stats *SuiteInformation } func (s *suiteWithStats) HandleStats(suiteName string, stats *SuiteInformation) { s.wasCalled = true s.stats = stats } func (s *suiteWithStats) TestSomething() { s.Equal(1, 1) } func (s *suiteWithStats) TestPanic() { panic("oops") } func TestSuiteWithStats(t *testing.T) { suiteWithStats := new(suiteWithStats) suiteSuccess := testing.RunTests(allTestsFilter, []testing.InternalTest{ { Name: t.Name() + "/suiteWithStats", F: func(t *testing.T) { Run(t, suiteWithStats) }, }, }) require.False(t, suiteSuccess, "suiteWithStats should report test failure because of panic in TestPanic") assert.True(t, suiteWithStats.wasCalled) assert.NotZero(t, suiteWithStats.stats.Start) assert.NotZero(t, suiteWithStats.stats.End) assert.False(t, suiteWithStats.stats.Passed()) testStats := suiteWithStats.stats.TestStats assert.NotZero(t, testStats["TestSomething"].Start) assert.NotZero(t, testStats["TestSomething"].End) assert.True(t, testStats["TestSomething"].Passed) assert.NotZero(t, testStats["TestPanic"].Start) assert.NotZero(t, testStats["TestPanic"].End) assert.False(t, testStats["TestPanic"].Passed) } // FailfastSuite will test the behavior when running with the failfast flag // It logs calls in the callOrder slice which we then use to assert the correct calls were made type FailfastSuite struct { Suite callOrder []string } func (s *FailfastSuite) call(method string) { s.callOrder = append(s.callOrder, method) } func TestFailfastSuite(t *testing.T) { // This test suite is run twice. Once normally and once with the -failfast flag by TestFailfastSuiteFailFastOn // If you need to debug it run this test directly with the failfast flag set on/off as you need failFast := flag.Lookup("test.failfast").Value.(flag.Getter).Get().(bool) s := new(FailfastSuite) ok := testing.RunTests( allTestsFilter, []testing.InternalTest{{ Name: t.Name() + "/FailfastSuite", F: func(t *testing.T) { Run(t, s) }, }}, ) assert.False(t, ok) var expect []string if failFast { // Test A Fails and because we are running with failfast Test B never runs and we proceed straight to TearDownSuite expect = []string{"SetupSuite", "SetupTest", "Test A Fails", "TearDownTest", "TearDownSuite"} } else { // Test A Fails and because we are running without failfast we continue and run Test B and then proceed to TearDownSuite expect = []string{"SetupSuite", "SetupTest", "Test A Fails", "TearDownTest", "SetupTest", "Test B Passes", "TearDownTest", "TearDownSuite"} } callOrderAssert(t, expect, s.callOrder) } type tHelper interface { Helper() } // callOrderAssert is a help with confirms that asserts that expect // matches one or more times in callOrder. This makes it compatible // with go test flag -count=X where X > 1. func callOrderAssert(t *testing.T, expect, callOrder []string) { var ti interface{} = t if h, ok := ti.(tHelper); ok { h.Helper() } callCount := len(callOrder) expectCount := len(expect) if callCount > expectCount && callCount%expectCount == 0 { // Command line flag -count=X where X > 1. for len(callOrder) >= expectCount { assert.Equal(t, expect, callOrder[:expectCount]) callOrder = callOrder[expectCount:] } return } assert.Equal(t, expect, callOrder) } func TestFailfastSuiteFailFastOn(t *testing.T) { // To test this with failfast on (and isolated from other intended test failures in our test suite) we launch it in its own process cmd := exec.Command("go", "test", "-v", "-race", "-run", "TestFailfastSuite", "-failfast") var out bytes.Buffer cmd.Stdout = &out t.Log("Running go test -v -race -run TestFailfastSuite -failfast") err := cmd.Run() t.Log(out.String()) if err != nil { t.Log(err) t.Fail() } } func (s *FailfastSuite) SetupSuite() { s.call("SetupSuite") } func (s *FailfastSuite) TearDownSuite() { s.call("TearDownSuite") } func (s *FailfastSuite) SetupTest() { s.call("SetupTest") } func (s *FailfastSuite) TearDownTest() { s.call("TearDownTest") } func (s *FailfastSuite) Test_A_Fails() { s.call("Test A Fails") s.T().Error("Test A meant to fail") } func (s *FailfastSuite) Test_B_Passes() { s.call("Test B Passes") s.Require().True(true) } type subtestPanicSuite struct { Suite inTearDownSuite bool inTearDownTest bool inTearDownSubTest bool } func (s *subtestPanicSuite) TearDownSuite() { s.inTearDownSuite = true } func (s *subtestPanicSuite) TearDownTest() { s.inTearDownTest = true } func (s *subtestPanicSuite) TearDownSubTest() { s.inTearDownSubTest = true } func (s *subtestPanicSuite) TestSubtestPanic() { ok := s.Run("subtest", func() { panic("panic") }) s.False(ok, "subtest failure is expected") } func TestSubtestPanic(t *testing.T) { suite := new(subtestPanicSuite) ok := testing.RunTests( allTestsFilter, []testing.InternalTest{{ Name: t.Name() + "/subtestPanicSuite", F: func(t *testing.T) { Run(t, suite) }, }}, ) assert.False(t, ok, "TestSubtestPanic/subtest should make the testsuite fail") assert.True(t, suite.inTearDownSubTest) assert.True(t, suite.inTearDownTest) assert.True(t, suite.inTearDownSuite) } type unInitializedSuite struct { Suite } // TestUnInitializedSuites asserts the behavior of the suite methods when the // suite is not initialized func TestUnInitializedSuites(t *testing.T) { t.Run("should panic on Require", func(t *testing.T) { suite := new(unInitializedSuite) assert.Panics(t, func() { suite.Require().True(true) }) }) t.Run("should panic on Assert", func(t *testing.T) { suite := new(unInitializedSuite) assert.Panics(t, func() { suite.Assert().True(true) }) }) } // SuiteSignatureValidationTester tests valid and invalid method signatures. type SuiteSignatureValidationTester struct { Suite executedTestCount int setUp bool toreDown bool } // SetupSuite runs once before any tests. func (s *SuiteSignatureValidationTester) SetupSuite() { s.setUp = true } // TearDownSuite runs once after all tests. func (s *SuiteSignatureValidationTester) TearDownSuite() { s.toreDown = true } // Valid test method — should run. func (s *SuiteSignatureValidationTester) TestValidSignature() { s.executedTestCount++ } // Invalid: has return value. func (s *SuiteSignatureValidationTester) TestInvalidSignatureReturnValue() interface{} { s.executedTestCount++ return nil } // Invalid: has input arg. func (s *SuiteSignatureValidationTester) TestInvalidSignatureArg(somearg string) { s.executedTestCount++ } // Invalid: both input arg and return value. func (s *SuiteSignatureValidationTester) TestInvalidSignatureBoth(somearg string) interface{} { s.executedTestCount++ return nil } // TestSuiteSignatureValidation ensures that invalid signature methods fail and valid method runs. func TestSuiteSignatureValidation(t *testing.T) { suiteTester := new(SuiteSignatureValidationTester) ok := testing.RunTests(allTestsFilter, []testing.InternalTest{ { Name: "signature validation", F: func(t *testing.T) { Run(t, suiteTester) }, }, }) require.False(t, ok, "Suite should fail due to invalid method signatures") assert.Equal(t, 1, suiteTester.executedTestCount, "Only the valid test method should have been executed") assert.True(t, suiteTester.setUp, "SetupSuite should have been executed") assert.True(t, suiteTester.toreDown, "TearDownSuite should have been executed") }