diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 2e53c4e6d..a34b3e8a5 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -8,18 +8,72 @@ This is the go-openapi fork of the testify testing package. The main goal is to ## Key Architecture -### Core Packages +### Single Source of Truth: `internal/assertions/` + +All assertion implementations live in `internal/assertions/`, organized by domain: +- **boolean.go** - True, False +- **collection.go** - Contains, Empty, Len, ElementsMatch, Subset, etc. +- **compare.go** - Greater, Less, comparison assertions +- **equal.go** - Equal, EqualValues, NotEqual, Same, etc. +- **error.go** - Error, NoError, ErrorIs, ErrorAs, etc. +- **file.go** - FileExists, DirExists, FileEmpty, FileNotEmpty +- **http.go** - HTTPSuccess, HTTPError, HTTPStatusCode, etc. +- **json.go** - JSONEq +- **number.go** - InDelta, InEpsilon, Positive, Negative +- **panic.go** - Panics, NotPanics, PanicsWithValue +- **string.go** - Regexp, NotRegexp +- **time.go** - WithinDuration +- **type.go** - IsType, Zero, NotZero, Implements +- **yaml.go** - YAMLEq + +**Key principle:** Write assertions once in `internal/assertions/` with comprehensive tests. Everything else is generated. + +### Core Packages (Generated) - **assert**: Provides non-fatal test assertions (tests continue after failures) + - Generated from `internal/assertions/` by `codegen/` + - Returns `bool` to indicate success/failure - **require**: Provides fatal test assertions (tests stop immediately on failure via `FailNow()`) -- Both packages share similar APIs, but `require` wraps `assert` functions to make them fatal + - Generated from `internal/assertions/` by `codegen/` + - Void functions that call `FailNow()` on failure -### Code Generation -- The codebase uses code generation extensively via `_codegen/main.go` -- Generated files include: - - `assert/assertion_format.go` - Format string variants of assertions - - `assert/assertion_forward.go` - Forwarded assertion methods - - `require/require.go` - Require variants of all assert functions - - `require/require_forward.go` - Forwarded require methods +Both packages are 100% generated and maintain API consistency mechanically. + +### Code Generation Architecture + +The codebase uses sophisticated code generation via the `codegen/` directory: + +**Structure:** +``` +codegen/ +├── internal/ +│ ├── scanner/ # Parses internal/assertions using go/packages and go/types +│ ├── generator/ # Template-based code generation engine +│ ├── model/ # Data model for assertions +├── main.go # CLI orchestration +└── (generated outputs in assert/ and require/) +``` + +**Generated files include:** +- **assert/assertion_assertions.go** - Package-level assertion functions +- **assert/assertion_format.go** - Format string variants (Equalf, Truef, etc.) +- **assert/assertion_forward.go** - Forwarded assertion methods for chaining +- **assert/assertion_*_test.go** - Generated tests for all assert variants +- **require/requirement_assertions.go** - Fatal assertion functions +- **require/requirement_format.go** - Fatal format variants +- **require/requirement_forward.go** - Fatal forwarded methods +- **require/requirement_*_test.go** - Generated tests for all require variants + +**Each assertion function generates 8 variants:** +1. `assert.Equal(t, ...)` - package-level function +2. `assert.Equalf(t, ..., "msg")` - format variant +3. `a.Equal(...)` - forward method (where `a := assert.New(t)`) +4. `a.Equalf(..., "msg")` - forward format variant +5. `require.Equal(t, ...)` - fatal package-level +6. `require.Equalf(t, ..., "msg")` - fatal format variant +7. `r.Equal(...)` - fatal forward method +8. `r.Equalf(..., "msg")` - fatal forward format variant + +With 76 assertion functions, this generates 608 functions automatically. ### Dependency Isolation Strategy - **internal/spew**: Internalized copy of go-spew for pretty-printing values @@ -36,31 +90,110 @@ The "enable" pattern allows YAML functionality to be opt-in: import `_ "github.c # Run all tests go test ./... -# Run tests in a specific package -go test ./assert -go test ./require +# Run tests in specific packages +go test ./internal/assertions # Source of truth with exhaustive tests +go test ./assert # Generated package tests +go test ./require # Generated package tests # Run a single test -go test ./assert -run TestEqual +go test ./internal/assertions -run TestEqual + +# Run with coverage +go test -cover ./internal/assertions # Should be 90%+ +go test -cover ./assert # Should be ~100% +go test -cover ./require # Should be ~100% # Run tests with verbose output go test -v ./... ``` +### Adding a New Assertion + +**The entire workflow:** +1. Add function to appropriate file in `internal/assertions/` +2. Add "Examples:" section to doc comment +3. Add tests to corresponding `*_test.go` file +4. Run `go generate ./...` +5. Done - all 8 variants generated with tests + +**Example - Adding a new assertion:** +```go +// In internal/assertions/string.go + +// StartsWith asserts that the string starts with the given prefix. +// +// Examples: +// +// success: "hello world", "hello" +// failure: "hello world", "bye" +func StartsWith(t T, str, prefix string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + if !strings.HasPrefix(str, prefix) { + return Fail(t, fmt.Sprintf("Expected %q to start with %q", str, prefix), msgAndArgs...) + } + return true +} +``` + +Then add tests in `internal/assertions/string_test.go` and run `go generate ./...`. + +This generates: +- `assert.StartsWith(t, str, prefix)` +- `assert.StartsWithf(t, str, prefix, "msg")` +- `a.StartsWith(str, prefix)` (forward method) +- `a.StartsWithf(str, prefix, "msg")` +- `require.StartsWith(t, str, prefix)` +- `require.StartsWithf(t, str, prefix, "msg")` +- `r.StartsWith(str, prefix)` (forward method) +- `r.StartsWithf(str, prefix, "msg")` +- Tests for all 8 variants + ### Code Generation -When modifying assertion functions in `assert/assertions.go`, regenerate derived code: ```bash -# Generate all code +# Generate all code from internal/assertions go generate ./... -# This runs the codegen tool which: -# 1. Parses assert/assertions.go for TestingT functions -# 2. Generates format variants (e.g., Equalf from Equal) -# 3. Generates require variants (fatal versions) -# 4. Generates forwarded assertion methods +# Or run the generator directly +cd codegen && go run . -target assert +cd codegen && go run . -target require + +# The generator: +# 1. Scans internal/assertions/ for exported functions +# 2. Extracts "Examples:" from doc comments +# 3. Generates assert/ package with all variants + tests +# 4. Generates require/ package with all variants + tests +# 5. Ensures 100% test coverage via example-driven tests +``` + +### Example-Driven Test Generation + +The generator reads "Examples:" sections from doc comments: + +```go +// Equal asserts that two objects are equal. +// +// Examples: +// +// success: 123, 123 +// failure: 123, 456 +func Equal(t T, expected, actual any, msgAndArgs ...any) bool { + // implementation +} ``` -The code generator looks for functions with signature `func(TestingT, ...) bool` in the assert package and creates corresponding variants. +From this, it generates tests that verify: +- Success case works correctly +- Failure case works correctly and calls appropriate failure methods +- Format variants work with message parameter +- Forward methods work with chaining + +**Test case types:** +- `success: ` - Test should pass +- `failure: ` - Test should fail +- `panic: ` - Test should panic (followed by assertion message on next line) + `` ### Build and Verify ```bash @@ -68,10 +201,18 @@ The code generator looks for functions with signature `func(TestingT, ...) bool` go mod tidy # Build code generator -cd _codegen && go build +cd codegen && go build # Format code go fmt ./... + +# Run all tests +go test ./... + +# Check coverage +go test -cover ./internal/assertions +go test -cover ./assert +go test -cover ./require ``` ## Important Constraints @@ -106,3 +247,89 @@ When using YAML assertions (YAMLEq, YAMLEqf): ## Testing Philosophy Keep tests simple and focused. The assert package provides detailed failure messages automatically, so test code should be minimal and readable. Use `require` when a test cannot continue meaningfully after a failure, and `assert` when subsequent checks might provide additional context. + +### Testing Strategy: Layered Coverage + +**Layer 1: Exhaustive Tests in `internal/assertions/`** (94% coverage) +- Comprehensive table-driven tests using Go 1.23 `iter.Seq` patterns +- Error message content and format validation +- Edge cases, nil handling, type coercion scenarios +- Domain-organized test files mirroring implementation +- Source of truth for assertion correctness + +**Layer 2: Generated Smoke Tests in `assert/` and `require/`** (~100% coverage) +- Minimal mechanical tests proving functions exist and work +- Success case: verify correct return value / no FailNow +- Failure case: verify correct return value / FailNow called +- Generated from "Examples:" in doc comments +- No error message testing (already covered in Layer 1) + +**Layer 3: Meta Tests for Generator** (future) +- Test that code generation produces correct output +- Verify function signatures, imports, structure +- Optional golden file testing + +This layered approach ensures: +- Deep testing where it matters (source implementation) +- Complete coverage of generated forwarding code +- Simple, maintainable test generation +- No duplication of complex test logic + +## Architecture Benefits + +### Why This Design Wins + +**For Contributors:** +- Add assertion in focused, domain-organized file +- Write tests once in single location +- Run `go generate` and get all variants for free +- Clear separation: source vs generated code + +**For Maintainers:** +- Mechanical consistency across 608 generated functions +- Template changes affect all functions uniformly +- Easy to add new variants (e.g., generics) +- Single source of truth prevents drift + +**For Users:** +- Comprehensive API with 76 assertions +- All expected variants (package, format, forward, require) +- Zero external dependencies +- Drop-in replacement for stretchr/testify + +**The Math:** +- 76 assertion functions × 8 variants = 608 functions +- Old model: Manually maintain 608 functions across multiple packages +- New model: Write 76 functions once, generate the rest +- Result: 87% reduction in manual code maintenance + +### Technical Innovations + +**Go AST/Types Integration:** +- Scanner uses `go/packages` and `go/types` for semantic analysis +- Position-based lookup bridges AST and type information +- Import alias resolution for accurate code generation +- Handles complex Go constructs (generics, interfaces, variadic args) + +**Example-Driven Testing:** +- "Examples:" sections in doc comments drive test generation +- success/failure/panic cases extracted automatically +- Tests generated for all 8 variants per function +- Achieves 100% coverage with minimal test complexity + +**Template Architecture:** +- Separate templates for assert vs require packages +- Conditional logic handles return values vs void functions +- Mock selection based on FailNow requirements +- Consistent formatting and structure across all output + +## Example Coverage Status + +Most assertion functions now have "Examples:" sections in their doc comments. The generator extracts these to create both tests and testable examples. + +**Coverage notes:** +- Basic assertions (Equal, Error, Contains, Len, True, False) have complete examples +- Some complex assertions use TODO placeholders for pointer/struct values +- All new assertions should include Examples before merging + +For the complete guide on adding examples, see `docs/MAINTAINERS.md` section "Maintaining Generated Code". diff --git a/.codecov.yml b/.codecov.yml index bf2951fae..ee1d899ac 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,2 +1,2 @@ ignore: - - _codegen + - codegen diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a3a062ce9..85707f7ef 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,50 +1,214 @@ -# Contributing to Testify +## Contribution Guidelines -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. +You'll find below general guidelines, which mostly correspond to standard practices for open sourced repositories. -## Philosophy +>**TL;DR** +> +> If you're already an experienced go developer on github, then you should just feel at home with us +> and you may well skip the rest of this document. +> +> You'll essentially find the usual guideline for a go library project on github. -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: +These guidelines are general to all libraries published on github by the `go-openapi` organization. -*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. +You'll find more detailed (or repo-specific) instructions in the [maintainer's docs](../docs). -*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. +## How can I contribute? -*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. +There are many ways in which you can contribute. Here are a few ideas: -## Pull Requests + * Reporting Issues / Bugs + * Suggesting Improvements + * Code + * bug fixes and new features that are within the main project scope + * improving test coverage + * addressing code quality issues + * Documentation + * Art work that makes the project look great -We welcome pull requests! Please include the following in the description: +## Questions & issues - * Motivation, why your change is important or helpful - * Example usage (if applicable) - * Whether you intend to add / change behavior or fix a bug +### Asking questions -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. +You may inquire about anything about this library by reporting a "Question" issue on github. -See `MAINTAINERS.md` for a list of users who can approve / merge your changes. +### Reporting issues -## Issues +Reporting a problem with our libraries _is_ a valuable contribution. -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! +You can do this on the github issues page of this repository. -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. +Please be as specific as possible when describing your issue. +Whenever relevant, please provide information about your environment (go version, OS). + +Adding a code snippet to reproduce the issue is great, and as a big time saver for maintainers. + +### Triaging issues + +You can help triage issues which may include: + +* reproducing bug reports +* asking for important information, such as version numbers or reproduction instructions +* answering questions and sharing your insight in issue comments + +## Code contributions + +### Pull requests are always welcome + +We are always thrilled to receive pull requests, and we do our best to +process them as fast as possible. + +Not sure if that typo is worth a pull request? Do it! We will appreciate it. + +If your pull request is not accepted on the first try, don't be discouraged! +If there's a problem with the implementation, hopefully you received feedback on what to improve. + +If you have a lot of ideas or a lot of issues to solve, try to refrain a bit and post focused +pull requests. +Think that they must be reviewed by a maintainer and it is easy to lost track of things on big PRs. + +We're trying very hard to keep the go-openapi packages lean and focused. +These packages constitute a toolkit: it won't do everything for everybody out of the box, +but everybody can use it to do just about everything related to OpenAPI. + +This means that we might decide against incorporating a new feature. + +However, there might be a way to implement that feature *on top of* our libraries. + +### Environment + +You just need a `go` compiler to be installed. No special tools are needed to work with our libraries. + +The go compiler version required is always the old stable (latest minor go version - 1). + +If you're already used to work with `go` you should already have everything in place. + +Although not required, you'll be certainly more productive with a local installation of `golangci-lint`, +the meta-linter our CI uses. + +If you don't have it, you may install it like so: + +```sh +go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest +``` + +### Conventions + +#### Git flow + +Fork the repo and make changes to your fork in a feature branch. + +To submit a pull request, push your branch to your fork (e.g. `upstream` remote): +github will propose to open a pull request on the original repository. + +Typically you'd follow some common naming conventions: + +- if it's a bugfix branch, name it `fix/XXX-something`where XXX is the number of the + issue on github +- if it's a feature branch, create an enhancement issue to announce your + intentions, and name it `feature/XXX-something` where XXX is the number of the issue. + +> NOTE: we don't enforce naming conventions on branches: it's your fork after all. + +#### Tests + +Submit unit tests for your changes. + +Go has a great built-in test framework ; use it! + +Take a look at existing tests for inspiration, and run the full test suite on your branch +before submitting a pull request. + +Our CI measures test coverage and the test coverage of every patch. +Although not a blocking step - because there are so many special cases - +this is an indicator that maintainers consider when approving a PR. + +Please try your best to cover about 80% of your patch. + +#### Code style + +You may read our stance on code style [there](../docs/STYLE.md). + +#### Documentation + +Don't forget to update the documentation when creating or modifying features. + +Most documentation for this library is directly found in code as comments for godoc. + +The documentation for the go-openapi packages is published on the public go docs site: + + + +Check your documentation changes for clarity, concision, and correctness. + +If you want to assess the rendering of your changes when published to `pkg.go.dev`, you may +want to install the `pkgsite` tool proposed by `golang.org`. + +```sh +go install golang.org/x/pkgsite/cmd/pkgsite@latest +``` + +Then run on the repository folder: +```sh +pkgsite . +``` + +This wil run a godoc server locally where you may see the documentation generated from your local repository. + +#### Commit messages + +Pull requests descriptions should be as clear as possible and include a +reference to all the issues that they address. + +Pull requests must not contain commits from other users or branches. + +Commit messages are not required to follow the "conventional commit" rule, but it's certainly a good +thing to follow this guidelinea (e.g. "fix: blah blah", "ci: did this", "feat: did that" ...). + +The title in your commit message is used directly to produce our release notes: try to keep them neat. + +The commit message body should detail your changes. + +If an issue should be closed by a commit, please add this reference in the commit body: + +``` +* fixes #{issue number} +``` + +#### Code review + +Code review comments may be added to your pull request. + +Discuss, then make the suggested modifications and push additional commits to your feature branch. + +Be sure to post a comment after pushing. The new commits will show up in the pull +request automatically, but the reviewers will not be notified unless you comment. + +Before the pull request is merged, +**make sure that you squash your commits into logical units of work** +using `git rebase -i` and `git push -f`. + +After every commit the test suite should be passing. + +Include documentation changes in the same commit so that a revert would remove all traces of the feature or fix. + +#### Sign your work + +The sign-off is a simple line at the end of your commit message, +which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. + +We require the simple DCO below with an email signing your commit. +PGP-signed commit are greatly appreciated but not required. + +The rules are pretty simple: + +* read our [DCO](./DCO.md) (from [developercertificate.org](http://developercertificate.org/)) +* if you agree with these terms, then you just add a line to every git commit message + + Signed-off-by: Joe Smith + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +You can add the sign off when creating the git commit via `git commit -s`. diff --git a/.github/DCO.md b/.github/DCO.md new file mode 100644 index 000000000..e168dc4ca --- /dev/null +++ b/.github/DCO.md @@ -0,0 +1,40 @@ + # Developer's Certificate of Origin + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 6e94f71ad..0437d770c 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -72,6 +72,16 @@ jobs: cache: true cache-dependency-path: '**/go.sum' + - name: Ensure TMP is created on windows runners + # On windows, tests require testing.TempDir to reside on the same drive as the code. + # TMP is used by os.TempDir() to determine the location of temporary files. + if: ${{ runner.os == 'Windows' }} + shell: bash + run: | + TMP="${{ github.workspace }}\..\tmp" + mkdir -p ${TMP} + echo "TMP=${TMP}" >> "${GITHUB_ENV}" + - name: Run unit tests on all modules in this repo shell: bash env: diff --git a/README.md b/README.md index 45b82ac53..e4e868455 100644 --- a/README.md +++ b/README.md @@ -166,13 +166,13 @@ To use this package in your projects: Features include: - * [Easy assertions](./original.md#assert-package) - * ~[Mocking](./original.md#mock-package)~ removed - * ~[Testing suite interfaces and functions](./original.md#suite-package)~ removed + * [Easy assertions](./docs/ORIGINAL.md#assert-package) + * ~[Mocking](./docs/ORIGINAL.md#mock-package)~ removed + * ~[Testing suite interfaces and functions](./docs/ORIGINAL.md#suite-package)~ removed ## Examples -See [the original README](./original.md) +See [the original README](./docs/ORIGINAL.md) ## Licensing @@ -186,7 +186,6 @@ distributed with this fork, including internalized libraries. * stretchr/testify [SPDX-License-Identifier: MIT](./NOTICE) * github.com/davecgh/go-spew [SPDX-License-Identifier: ISC](./internal/spew/LICENSE) * github.com/pmezard/go-difflib [SPDX-License-Identifier: MIT-like](./internal/difflib/LICENSE) -* imports [SPDX-License-Identifier: MIT](./_codegen/internal/imports/LICENSE) ## PRs from the original repo diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..7f6a86bbd --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +This policy outlines the commitment and practices of the go-openapi maintainers regarding security. + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 2.0.x | :white_check_mark: | + +## Reporting a vulnerability + +If you become aware of a security vulnerability that affects the current repository, +please report it privately to the maintainers. + +Please follow the instructions provided by github to +[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability). + +TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability". diff --git a/_codegen/.gitignore b/_codegen/.gitignore deleted file mode 100644 index 0a25bc682..000000000 --- a/_codegen/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_codegen diff --git a/_codegen/go.mod b/_codegen/go.mod deleted file mode 100644 index 596ebc365..000000000 --- a/_codegen/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/go-openapi/testify/v2/_codegen - -go 1.24.0 diff --git a/_codegen/internal/imports/LICENSE b/_codegen/internal/imports/LICENSE deleted file mode 100644 index 3c3f71957..000000000 --- a/_codegen/internal/imports/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Ernesto Jiménez - -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. diff --git a/_codegen/internal/imports/imports.go b/_codegen/internal/imports/imports.go deleted file mode 100644 index 264404742..000000000 --- a/_codegen/internal/imports/imports.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Ernesto Jiménez - -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. -*/ - -package imports - -import ( - "go/types" - "os" - "path/filepath" - "strings" -) - -type Importer interface { - AddImportsFrom(t types.Type) - Imports() map[string]string -} - -type Imports struct { - *imports -} - -// imports contains metadata about all the imports from a given package. -type imports struct { - currentpkg string - imp map[string]string -} - -// AddImportsFrom adds imports used in the passed type. -func (imp *imports) AddImportsFrom(t types.Type) { - switch el := t.(type) { - case *types.Basic: - case *types.Slice: - imp.AddImportsFrom(el.Elem()) - case *types.Pointer: - imp.AddImportsFrom(el.Elem()) - case *types.Named: - pkg := el.Obj().Pkg() - if pkg == nil { - return - } - if pkg.Name() == imp.currentpkg { - return - } - imp.imp[cleanImportPath(pkg.Path())] = pkg.Name() - case *types.Tuple: - for v := range el.Variables() { - imp.AddImportsFrom(v.Type()) - } - default: - } -} - -func cleanImportPath(ipath string) string { - return gopathlessImportPath( - vendorlessImportPath(ipath), - ) -} - -func gopathlessImportPath(ipath string) string { - paths := strings.SplitSeq(os.Getenv("GOPATH"), ":") - for p := range paths { - ipath = strings.TrimPrefix(ipath, filepath.Join(p, "src")+string(filepath.Separator)) - } - return ipath -} - -// vendorlessImportPath returns the devendorized version of the provided import path. -// e.g. "foo/bar/vendor/a/b" => "a/b". -func vendorlessImportPath(ipath string) string { - // Devendorize for use in import statement. - if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { - return ipath[i+len("/vendor/"):] - } - if strings.HasPrefix(ipath, "vendor/") { - return ipath[len("vendor/"):] - } - return ipath -} - -// Imports adds imports used in the passed type. -func (imp *imports) Imports() map[string]string { - return imp.imp -} - -// New initializes a new structure to track packages imported by the currentpkg. -func New(currentpkg string) *Imports { - return &Imports{ - imports: &imports{ - currentpkg: currentpkg, - imp: make(map[string]string), - }, - } -} diff --git a/_codegen/main.go b/_codegen/main.go deleted file mode 100644 index 434acdb8d..000000000 --- a/_codegen/main.go +++ /dev/null @@ -1,344 +0,0 @@ -// This program reads all assertion functions from the assert package and -// automatically generates the corresponding requires and forwarded assertions - -package main - -import ( - "bytes" - "flag" - "fmt" - "go/ast" - "go/build" - "go/doc" - "go/format" - "go/importer" - "go/parser" - "go/token" - "go/types" - "io" - "log" - "os" - "path" - "regexp" - "strings" - "text/template" - - "github.com/go-openapi/testify/v2/_codegen/internal/imports" -) - -//nolint:gochecknoglobals // ok to register flags as globals -var ( - pkg = flag.String("assert-path", "github.com/go-openapi/testify/v2/assert", "Path to the assert package") - includeF = flag.Bool("include-format-funcs", false, "include format functions such as Errorf and Equalf") - outputPkg = flag.String("output-package", "", "package for the resulting code") - tmplFile = flag.String("template", "", "What file to load the function template from") - out = flag.String("out", "", "What file to write the source code to") -) - -func main() { - flag.Parse() - - scope, docs, err := parsePackageSource(*pkg) - if err != nil { - log.Fatal(err) - } - - importer, funcs, err := analyzeCode(scope, docs) - if err != nil { - log.Fatal(err) - } - - if err := generateCode(importer, funcs); err != nil { - log.Fatal(err) - } -} - -func generateCode(importer imports.Importer, funcs []testFunc) error { - buff := bytes.NewBuffer(nil) - - tmplHead, tmplFunc, err := parseTemplates() - if err != nil { - return err - } - - // Generate header - if err := tmplHead.Execute(buff, struct { - Name string - Imports map[string]string - }{ - *outputPkg, - importer.Imports(), - }); err != nil { - return err - } - - // Generate funcs - for _, fn := range funcs { - buff.WriteString("\n\n") - if err := tmplFunc.Execute(buff, &fn); err != nil { - return err - } - } - - code, err := format.Source(buff.Bytes()) - if err != nil { - return err - } - - // Write file - output, err := outputFile() - if err != nil { - return err - } - defer output.Close() - _, err = io.Copy(output, bytes.NewReader(code)) - return err -} - -func parseTemplates() (*template.Template, *template.Template, error) { - tmplHead, err := template.New("header").Parse(headerTemplate) - if err != nil { - return nil, nil, err - } - var funcTemplate string - if *tmplFile != "" { - f, err := os.ReadFile(*tmplFile) - if err != nil { - return nil, nil, err - } - funcTemplate = string(f) - } else { - funcTemplate = defaultTemplate - } - - tmpl, err := template.New("function").Funcs(template.FuncMap{ - "replace": strings.ReplaceAll, - }).Parse(funcTemplate) - if err != nil { - return nil, nil, err - } - - return tmplHead, tmpl, nil -} - -func outputFile() (*os.File, error) { - filename := *out - if filename == "-" || (filename == "" && *tmplFile == "") { - return os.Stdout, nil - } - if filename == "" { - filename = strings.TrimSuffix(strings.TrimSuffix(*tmplFile, ".tmpl"), ".go") + ".go" - } - return os.Create(filename) -} - -// analyzeCode takes the types scope and the docs and returns the import -// information and information about all the assertion functions. -func analyzeCode(scope *types.Scope, docs *doc.Package) (imports.Importer, []testFunc, error) { //nolint:ireturn // ok to use what stdlib does here - underlying := scope.Lookup("TestingT").Type().Underlying() - testingT, ok := underlying.(*types.Interface) - if !ok { - panic(fmt.Errorf("internal error: expected go type to resolve as *types.Interface but got: %T", underlying)) - } - - importer := imports.New(*outputPkg) - funcs := make([]testFunc, 0, len(docs.Funcs)) - // Go through all the top level functions - for _, fdocs := range docs.Funcs { - // Find the function - obj := scope.Lookup(fdocs.Name) - - fn, ok := obj.(*types.Func) - if !ok { - continue - } - - // Check function signature has at least two arguments - sig, ok := fn.Type().(*types.Signature) - if !ok { - return nil, nil, fmt.Errorf("internal error: expected go type to resolve as *types.Signature but got: %T", sig) - } - - const minParams = 2 - if sig.Params().Len() < minParams { - continue - } - // Check first argument is of type testingT - first, ok := sig.Params().At(0).Type().(*types.Named) - if !ok { - continue - } - - firstType, ok := first.Underlying().(*types.Interface) - if !ok { - continue - } - if !types.Implements(firstType, testingT) { - continue - } - - // Skip functions ending with f - if strings.HasSuffix(fdocs.Name, "f") && !*includeF { - continue - } - - funcs = append(funcs, testFunc{*outputPkg, fdocs, fn}) - importer.AddImportsFrom(sig.Params()) - } - - return importer, funcs, nil -} - -// parsePackageSource returns the types scope and the package documentation from the package. -func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) { - pd, err := build.Import(pkg, ".", 0) - if err != nil { - return nil, nil, err - } - - fset := token.NewFileSet() - files := make(map[string]*ast.File) - fileList := make([]*ast.File, len(pd.GoFiles)) - for i, fname := range pd.GoFiles { - src, err := os.ReadFile(path.Join(pd.Dir, fname)) - if err != nil { - return nil, nil, err - } - f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors) - if err != nil { - return nil, nil, err - } - files[fname] = f - fileList[i] = f - } - - cfg := types.Config{ - Importer: importer.ForCompiler(token.NewFileSet(), "source", nil), - } - info := types.Info{ - Defs: make(map[*ast.Ident]types.Object), - } - tp, err := cfg.Check(pkg, fset, fileList, &info) - if err != nil { - return nil, nil, err - } - - scope := tp.Scope() - - ap, _ := ast.NewPackage(fset, files, nil, nil) //nolint:staticcheck // will need more work to upgrade - docs := doc.New(ap, pkg, 0) - - return scope, docs, nil -} - -type testFunc struct { - CurrentPkg string - DocInfo *doc.Func - TypeInfo *types.Func -} - -func (f *testFunc) Qualifier(p *types.Package) string { - if p == nil || p.Name() == f.CurrentPkg { - return "" - } - return p.Name() -} - -func (f *testFunc) Params() string { - sig, ok := f.TypeInfo.Type().(*types.Signature) - if !ok { - panic(fmt.Errorf("internal error: expected go type to resolve as *types.Interface but got: %T", f.TypeInfo.Type())) - } - params := sig.Params() - var p strings.Builder - comma := "" - to := params.Len() - var i int - - if sig.Variadic() { - to-- - } - for i = 1; i < to; i++ { - param := params.At(i) - p.WriteString(fmt.Sprintf("%s%s %s", comma, param.Name(), types.TypeString(param.Type(), f.Qualifier))) - comma = ", " - } - if sig.Variadic() { - param := params.At(params.Len() - 1) - slice, ok := param.Type().(*types.Slice) - if !ok { - panic(fmt.Errorf("internal error: expected go type to resolve as *types.Slice but got: %T", param.Type())) - } - p.WriteString(fmt.Sprintf("%s%s ...%s", comma, param.Name(), types.TypeString(slice.Elem(), f.Qualifier))) - } - - return p.String() -} - -func (f *testFunc) ForwardedParams() string { - sig, ok := f.TypeInfo.Type().(*types.Signature) - if !ok { - panic(fmt.Errorf("internal error: expected go type to resolve as *types.Signature but got: %T", sig)) - } - params := sig.Params() - var p strings.Builder - comma := "" - to := params.Len() - var i int - - if sig.Variadic() { - to-- - } - for i = 1; i < to; i++ { - param := params.At(i) - p.WriteString(fmt.Sprintf("%s%s", comma, param.Name())) - comma = ", " - } - if sig.Variadic() { - param := params.At(params.Len() - 1) - p.WriteString(fmt.Sprintf("%s%s...", comma, param.Name())) - } - return p.String() -} - -func (f *testFunc) ParamsFormat() string { - return strings.Replace(f.Params(), "msgAndArgs", "msg string, args", 1) -} - -func (f *testFunc) ForwardedParamsFormat() string { - return strings.Replace(f.ForwardedParams(), "msgAndArgs", "append([]any{msg}, args...)", 1) -} - -func (f *testFunc) Comment() string { - return "// " + strings.ReplaceAll(strings.TrimSpace(f.DocInfo.Doc), "\n", "\n// ") -} - -func (f *testFunc) CommentFormat() string { - search := f.DocInfo.Name - replace := f.DocInfo.Name + "f" - comment := strings.ReplaceAll(f.Comment(), search, replace) - exp := regexp.MustCompile(replace + `\(((\(\)|[^\n])+)\)`) - return exp.ReplaceAllString(comment, replace+`($1, "error message %s", "formatted")`) -} - -func (f *testFunc) CommentWithoutT(receiver string) string { - search := fmt.Sprintf("assert.%s(t, ", f.DocInfo.Name) - replace := fmt.Sprintf("%s.%s(", receiver, f.DocInfo.Name) - return strings.ReplaceAll(f.Comment(), search, replace) -} - -// Standard header https://go.dev/s/generatedcode. -const headerTemplate = `// Code generated with github.com/go-openapi/testify/v2/_codegen; DO NOT EDIT. - -package {{.Name}} - -import ( -{{range $path, $name := .Imports}} - {{$name}} "{{$path}}"{{end}} -) -` - -const defaultTemplate = `{{.Comment}} -func (fwd *AssertionsForwarder) {{.DocInfo.Name}}({{.Params}}) bool { - return assert.{{.DocInfo.Name}}({{.ForwardedParams}}) -}` diff --git a/assert/assert_adhoc_example_1_test.go b/assert/assert_adhoc_example_1_test.go new file mode 100644 index 000000000..ef08ed0f8 --- /dev/null +++ b/assert/assert_adhoc_example_1_test.go @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assert_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExampleComparisonAssertionFunc() { + t := new(testing.T) // normally provided by test + + adder := func(x, y int) int { + return x + y + } + + for tt := range comparisonFuncCases() { + tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type args struct { + x int + y int +} + +type comparisonFuncCase struct { + name string + args args + expect int + assertion assert.ComparisonAssertionFunc +} + +func comparisonFuncCases() iter.Seq[comparisonFuncCase] { + return slices.Values([]comparisonFuncCase{ + {"2+2=4", args{2, 2}, 4, assert.Equal}, + {"2+2!=5", args{2, 2}, 5, assert.NotEqual}, + {"2+3==5", args{2, 3}, 5, assert.Exactly}, + }) +} diff --git a/assert/assert_adhoc_example_2_test.go b/assert/assert_adhoc_example_2_test.go new file mode 100644 index 000000000..a4b8082c2 --- /dev/null +++ b/assert/assert_adhoc_example_2_test.go @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assert_test + +import ( + "encoding/json" + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExampleValueAssertionFunc() { + t := new(testing.T) // normally provided by test + + dumbParse := func(input string) any { + var x any + _ = json.Unmarshal([]byte(input), &x) + return x + } + + for tt := range valueAssertionCases() { + tt.assertion(t, dumbParse(tt.arg)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type valueAssertionCase struct { + name string + arg string + assertion assert.ValueAssertionFunc +} + +func valueAssertionCases() iter.Seq[valueAssertionCase] { + return slices.Values([]valueAssertionCase{ + {"true is not nil", "true", assert.NotNil}, + {"empty string is nil", "", assert.Nil}, + {"zero is not nil", "0", assert.NotNil}, + {"zero is zero", "0", assert.Zero}, + {"false is zero", "false", assert.Zero}, + }) +} diff --git a/assert/assert_adhoc_example_3_test.go b/assert/assert_adhoc_example_3_test.go new file mode 100644 index 000000000..d6923509d --- /dev/null +++ b/assert/assert_adhoc_example_3_test.go @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assert_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExampleBoolAssertionFunc() { + t := new(testing.T) // normally provided by test + + isOkay := func(x int) bool { + return x >= 42 + } + + for tt := range boolAssertionCases() { + tt.assertion(t, isOkay(tt.arg)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type boolAssertionCase struct { + name string + arg int + assertion assert.BoolAssertionFunc +} + +func boolAssertionCases() iter.Seq[boolAssertionCase] { + return slices.Values([]boolAssertionCase{ + {"-1 is bad", -1, assert.False}, + {"42 is good", 42, assert.True}, + {"41 is bad", 41, assert.False}, + {"45 is cool", 45, assert.True}, + }) +} diff --git a/assert/assert_adhoc_example_4_test.go b/assert/assert_adhoc_example_4_test.go new file mode 100644 index 000000000..f8f21c5af --- /dev/null +++ b/assert/assert_adhoc_example_4_test.go @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assert_test + +import ( + "encoding/json" + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExampleErrorAssertionFunc() { + t := new(testing.T) // normally provided by test + + dumbParseNum := func(input string, v any) error { + return json.Unmarshal([]byte(input), v) + } + + for tt := range errorAssertionCases() { + var x float64 + tt.assertion(t, dumbParseNum(tt.arg, &x)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type errorAssertionCase struct { + name string + arg string + assertion assert.ErrorAssertionFunc +} + +func errorAssertionCases() iter.Seq[errorAssertionCase] { + return slices.Values([]errorAssertionCase{ + {"1.2 is number", "1.2", assert.NoError}, + {"1.2.3 not number", "1.2.3", assert.Error}, + {"true is not number", "true", assert.Error}, + {"3 is number", "3", assert.NoError}, + }) +} diff --git a/assert/assert_adhoc_example_5_test.go b/assert/assert_adhoc_example_5_test.go new file mode 100644 index 000000000..e93bd1a64 --- /dev/null +++ b/assert/assert_adhoc_example_5_test.go @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assert_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExamplePanicAssertionFunc() { + t := new(testing.T) // normally provided by test + + for tt := range panicAssertionCases() { + tt.assertion(t, tt.panicFn) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type panicAssertionCase struct { + name string + panicFn assert.PanicTestFunc + assertion assert.PanicAssertionFunc +} + +func panicAssertionCases() iter.Seq[panicAssertionCase] { + return slices.Values([]panicAssertionCase{ + {"with panic", func() { panic(nil) }, assert.Panics}, + {"without panic", func() {}, assert.NotPanics}, + }) +} diff --git a/assert/assert_assertions.go b/assert/assert_assertions.go new file mode 100644 index 000000000..b16424664 --- /dev/null +++ b/assert/assert_assertions.go @@ -0,0 +1,1482 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// Condition uses a Comparison to assert a complex condition. +// +// Examples: +// +// success: func() bool { return true } +// failure: func() bool { return false } +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Condition(t T, comp Comparison, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Condition(t, comp, msgAndArgs...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// Usage: +// +// assertions.Contains(t, "Hello World", "World") +// assertions.Contains(t, ["Hello", "World"], "World") +// assertions.Contains(t, {"Hello": "World"}, "Hello") +// +// Examples: +// +// success: []string{"A","B"}, "A" +// failure: []string{"A","B"}, "C" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Contains(t T, s any, contains any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Contains(t, s, contains, 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_dir") +// failure: filepath.Join(testDataPath(),"non_existing_dir") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func DirExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.DirExists(t, path, 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]). +// +// Examples: +// +// success: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +// failure: []int{1, 2, 3}, []int{1, 2, 4} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ElementsMatch(t T, listA any, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ElementsMatch(t, listA, listB, msgAndArgs...) +} + +// 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) +// +// Examples: +// +// success: "" +// failure: "not empty" +// +// Upon failure, the test [T] is marked as failed and continues execution. +// +// [Zero values]: https://go.dev/ref/spec#The_zero_value +func Empty(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Empty(t, object, 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. +// +// Examples: +// +// success: 123, 123 +// failure: 123, 456 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Equal(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Equal(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() +// assert.EqualError(t, err, expectedErrorString) +// +// Examples: +// +// success: ErrTest, "assert.ErrTest general error for testing" +// failure: ErrTest, "wrong error message" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualError(t T, theError error, errString string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualError(t, theError, errString, msgAndArgs...) +} + +// 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 +// +// Examples: +// +// success: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2} +// failure: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualExportedValues(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualExportedValues(t, expected, actual, msgAndArgs...) +} + +// EqualValues asserts that two objects are equal or convertible to the larger +// type and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +// +// Examples: +// +// success: uint32(123), int32(123) +// failure: uint32(123), int32(456) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualValues(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualValues(t, expected, actual, msgAndArgs...) +} + +// Error asserts that a function returned a non-nil error (ie. an error). +// +// actualObj, err := SomeFunction() +// assert.Error(t, err) +// +// Examples: +// +// success: ErrTest +// failure: nil +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Error(t T, err error, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Error(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. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +// failure: ErrTest, new(*dummyError) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorAs(t T, err error, target any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorAs(t, err, target, msgAndArgs...) +} + +// 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) +// +// Examples: +// +// success: ErrTest, "general error" +// failure: ErrTest, "not in message" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorContains(t T, theError error, contains string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorContains(t, theError, contains, msgAndArgs...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", io.EOF), io.EOF +// failure: ErrTest, io.EOF +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorIs(t T, err error, target error, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorIs(t, err, target, msgAndArgs...) +} + +// 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) +// +// Examples: +// +// success: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Eventually(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Eventually(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 +// }() +// 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") +// +// Examples: +// +// success: func(c *CollectT) { True(c,true) }, 100*time.Millisecond, 20*time.Millisecond +// failure: func(c *CollectT) { False(c,true) }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EventuallyWithT(t T, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +// +// Examples: +// +// success: int32(123), int32(123) +// failure: int32(123), int64(123) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Exactly(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Exactly(t, expected, actual, msgAndArgs...) +} + +// Fail reports a failure through. +// +// Example: +// +// failure: "failed" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Fail(t T, failureMessage string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Fail(t, failureMessage, msgAndArgs...) +} + +// FailNow fails test. +// +// Example: +// +// failure: "failed" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FailNow(t T, failureMessage string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FailNow(t, failureMessage, msgAndArgs...) +} + +// False asserts that the specified value is false. +// +// Usage: +// +// assertions.False(t, myBool) +// +// Examples: +// +// success: 1 == 0 +// failure: 1 == 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func False(t T, value bool, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.False(t, value, msgAndArgs...) +} + +// FileEmpty checks whether a file exists in the given path and is empty. +// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"empty_file") +// failure: filepath.Join(testDataPath(),"existing_file") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileEmpty(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileEmpty(t, path, msgAndArgs...) +} + +// 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"non_existing_file") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileExists(t, path, msgAndArgs...) +} + +// FileNotEmpty checks whether a file exists in the given path and is not empty. +// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"empty_file") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileNotEmpty(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileNotEmpty(t, path, msgAndArgs...) +} + +// Greater asserts that the first element is strictly greater than the second. +// +// Usage: +// +// assertions.Greater(t, 2, 1) +// assertions.Greater(t, float64(2), float64(1)) +// assertions.Greater(t, "b", "a") +// +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Greater(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Greater(t, e1, e2, 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") +// +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func GreaterOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.GreaterOrEqual(t, e1, e2, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPBodyContains(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPBodyNotContains(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpError, "GET", "/", nil +// failure: httpOK, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPError(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPError(t, handler, method, url, values, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpRedirect, "GET", "/", nil +// failure: httpError, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPRedirect(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpOK, "GET", "/", nil, http.StatusOK +// failure: httpError, "GET", "/", nil, http.StatusOK +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPStatusCode(t T, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: httpOK, "GET", "/", nil +// failure: httpError, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPSuccess(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// +// Examples: +// +// success: ptr(dummyInterface), new(testing.T) +// failure: (*error)(nil), new(testing.T) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Implements(t T, interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Implements(t, interfaceObject, object, msgAndArgs...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// +// Examples: +// +// success: 1.0, 1.01, 0.02 +// failure: 1.0, 1.1, 0.05 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDelta(t T, expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDelta(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. +// +// Examples: +// +// success: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02 +// failure: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDeltaMapValues(t T, expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +// +// Examples: +// +// success: []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02 +// failure: []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDeltaSlice(t T, expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon. +// +// Examples: +// +// success: 100.0, 101.0, 0.02 +// failure: 100.0, 110.0, 0.05 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InEpsilon(t T, expected any, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +// +// Examples: +// +// success: []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02 +// failure: []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InEpsilonSlice(t T, expected any, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InEpsilonSlice(t, expected, actual, epsilon, 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"}) +// +// Examples: +// +// success: []int{3, 2, 1} +// failure: []int{1, 2, 3} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsDecreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsDecreasing(t, object, msgAndArgs...) +} + +// 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"}) +// +// Examples: +// +// success: []int{1, 2, 3} +// failure: []int{1, 1, 2} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsIncreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsIncreasing(t, object, 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"}) +// +// Examples: +// +// success: []int{1, 1, 2} +// failure: []int{2, 1, 1} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNonDecreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNonDecreasing(t, object, 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"}) +// +// Examples: +// +// success: []int{2, 1, 1} +// failure: []int{1, 2, 3} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNonIncreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNonIncreasing(t, object, msgAndArgs...) +} + +// IsNotType asserts that the specified objects are not of the same type. +// +// assert.IsNotType(t, &NotMyStruct{}, &MyStruct{}) +// +// Examples: +// +// success: int32(123), int64(456) +// failure: 123, 456 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNotType(t T, theType any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNotType(t, theType, object, msgAndArgs...) +} + +// IsType asserts that the specified objects are of the same type. +// +// assert.IsType(t, &MyStruct{}, &MyStruct{}) +// +// Examples: +// +// success: 123, 456 +// failure: int32(123), int64(456) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsType(t T, expectedType any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsType(t, expectedType, object, msgAndArgs...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// +// Examples: +// +// success: `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}` +// failure: `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]` +// +// Upon failure, the test [T] is marked as failed and continues execution. +func JSONEq(t T, expected string, actual string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.JSONEq(t, expected, actual, msgAndArgs...) +} + +// JSONEqBytes asserts that two JSON byte slices are equivalent. +// +// assert.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) +// +// Examples: +// +// success: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`) +// failure: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func JSONEqBytes(t T, expected []byte, actual []byte, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.JSONEqBytes(t, expected, actual, msgAndArgs...) +} + +// Len asserts that the specified object has specific length. +// +// Len also fails if the object has a type that len() does not accept. +// +// The asserted object can be a string, a slice, a map, an array or a channel. +// +// See also [reflect.Len]. +// +// Usage: +// +// assertions.Len(t, mySlice, 3) +// assertions.Len(t, myString, 4) +// assertions.Len(t, myMap, 5) +// +// Examples: +// +// success: []string{"A","B"}, 2 +// failure: []string{"A","B"}, 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Len(t T, object any, length int, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Len(t, object, length, msgAndArgs...) +} + +// Less asserts that the first element is strictly less than the second. +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Less(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Less(t, e1, e2, 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") +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func LessOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.LessOrEqual(t, e1, e2, msgAndArgs...) +} + +// Negative asserts that the specified element is strictly negative. +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +// +// Examples: +// +// success: -1 +// failure: 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Negative(t T, e any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Negative(t, e, msgAndArgs...) +} + +// 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) +// +// Examples: +// +// success: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Never(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Never(t, condition, waitFor, tick, msgAndArgs...) +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +// +// Examples: +// +// success: nil +// failure: "not nil" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Nil(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Nil(t, object, msgAndArgs...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_dir") +// failure: filepath.Join(testDataPath(),"existing_dir") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoDirExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoDirExists(t, path, msgAndArgs...) +} + +// 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) +// } +// +// Examples: +// +// success: nil +// failure: ErrTest +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoError(t T, err error, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoError(t, err, msgAndArgs...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_file") +// failure: filepath.Join(testDataPath(),"existing_file") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoFileExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoFileExists(t, path, msgAndArgs...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// Usage: +// +// assertions.NotContains(t, "Hello World", "Earth") +// assertions.NotContains(t, ["Hello", "World"], "Earth") +// assertions.NotContains(t, {"Hello": "World"}, "Earth") +// +// Examples: +// +// success: []string{"A","B"}, "C" +// failure: []string{"A","B"}, "B" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotContains(t T, s any, contains any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotContains(t, s, contains, msgAndArgs...) +} + +// 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. +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2, 4} +// failure: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotElementsMatch(t T, listA any, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotElementsMatch(t, listA, listB, msgAndArgs...) +} + +// NotEmpty asserts that the specified object is NOT [Empty]. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +// +// Examples: +// +// success: "not empty" +// failure: "" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEmpty(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEmpty(t, object, msgAndArgs...) +} + +// 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). +// +// Examples: +// +// success: 123, 456 +// failure: 123, 123 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEqual(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEqual(t, expected, actual, msgAndArgs...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type. +// +// assert.NotEqualValues(t, obj1, obj2) +// +// Examples: +// +// success: uint32(123), int32(456) +// failure: uint32(123), int32(123) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEqualValues(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEqualValues(t, expected, actual, msgAndArgs...) +} + +// NotErrorAs asserts that none of the errors in err's chain matches target, +// but if so, sets target to that error value. +// +// Examples: +// +// success: ErrTest, new(*dummyError) +// failure: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotErrorAs(t T, err error, target any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotErrorAs(t, err, target, msgAndArgs...) +} + +// NotErrorIs asserts that none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +// +// Examples: +// +// success: ErrTest, io.EOF +// failure: fmt.Errorf("wrap: %w", io.EOF), io.EOF +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotErrorIs(t T, err error, target error, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotErrorIs(t, err, target, msgAndArgs...) +} + +// NotImplements asserts that an object does not implement the specified interface. +// +// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) +// +// Examples: +// +// success: (*error)(nil), new(testing.T) +// failure: ptr(dummyInterface), new(testing.T) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotImplements(t T, interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotImplements(t, interfaceObject, object, msgAndArgs...) +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +// +// Examples: +// +// success: "not nil" +// failure: nil +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotNil(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotNil(t, object, msgAndArgs...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +// +// Examples: +// +// success: func() { } +// failure: func() { panic("panicking") } +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotPanics(t T, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotPanics(t, f, msgAndArgs...) +} + +// 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") +// +// Examples: +// +// success: "^start", "not starting" +// failure: "^start", "starting" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotRegexp(t T, rx any, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotRegexp(t, rx, str, msgAndArgs...) +} + +// 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. +// +// Examples: +// +// success: &staticVar, ptr("static string") +// failure: &staticVar, staticVarPtr +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotSame(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotSame(t, expected, actual, msgAndArgs...) +} + +// 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{4, 5} +// failure: []int{1, 2, 3}, []int{1, 2} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotSubset(t T, list any, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotSubset(t, list, subset, msgAndArgs...) +} + +// NotZero asserts that i is not the zero value for its type. +// +// Examples: +// +// success: 1 +// failure: 0 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotZero(t T, i any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotZero(t, i, msgAndArgs...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +// +// Examples: +// +// success: func() { panic("panicking") } +// failure: func() { } +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Panics(t T, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Panics(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. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// +// Examples: +// +// success: ErrTest.Error(), func() { panic(ErrTest) } +// failure: ErrTest.Error(), func() { } +// +// Upon failure, the test [T] is marked as failed and continues execution. +func PanicsWithError(t T, errString string, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.PanicsWithError(t, errString, f, msgAndArgs...) +} + +// 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() }) +// +// Examples: +// +// success: "panicking", func() { panic("panicking") } +// failure: "panicking", func() { } +// +// Upon failure, the test [T] is marked as failed and continues execution. +func PanicsWithValue(t T, expected any, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.PanicsWithValue(t, expected, f, msgAndArgs...) +} + +// Positive asserts that the specified element is strictly positive. +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +// +// Examples: +// +// success: 1 +// failure: -1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Positive(t T, e any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Positive(t, e, msgAndArgs...) +} + +// 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") +// +// Examples: +// +// success: "^start", "starting" +// failure: "^start", "not starting" +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Regexp(t T, rx any, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Regexp(t, rx, str, msgAndArgs...) +} + +// 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. +// +// Examples: +// +// success: &staticVar, staticVarPtr +// failure: &staticVar, ptr("static string") +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Same(t T, expected any, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Same(t, expected, actual, msgAndArgs...) +} + +// 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2} +// failure: []int{1, 2, 3}, []int{4, 5} +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Subset(t T, list any, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Subset(t, list, subset, msgAndArgs...) +} + +// True asserts that the specified value is true. +// +// Usage: +// +// assertions.True(t, myBool) +// +// Examples: +// +// success: 1 == 1 +// failure: 1 == 0 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func True(t T, value bool, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.True(t, value, msgAndArgs...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), 10*time.Second) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second +// failure: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second +// +// Upon failure, the test [T] is marked as failed and continues execution. +func WithinDuration(t T, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.WithinDuration(t, expected, actual, delta, msgAndArgs...) +} + +// 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)) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +// failure: time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +// +// Upon failure, the test [T] is marked as failed and continues execution. +func WithinRange(t T, actual time.Time, start time.Time, end time.Time, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.WithinRange(t, actual, start, end, msgAndArgs...) +} + +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// Usage: +// +// 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 +// ` +// assertions.YAMLEq(t, expected, actual) +// +// Example: +// +// panic: "key: value", "key: value" +// should panic without the yaml feature enabled +// +// Upon failure, the test [T] is marked as failed and continues execution. +func YAMLEq(t T, expected string, actual string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.YAMLEq(t, expected, actual, msgAndArgs...) +} + +// Zero asserts that i is the zero value for its type. +// +// Examples: +// +// success: 0 +// failure: 1 +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Zero(t T, i any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Zero(t, i, msgAndArgs...) +} diff --git a/assert/assert_assertions_test.go b/assert/assert_assertions_test.go new file mode 100644 index 000000000..63ec808c8 --- /dev/null +++ b/assert/assert_assertions_test.go @@ -0,0 +1,1956 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestCondition(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Condition(t, func() bool { return true }) + if !result { + t.Error("Condition should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Condition(mock, func() bool { return false }) + if result { + t.Error("Condition should return false on failure") + } + if !mock.failed { + t.Error("Condition should mark test as failed") + } + }) +} + +func TestContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Contains(t, []string{"A", "B"}, "A") + if !result { + t.Error("Contains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Contains(mock, []string{"A", "B"}, "C") + if result { + t.Error("Contains should return false on failure") + } + if !mock.failed { + t.Error("Contains should mark test as failed") + } + }) +} + +func TestDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := DirExists(t, filepath.Join(testDataPath(), "existing_dir")) + if !result { + t.Error("DirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := DirExists(mock, filepath.Join(testDataPath(), "non_existing_dir")) + if result { + t.Error("DirExists should return false on failure") + } + if !mock.failed { + t.Error("DirExists should mark test as failed") + } + }) +} + +func TestElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ElementsMatch(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + if !result { + t.Error("ElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ElementsMatch(mock, []int{1, 2, 3}, []int{1, 2, 4}) + if result { + t.Error("ElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("ElementsMatch should mark test as failed") + } + }) +} + +func TestEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Empty(t, "") + if !result { + t.Error("Empty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Empty(mock, "not empty") + if result { + t.Error("Empty should return false on failure") + } + if !mock.failed { + t.Error("Empty should mark test as failed") + } + }) +} + +func TestEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Equal(t, 123, 123) + if !result { + t.Error("Equal should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Equal(mock, 123, 456) + if result { + t.Error("Equal should return false on failure") + } + if !mock.failed { + t.Error("Equal should mark test as failed") + } + }) +} + +func TestEqualError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualError(t, ErrTest, "assert.ErrTest general error for testing") + if !result { + t.Error("EqualError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualError(mock, ErrTest, "wrong error message") + if result { + t.Error("EqualError should return false on failure") + } + if !mock.failed { + t.Error("EqualError should mark test as failed") + } + }) +} + +func TestEqualExportedValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualExportedValues(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + if !result { + t.Error("EqualExportedValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualExportedValues(mock, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}) + if result { + t.Error("EqualExportedValues should return false on failure") + } + if !mock.failed { + t.Error("EqualExportedValues should mark test as failed") + } + }) +} + +func TestEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualValues(t, uint32(123), int32(123)) + if !result { + t.Error("EqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualValues(mock, uint32(123), int32(456)) + if result { + t.Error("EqualValues should return false on failure") + } + if !mock.failed { + t.Error("EqualValues should mark test as failed") + } + }) +} + +func TestError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Error(t, ErrTest) + if !result { + t.Error("Error should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Error(mock, nil) + if result { + t.Error("Error should return false on failure") + } + if !mock.failed { + t.Error("Error should mark test as failed") + } + }) +} + +func TestErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorAs(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + if !result { + t.Error("ErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorAs(mock, ErrTest, new(*dummyError)) + if result { + t.Error("ErrorAs should return false on failure") + } + if !mock.failed { + t.Error("ErrorAs should mark test as failed") + } + }) +} + +func TestErrorContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorContains(t, ErrTest, "general error") + if !result { + t.Error("ErrorContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorContains(mock, ErrTest, "not in message") + if result { + t.Error("ErrorContains should return false on failure") + } + if !mock.failed { + t.Error("ErrorContains should mark test as failed") + } + }) +} + +func TestErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorIs(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + if !result { + t.Error("ErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorIs(mock, ErrTest, io.EOF) + if result { + t.Error("ErrorIs should return false on failure") + } + if !mock.failed { + t.Error("ErrorIs should mark test as failed") + } + }) +} + +func TestEventually(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Eventually(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("Eventually should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Eventually(mock, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("Eventually should return false on failure") + } + if !mock.failed { + t.Error("Eventually should mark test as failed") + } + }) +} + +func TestEventuallyWithT(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EventuallyWithT(t, func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("EventuallyWithT should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EventuallyWithT(mock, func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("EventuallyWithT should return false on failure") + } + if !mock.failed { + t.Error("EventuallyWithT should mark test as failed") + } + }) +} + +func TestExactly(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Exactly(t, int32(123), int32(123)) + if !result { + t.Error("Exactly should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Exactly(mock, int32(123), int64(123)) + if result { + t.Error("Exactly should return false on failure") + } + if !mock.failed { + t.Error("Exactly should mark test as failed") + } + }) +} + +func TestFail(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Fail(mock, "failed") + if result { + t.Error("Fail should return false on failure") + } + if !mock.failed { + t.Error("Fail should mark test as failed") + } + }) +} + +func TestFailNow(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + result := FailNow(mock, "failed") + if result { + t.Error("FailNow should return false on failure") + } + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestFalse(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := False(t, 1 == 0) + if !result { + t.Error("False should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := False(mock, 1 == 1) + if result { + t.Error("False should return false on failure") + } + if !mock.failed { + t.Error("False should mark test as failed") + } + }) +} + +func TestFileEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileEmpty(t, filepath.Join(testDataPath(), "empty_file")) + if !result { + t.Error("FileEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileEmpty(mock, filepath.Join(testDataPath(), "existing_file")) + if result { + t.Error("FileEmpty should return false on failure") + } + if !mock.failed { + t.Error("FileEmpty should mark test as failed") + } + }) +} + +func TestFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileExists(t, filepath.Join(testDataPath(), "existing_file")) + if !result { + t.Error("FileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileExists(mock, filepath.Join(testDataPath(), "non_existing_file")) + if result { + t.Error("FileExists should return false on failure") + } + if !mock.failed { + t.Error("FileExists should mark test as failed") + } + }) +} + +func TestFileNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileNotEmpty(t, filepath.Join(testDataPath(), "existing_file")) + if !result { + t.Error("FileNotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileNotEmpty(mock, filepath.Join(testDataPath(), "empty_file")) + if result { + t.Error("FileNotEmpty should return false on failure") + } + if !mock.failed { + t.Error("FileNotEmpty should mark test as failed") + } + }) +} + +func TestGreater(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Greater(t, 2, 1) + if !result { + t.Error("Greater should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Greater(mock, 1, 2) + if result { + t.Error("Greater should return false on failure") + } + if !mock.failed { + t.Error("Greater should mark test as failed") + } + }) +} + +func TestGreaterOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := GreaterOrEqual(t, 2, 1) + if !result { + t.Error("GreaterOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := GreaterOrEqual(mock, 1, 2) + if result { + t.Error("GreaterOrEqual should return false on failure") + } + if !mock.failed { + t.Error("GreaterOrEqual should mark test as failed") + } + }) +} + +func TestHTTPBodyContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPBodyContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + if !result { + t.Error("HTTPBodyContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPBodyContains(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!") + if result { + t.Error("HTTPBodyContains should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyContains should mark test as failed") + } + }) +} + +func TestHTTPBodyNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPBodyNotContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + if !result { + t.Error("HTTPBodyNotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPBodyNotContains(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!") + if result { + t.Error("HTTPBodyNotContains should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyNotContains should mark test as failed") + } + }) +} + +func TestHTTPError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPError(t, httpError, "GET", "/", nil) + if !result { + t.Error("HTTPError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPError(mock, httpOK, "GET", "/", nil) + if result { + t.Error("HTTPError should return false on failure") + } + if !mock.failed { + t.Error("HTTPError should mark test as failed") + } + }) +} + +func TestHTTPRedirect(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPRedirect(t, httpRedirect, "GET", "/", nil) + if !result { + t.Error("HTTPRedirect should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPRedirect(mock, httpError, "GET", "/", nil) + if result { + t.Error("HTTPRedirect should return false on failure") + } + if !mock.failed { + t.Error("HTTPRedirect should mark test as failed") + } + }) +} + +func TestHTTPStatusCode(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPStatusCode(t, httpOK, "GET", "/", nil, http.StatusOK) + if !result { + t.Error("HTTPStatusCode should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPStatusCode(mock, httpError, "GET", "/", nil, http.StatusOK) + if result { + t.Error("HTTPStatusCode should return false on failure") + } + if !mock.failed { + t.Error("HTTPStatusCode should mark test as failed") + } + }) +} + +func TestHTTPSuccess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPSuccess(t, httpOK, "GET", "/", nil) + if !result { + t.Error("HTTPSuccess should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPSuccess(mock, httpError, "GET", "/", nil) + if result { + t.Error("HTTPSuccess should return false on failure") + } + if !mock.failed { + t.Error("HTTPSuccess should mark test as failed") + } + }) +} + +func TestImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Implements(t, ptr(dummyInterface), new(testing.T)) + if !result { + t.Error("Implements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Implements(mock, (*error)(nil), new(testing.T)) + if result { + t.Error("Implements should return false on failure") + } + if !mock.failed { + t.Error("Implements should mark test as failed") + } + }) +} + +func TestInDelta(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDelta(t, 1.0, 1.01, 0.02) + if !result { + t.Error("InDelta should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDelta(mock, 1.0, 1.1, 0.05) + if result { + t.Error("InDelta should return false on failure") + } + if !mock.failed { + t.Error("InDelta should mark test as failed") + } + }) +} + +func TestInDeltaMapValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDeltaMapValues(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + if !result { + t.Error("InDeltaMapValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDeltaMapValues(mock, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05) + if result { + t.Error("InDeltaMapValues should return false on failure") + } + if !mock.failed { + t.Error("InDeltaMapValues should mark test as failed") + } + }) +} + +func TestInDeltaSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDeltaSlice(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + if !result { + t.Error("InDeltaSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDeltaSlice(mock, []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05) + if result { + t.Error("InDeltaSlice should return false on failure") + } + if !mock.failed { + t.Error("InDeltaSlice should mark test as failed") + } + }) +} + +func TestInEpsilon(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InEpsilon(t, 100.0, 101.0, 0.02) + if !result { + t.Error("InEpsilon should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InEpsilon(mock, 100.0, 110.0, 0.05) + if result { + t.Error("InEpsilon should return false on failure") + } + if !mock.failed { + t.Error("InEpsilon should mark test as failed") + } + }) +} + +func TestInEpsilonSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InEpsilonSlice(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + if !result { + t.Error("InEpsilonSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InEpsilonSlice(mock, []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05) + if result { + t.Error("InEpsilonSlice should return false on failure") + } + if !mock.failed { + t.Error("InEpsilonSlice should mark test as failed") + } + }) +} + +func TestIsDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsDecreasing(t, []int{3, 2, 1}) + if !result { + t.Error("IsDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsDecreasing(mock, []int{1, 2, 3}) + if result { + t.Error("IsDecreasing should return false on failure") + } + if !mock.failed { + t.Error("IsDecreasing should mark test as failed") + } + }) +} + +func TestIsIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsIncreasing(t, []int{1, 2, 3}) + if !result { + t.Error("IsIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsIncreasing(mock, []int{1, 1, 2}) + if result { + t.Error("IsIncreasing should return false on failure") + } + if !mock.failed { + t.Error("IsIncreasing should mark test as failed") + } + }) +} + +func TestIsNonDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNonDecreasing(t, []int{1, 1, 2}) + if !result { + t.Error("IsNonDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNonDecreasing(mock, []int{2, 1, 1}) + if result { + t.Error("IsNonDecreasing should return false on failure") + } + if !mock.failed { + t.Error("IsNonDecreasing should mark test as failed") + } + }) +} + +func TestIsNonIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNonIncreasing(t, []int{2, 1, 1}) + if !result { + t.Error("IsNonIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNonIncreasing(mock, []int{1, 2, 3}) + if result { + t.Error("IsNonIncreasing should return false on failure") + } + if !mock.failed { + t.Error("IsNonIncreasing should mark test as failed") + } + }) +} + +func TestIsNotType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNotType(t, int32(123), int64(456)) + if !result { + t.Error("IsNotType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNotType(mock, 123, 456) + if result { + t.Error("IsNotType should return false on failure") + } + if !mock.failed { + t.Error("IsNotType should mark test as failed") + } + }) +} + +func TestIsType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsType(t, 123, 456) + if !result { + t.Error("IsType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsType(mock, int32(123), int64(456)) + if result { + t.Error("IsType should return false on failure") + } + if !mock.failed { + t.Error("IsType should mark test as failed") + } + }) +} + +func TestJSONEq(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if !result { + t.Error("JSONEq should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := JSONEq(mock, `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`) + if result { + t.Error("JSONEq should return false on failure") + } + if !mock.failed { + t.Error("JSONEq should mark test as failed") + } + }) +} + +func TestJSONEqBytes(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + if !result { + t.Error("JSONEqBytes should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := JSONEqBytes(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`)) + if result { + t.Error("JSONEqBytes should return false on failure") + } + if !mock.failed { + t.Error("JSONEqBytes should mark test as failed") + } + }) +} + +func TestLen(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Len(t, []string{"A", "B"}, 2) + if !result { + t.Error("Len should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Len(mock, []string{"A", "B"}, 1) + if result { + t.Error("Len should return false on failure") + } + if !mock.failed { + t.Error("Len should mark test as failed") + } + }) +} + +func TestLess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Less(t, 1, 2) + if !result { + t.Error("Less should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Less(mock, 2, 1) + if result { + t.Error("Less should return false on failure") + } + if !mock.failed { + t.Error("Less should mark test as failed") + } + }) +} + +func TestLessOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := LessOrEqual(t, 1, 2) + if !result { + t.Error("LessOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := LessOrEqual(mock, 2, 1) + if result { + t.Error("LessOrEqual should return false on failure") + } + if !mock.failed { + t.Error("LessOrEqual should mark test as failed") + } + }) +} + +func TestNegative(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Negative(t, -1) + if !result { + t.Error("Negative should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Negative(mock, 1) + if result { + t.Error("Negative should return false on failure") + } + if !mock.failed { + t.Error("Negative should mark test as failed") + } + }) +} + +func TestNever(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Never(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("Never should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Never(mock, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("Never should return false on failure") + } + if !mock.failed { + t.Error("Never should mark test as failed") + } + }) +} + +func TestNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Nil(t, nil) + if !result { + t.Error("Nil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Nil(mock, "not nil") + if result { + t.Error("Nil should return false on failure") + } + if !mock.failed { + t.Error("Nil should mark test as failed") + } + }) +} + +func TestNoDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoDirExists(t, filepath.Join(testDataPath(), "non_existing_dir")) + if !result { + t.Error("NoDirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoDirExists(mock, filepath.Join(testDataPath(), "existing_dir")) + if result { + t.Error("NoDirExists should return false on failure") + } + if !mock.failed { + t.Error("NoDirExists should mark test as failed") + } + }) +} + +func TestNoError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoError(t, nil) + if !result { + t.Error("NoError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoError(mock, ErrTest) + if result { + t.Error("NoError should return false on failure") + } + if !mock.failed { + t.Error("NoError should mark test as failed") + } + }) +} + +func TestNoFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoFileExists(t, filepath.Join(testDataPath(), "non_existing_file")) + if !result { + t.Error("NoFileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoFileExists(mock, filepath.Join(testDataPath(), "existing_file")) + if result { + t.Error("NoFileExists should return false on failure") + } + if !mock.failed { + t.Error("NoFileExists should mark test as failed") + } + }) +} + +func TestNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotContains(t, []string{"A", "B"}, "C") + if !result { + t.Error("NotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotContains(mock, []string{"A", "B"}, "B") + if result { + t.Error("NotContains should return false on failure") + } + if !mock.failed { + t.Error("NotContains should mark test as failed") + } + }) +} + +func TestNotElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotElementsMatch(t, []int{1, 2, 3}, []int{1, 2, 4}) + if !result { + t.Error("NotElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotElementsMatch(mock, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + if result { + t.Error("NotElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("NotElementsMatch should mark test as failed") + } + }) +} + +func TestNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEmpty(t, "not empty") + if !result { + t.Error("NotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEmpty(mock, "") + if result { + t.Error("NotEmpty should return false on failure") + } + if !mock.failed { + t.Error("NotEmpty should mark test as failed") + } + }) +} + +func TestNotEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEqual(t, 123, 456) + if !result { + t.Error("NotEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEqual(mock, 123, 123) + if result { + t.Error("NotEqual should return false on failure") + } + if !mock.failed { + t.Error("NotEqual should mark test as failed") + } + }) +} + +func TestNotEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEqualValues(t, uint32(123), int32(456)) + if !result { + t.Error("NotEqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEqualValues(mock, uint32(123), int32(123)) + if result { + t.Error("NotEqualValues should return false on failure") + } + if !mock.failed { + t.Error("NotEqualValues should mark test as failed") + } + }) +} + +func TestNotErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotErrorAs(t, ErrTest, new(*dummyError)) + if !result { + t.Error("NotErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotErrorAs(mock, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + if result { + t.Error("NotErrorAs should return false on failure") + } + if !mock.failed { + t.Error("NotErrorAs should mark test as failed") + } + }) +} + +func TestNotErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotErrorIs(t, ErrTest, io.EOF) + if !result { + t.Error("NotErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotErrorIs(mock, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + if result { + t.Error("NotErrorIs should return false on failure") + } + if !mock.failed { + t.Error("NotErrorIs should mark test as failed") + } + }) +} + +func TestNotImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotImplements(t, (*error)(nil), new(testing.T)) + if !result { + t.Error("NotImplements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotImplements(mock, ptr(dummyInterface), new(testing.T)) + if result { + t.Error("NotImplements should return false on failure") + } + if !mock.failed { + t.Error("NotImplements should mark test as failed") + } + }) +} + +func TestNotNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotNil(t, "not nil") + if !result { + t.Error("NotNil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotNil(mock, nil) + if result { + t.Error("NotNil should return false on failure") + } + if !mock.failed { + t.Error("NotNil should mark test as failed") + } + }) +} + +func TestNotPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotPanics(t, func() {}) + if !result { + t.Error("NotPanics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotPanics(mock, func() { panic("panicking") }) + if result { + t.Error("NotPanics should return false on failure") + } + if !mock.failed { + t.Error("NotPanics should mark test as failed") + } + }) +} + +func TestNotRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotRegexp(t, "^start", "not starting") + if !result { + t.Error("NotRegexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotRegexp(mock, "^start", "starting") + if result { + t.Error("NotRegexp should return false on failure") + } + if !mock.failed { + t.Error("NotRegexp should mark test as failed") + } + }) +} + +func TestNotSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotSame(t, &staticVar, ptr("static string")) + if !result { + t.Error("NotSame should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotSame(mock, &staticVar, staticVarPtr) + if result { + t.Error("NotSame should return false on failure") + } + if !mock.failed { + t.Error("NotSame should mark test as failed") + } + }) +} + +func TestNotSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotSubset(t, []int{1, 2, 3}, []int{4, 5}) + if !result { + t.Error("NotSubset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotSubset(mock, []int{1, 2, 3}, []int{1, 2}) + if result { + t.Error("NotSubset should return false on failure") + } + if !mock.failed { + t.Error("NotSubset should mark test as failed") + } + }) +} + +func TestNotZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotZero(t, 1) + if !result { + t.Error("NotZero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotZero(mock, 0) + if result { + t.Error("NotZero should return false on failure") + } + if !mock.failed { + t.Error("NotZero should mark test as failed") + } + }) +} + +func TestPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Panics(t, func() { panic("panicking") }) + if !result { + t.Error("Panics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Panics(mock, func() {}) + if result { + t.Error("Panics should return false on failure") + } + if !mock.failed { + t.Error("Panics should mark test as failed") + } + }) +} + +func TestPanicsWithError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := PanicsWithError(t, ErrTest.Error(), func() { panic(ErrTest) }) + if !result { + t.Error("PanicsWithError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := PanicsWithError(mock, ErrTest.Error(), func() {}) + if result { + t.Error("PanicsWithError should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithError should mark test as failed") + } + }) +} + +func TestPanicsWithValue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := PanicsWithValue(t, "panicking", func() { panic("panicking") }) + if !result { + t.Error("PanicsWithValue should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := PanicsWithValue(mock, "panicking", func() {}) + if result { + t.Error("PanicsWithValue should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithValue should mark test as failed") + } + }) +} + +func TestPositive(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Positive(t, 1) + if !result { + t.Error("Positive should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Positive(mock, -1) + if result { + t.Error("Positive should return false on failure") + } + if !mock.failed { + t.Error("Positive should mark test as failed") + } + }) +} + +func TestRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Regexp(t, "^start", "starting") + if !result { + t.Error("Regexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Regexp(mock, "^start", "not starting") + if result { + t.Error("Regexp should return false on failure") + } + if !mock.failed { + t.Error("Regexp should mark test as failed") + } + }) +} + +func TestSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Same(t, &staticVar, staticVarPtr) + if !result { + t.Error("Same should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Same(mock, &staticVar, ptr("static string")) + if result { + t.Error("Same should return false on failure") + } + if !mock.failed { + t.Error("Same should mark test as failed") + } + }) +} + +func TestSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Subset(t, []int{1, 2, 3}, []int{1, 2}) + if !result { + t.Error("Subset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Subset(mock, []int{1, 2, 3}, []int{4, 5}) + if result { + t.Error("Subset should return false on failure") + } + if !mock.failed { + t.Error("Subset should mark test as failed") + } + }) +} + +func TestTrue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := True(t, 1 == 1) + if !result { + t.Error("True should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := True(mock, 1 == 0) + if result { + t.Error("True should return false on failure") + } + if !mock.failed { + t.Error("True should mark test as failed") + } + }) +} + +func TestWithinDuration(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := WithinDuration(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + if !result { + t.Error("WithinDuration should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := WithinDuration(mock, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second) + if result { + t.Error("WithinDuration should return false on failure") + } + if !mock.failed { + t.Error("WithinDuration should mark test as failed") + } + }) +} + +func TestWithinRange(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := WithinRange(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + if !result { + t.Error("WithinRange should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := WithinRange(mock, time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + if result { + t.Error("WithinRange should return false on failure") + } + if !mock.failed { + t.Error("WithinRange should mark test as failed") + } + }) +} + +func TestYAMLEq(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panics(t, func() { + YAMLEq(t, "key: value", "key: value") + }, "should panic without the yaml feature enabled") + }) +} + +func TestZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Zero(t, 0) + if !result { + t.Error("Zero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Zero(mock, 1) + if result { + t.Error("Zero should return false on failure") + } + if !mock.failed { + t.Error("Zero should mark test as failed") + } + }) +} + +// mockT is a mock testing.T for assertion tests +type mockT struct { + failed bool +} + +func (m *mockT) Helper() {} + +func (m *mockT) Errorf(format string, args ...any) { + m.failed = true +} + +type mockFailNowT struct { + failed bool +} + +// Helper is like [testing.T.Helper] but does nothing. +func (mockFailNowT) Helper() {} + +func (m *mockFailNowT) Errorf(format string, args ...any) { + _ = format + _ = args +} + +func (m *mockFailNowT) FailNow() { + m.failed = true +} + +func testDataPath() string { + return filepath.Join("..", "internal", "assertions", "testdata") +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/assert/assert_examples_test.go b/assert/assert_examples_test.go new file mode 100644 index 000000000..4cda71b3e --- /dev/null +++ b/assert/assert_examples_test.go @@ -0,0 +1,688 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert_test + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" + + "github.com/go-openapi/testify/v2/assert" +) + +func ExampleCondition() { + t := new(testing.T) + success := assert.Condition(t, func() bool { return true }) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleContains() { + t := new(testing.T) + success := assert.Contains(t, []string{"A", "B"}, "A") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleDirExists() { + t := new(testing.T) + success := assert.DirExists(t, filepath.Join(testDataPath(), "existing_dir")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleElementsMatch() { + t := new(testing.T) + success := assert.ElementsMatch(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEmpty() { + t := new(testing.T) + success := assert.Empty(t, "") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEqual() { + t := new(testing.T) + success := assert.Equal(t, 123, 123) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEqualError() { + t := new(testing.T) + success := assert.EqualError(t, assert.ErrTest, "assert.ErrTest general error for testing") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEqualExportedValues() { + t := new(testing.T) + success := assert.EqualExportedValues(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEqualValues() { + t := new(testing.T) + success := assert.EqualValues(t, uint32(123), int32(123)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleError() { + t := new(testing.T) + success := assert.Error(t, assert.ErrTest) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleErrorAs() { + t := new(testing.T) + success := assert.ErrorAs(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleErrorContains() { + t := new(testing.T) + success := assert.ErrorContains(t, assert.ErrTest, "general error") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleErrorIs() { + t := new(testing.T) + success := assert.ErrorIs(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEventually() { + t := new(testing.T) + success := assert.Eventually(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleEventuallyWithT() { + t := new(testing.T) + success := assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleExactly() { + t := new(testing.T) + success := assert.Exactly(t, int32(123), int32(123)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +// func ExampleFail() { +// no success example available. Please add some examples to produce a testable example. +// } + +// func ExampleFailNow() { +// no success example available. Please add some examples to produce a testable example. +// } + +func ExampleFalse() { + t := new(testing.T) + success := assert.False(t, 1 == 0) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleFileEmpty() { + t := new(testing.T) + success := assert.FileEmpty(t, filepath.Join(testDataPath(), "empty_file")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleFileExists() { + t := new(testing.T) + success := assert.FileExists(t, filepath.Join(testDataPath(), "existing_file")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleFileNotEmpty() { + t := new(testing.T) + success := assert.FileNotEmpty(t, filepath.Join(testDataPath(), "existing_file")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleGreater() { + t := new(testing.T) + success := assert.Greater(t, 2, 1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleGreaterOrEqual() { + t := new(testing.T) + success := assert.GreaterOrEqual(t, 2, 1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPBodyContains() { + t := new(testing.T) + success := assert.HTTPBodyContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPBodyNotContains() { + t := new(testing.T) + success := assert.HTTPBodyNotContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPError() { + t := new(testing.T) + success := assert.HTTPError(t, httpError, "GET", "/", nil) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPRedirect() { + t := new(testing.T) + success := assert.HTTPRedirect(t, httpRedirect, "GET", "/", nil) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPStatusCode() { + t := new(testing.T) + success := assert.HTTPStatusCode(t, httpOK, "GET", "/", nil, http.StatusOK) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleHTTPSuccess() { + t := new(testing.T) + success := assert.HTTPSuccess(t, httpOK, "GET", "/", nil) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleImplements() { + t := new(testing.T) + success := assert.Implements(t, ptr(dummyInterface), new(testing.T)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleInDelta() { + t := new(testing.T) + success := assert.InDelta(t, 1.0, 1.01, 0.02) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleInDeltaMapValues() { + t := new(testing.T) + success := assert.InDeltaMapValues(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleInDeltaSlice() { + t := new(testing.T) + success := assert.InDeltaSlice(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleInEpsilon() { + t := new(testing.T) + success := assert.InEpsilon(t, 100.0, 101.0, 0.02) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleInEpsilonSlice() { + t := new(testing.T) + success := assert.InEpsilonSlice(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsDecreasing() { + t := new(testing.T) + success := assert.IsDecreasing(t, []int{3, 2, 1}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsIncreasing() { + t := new(testing.T) + success := assert.IsIncreasing(t, []int{1, 2, 3}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsNonDecreasing() { + t := new(testing.T) + success := assert.IsNonDecreasing(t, []int{1, 1, 2}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsNonIncreasing() { + t := new(testing.T) + success := assert.IsNonIncreasing(t, []int{2, 1, 1}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsNotType() { + t := new(testing.T) + success := assert.IsNotType(t, int32(123), int64(456)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleIsType() { + t := new(testing.T) + success := assert.IsType(t, 123, 456) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleJSONEq() { + t := new(testing.T) + success := assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleJSONEqBytes() { + t := new(testing.T) + success := assert.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleLen() { + t := new(testing.T) + success := assert.Len(t, []string{"A", "B"}, 2) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleLess() { + t := new(testing.T) + success := assert.Less(t, 1, 2) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleLessOrEqual() { + t := new(testing.T) + success := assert.LessOrEqual(t, 1, 2) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNegative() { + t := new(testing.T) + success := assert.Negative(t, -1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNever() { + t := new(testing.T) + success := assert.Never(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNil() { + t := new(testing.T) + success := assert.Nil(t, nil) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNoDirExists() { + t := new(testing.T) + success := assert.NoDirExists(t, filepath.Join(testDataPath(), "non_existing_dir")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNoError() { + t := new(testing.T) + success := assert.NoError(t, nil) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNoFileExists() { + t := new(testing.T) + success := assert.NoFileExists(t, filepath.Join(testDataPath(), "non_existing_file")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotContains() { + t := new(testing.T) + success := assert.NotContains(t, []string{"A", "B"}, "C") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotElementsMatch() { + t := new(testing.T) + success := assert.NotElementsMatch(t, []int{1, 2, 3}, []int{1, 2, 4}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotEmpty() { + t := new(testing.T) + success := assert.NotEmpty(t, "not empty") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotEqual() { + t := new(testing.T) + success := assert.NotEqual(t, 123, 456) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotEqualValues() { + t := new(testing.T) + success := assert.NotEqualValues(t, uint32(123), int32(456)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotErrorAs() { + t := new(testing.T) + success := assert.NotErrorAs(t, assert.ErrTest, new(*dummyError)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotErrorIs() { + t := new(testing.T) + success := assert.NotErrorIs(t, assert.ErrTest, io.EOF) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotImplements() { + t := new(testing.T) + success := assert.NotImplements(t, (*error)(nil), new(testing.T)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotNil() { + t := new(testing.T) + success := assert.NotNil(t, "not nil") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotPanics() { + t := new(testing.T) + success := assert.NotPanics(t, func() {}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotRegexp() { + t := new(testing.T) + success := assert.NotRegexp(t, "^start", "not starting") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotSame() { + t := new(testing.T) + success := assert.NotSame(t, &staticVar, ptr("static string")) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotSubset() { + t := new(testing.T) + success := assert.NotSubset(t, []int{1, 2, 3}, []int{4, 5}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleNotZero() { + t := new(testing.T) + success := assert.NotZero(t, 1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExamplePanics() { + t := new(testing.T) + success := assert.Panics(t, func() { panic("panicking") }) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExamplePanicsWithError() { + t := new(testing.T) + success := assert.PanicsWithError(t, assert.ErrTest.Error(), func() { panic(assert.ErrTest) }) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExamplePanicsWithValue() { + t := new(testing.T) + success := assert.PanicsWithValue(t, "panicking", func() { panic("panicking") }) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExamplePositive() { + t := new(testing.T) + success := assert.Positive(t, 1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleRegexp() { + t := new(testing.T) + success := assert.Regexp(t, "^start", "starting") + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleSame() { + t := new(testing.T) + success := assert.Same(t, &staticVar, staticVarPtr) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleSubset() { + t := new(testing.T) + success := assert.Subset(t, []int{1, 2, 3}, []int{1, 2}) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleTrue() { + t := new(testing.T) + success := assert.True(t, 1 == 1) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleWithinDuration() { + t := new(testing.T) + success := assert.WithinDuration(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +func ExampleWithinRange() { + t := new(testing.T) + success := assert.WithinRange(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +// func ExampleYAMLEq() { +// no success example available. Please add some examples to produce a testable example. +// } + +func ExampleZero() { + t := new(testing.T) + success := assert.Zero(t, 0) + fmt.Printf("success: %t\n", success) + + // Output: success: true +} + +// Test helpers (also in the tests for package assert +// +// This code is duplicated because the current test is run as a separate test package: assert_test + +func testDataPath() string { + return filepath.Join("..", "internal", "assertions", "testdata") +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface assert.T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/assert/assert_format.go b/assert/assert_format.go new file mode 100644 index 000000000..597352781 --- /dev/null +++ b/assert/assert_format.go @@ -0,0 +1,812 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// Conditionf is the same as [Condition], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Conditionf(t T, comp Comparison, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Condition(t, comp, forwardArgs(msg, args)) +} + +// Containsf is the same as [Contains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Containsf(t T, s any, contains any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Contains(t, s, contains, forwardArgs(msg, args)) +} + +// DirExistsf is the same as [DirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func DirExistsf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.DirExists(t, path, forwardArgs(msg, args)) +} + +// ElementsMatchf is the same as [ElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ElementsMatchf(t T, listA any, listB any, msg string, args ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ElementsMatch(t, listA, listB, forwardArgs(msg, args)) +} + +// Emptyf is the same as [Empty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Emptyf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Empty(t, object, forwardArgs(msg, args)) +} + +// Equalf is the same as [Equal], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Equalf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Equal(t, expected, actual, forwardArgs(msg, args)) +} + +// EqualErrorf is the same as [EqualError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualErrorf(t T, theError error, errString string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualError(t, theError, errString, forwardArgs(msg, args)) +} + +// EqualExportedValuesf is the same as [EqualExportedValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualExportedValuesf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualExportedValues(t, expected, actual, forwardArgs(msg, args)) +} + +// EqualValuesf is the same as [EqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EqualValuesf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EqualValues(t, expected, actual, forwardArgs(msg, args)) +} + +// Errorf is the same as [Error], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Errorf(t T, err error, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Error(t, err, forwardArgs(msg, args)) +} + +// ErrorAsf is the same as [ErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorAsf(t T, err error, target any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorAs(t, err, target, forwardArgs(msg, args)) +} + +// ErrorContainsf is the same as [ErrorContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorContainsf(t T, theError error, contains string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorContains(t, theError, contains, forwardArgs(msg, args)) +} + +// ErrorIsf is the same as [ErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func ErrorIsf(t T, err error, target error, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.ErrorIs(t, err, target, forwardArgs(msg, args)) +} + +// Eventuallyf is the same as [Eventually], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Eventuallyf(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Eventually(t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// EventuallyWithTf is the same as [EventuallyWithT], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func EventuallyWithTf(t T, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.EventuallyWithT(t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// Exactlyf is the same as [Exactly], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Exactlyf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Exactly(t, expected, actual, forwardArgs(msg, args)) +} + +// Failf is the same as [Fail], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Failf(t T, failureMessage string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Fail(t, failureMessage, forwardArgs(msg, args)) +} + +// FailNowf is the same as [FailNow], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FailNowf(t T, failureMessage string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FailNow(t, failureMessage, forwardArgs(msg, args)) +} + +// Falsef is the same as [False], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Falsef(t T, value bool, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.False(t, value, forwardArgs(msg, args)) +} + +// FileEmptyf is the same as [FileEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileEmptyf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileEmpty(t, path, forwardArgs(msg, args)) +} + +// FileExistsf is the same as [FileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileExistsf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileExists(t, path, forwardArgs(msg, args)) +} + +// FileNotEmptyf is the same as [FileNotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func FileNotEmptyf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.FileNotEmpty(t, path, forwardArgs(msg, args)) +} + +// Greaterf is the same as [Greater], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Greaterf(t T, e1 any, e2 any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Greater(t, e1, e2, forwardArgs(msg, args)) +} + +// GreaterOrEqualf is the same as [GreaterOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func GreaterOrEqualf(t T, e1 any, e2 any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.GreaterOrEqual(t, e1, e2, forwardArgs(msg, args)) +} + +// HTTPBodyContainsf is the same as [HTTPBodyContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPBodyContainsf(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyContains(t, handler, method, url, values, str, forwardArgs(msg, args)) +} + +// HTTPBodyNotContainsf is the same as [HTTPBodyNotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPBodyNotContainsf(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyNotContains(t, handler, method, url, values, str, forwardArgs(msg, args)) +} + +// HTTPErrorf is the same as [HTTPError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPErrorf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPError(t, handler, method, url, values, forwardArgs(msg, args)) +} + +// HTTPRedirectf is the same as [HTTPRedirect], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPRedirectf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPRedirect(t, handler, method, url, values, forwardArgs(msg, args)) +} + +// HTTPStatusCodef is the same as [HTTPStatusCode], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPStatusCodef(t T, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPStatusCode(t, handler, method, url, values, statuscode, forwardArgs(msg, args)) +} + +// HTTPSuccessf is the same as [HTTPSuccess], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func HTTPSuccessf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.HTTPSuccess(t, handler, method, url, values, forwardArgs(msg, args)) +} + +// Implementsf is the same as [Implements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Implementsf(t T, interfaceObject any, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Implements(t, interfaceObject, object, forwardArgs(msg, args)) +} + +// InDeltaf is the same as [InDelta], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDeltaf(t T, expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDelta(t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InDeltaMapValuesf is the same as [InDeltaMapValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDeltaMapValuesf(t T, expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDeltaMapValues(t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InDeltaSlicef is the same as [InDeltaSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InDeltaSlicef(t T, expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InDeltaSlice(t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InEpsilonf is the same as [InEpsilon], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InEpsilonf(t T, expected any, actual any, epsilon float64, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InEpsilon(t, expected, actual, epsilon, forwardArgs(msg, args)) +} + +// InEpsilonSlicef is the same as [InEpsilonSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func InEpsilonSlicef(t T, expected any, actual any, epsilon float64, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.InEpsilonSlice(t, expected, actual, epsilon, forwardArgs(msg, args)) +} + +// IsDecreasingf is the same as [IsDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsDecreasingf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsDecreasing(t, object, forwardArgs(msg, args)) +} + +// IsIncreasingf is the same as [IsIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsIncreasingf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsIncreasing(t, object, forwardArgs(msg, args)) +} + +// IsNonDecreasingf is the same as [IsNonDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNonDecreasingf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNonDecreasing(t, object, forwardArgs(msg, args)) +} + +// IsNonIncreasingf is the same as [IsNonIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNonIncreasingf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNonIncreasing(t, object, forwardArgs(msg, args)) +} + +// IsNotTypef is the same as [IsNotType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsNotTypef(t T, theType any, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsNotType(t, theType, object, forwardArgs(msg, args)) +} + +// IsTypef is the same as [IsType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func IsTypef(t T, expectedType any, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.IsType(t, expectedType, object, forwardArgs(msg, args)) +} + +// JSONEqf is the same as [JSONEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func JSONEqf(t T, expected string, actual string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.JSONEq(t, expected, actual, forwardArgs(msg, args)) +} + +// JSONEqBytesf is the same as [JSONEqBytes], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func JSONEqBytesf(t T, expected []byte, actual []byte, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.JSONEqBytes(t, expected, actual, forwardArgs(msg, args)) +} + +// Lenf is the same as [Len], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Lenf(t T, object any, length int, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Len(t, object, length, forwardArgs(msg, args)) +} + +// Lessf is the same as [Less], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Lessf(t T, e1 any, e2 any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Less(t, e1, e2, forwardArgs(msg, args)) +} + +// LessOrEqualf is the same as [LessOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func LessOrEqualf(t T, e1 any, e2 any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.LessOrEqual(t, e1, e2, forwardArgs(msg, args)) +} + +// Negativef is the same as [Negative], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Negativef(t T, e any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Negative(t, e, forwardArgs(msg, args)) +} + +// Neverf is the same as [Never], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Neverf(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Never(t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// Nilf is the same as [Nil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Nilf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Nil(t, object, forwardArgs(msg, args)) +} + +// NoDirExistsf is the same as [NoDirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoDirExistsf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoDirExists(t, path, forwardArgs(msg, args)) +} + +// NoErrorf is the same as [NoError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoErrorf(t T, err error, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoError(t, err, forwardArgs(msg, args)) +} + +// NoFileExistsf is the same as [NoFileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NoFileExistsf(t T, path string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NoFileExists(t, path, forwardArgs(msg, args)) +} + +// NotContainsf is the same as [NotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotContainsf(t T, s any, contains any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotContains(t, s, contains, forwardArgs(msg, args)) +} + +// NotElementsMatchf is the same as [NotElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotElementsMatchf(t T, listA any, listB any, msg string, args ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotElementsMatch(t, listA, listB, forwardArgs(msg, args)) +} + +// NotEmptyf is the same as [NotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEmptyf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEmpty(t, object, forwardArgs(msg, args)) +} + +// NotEqualf is the same as [NotEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEqualf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEqual(t, expected, actual, forwardArgs(msg, args)) +} + +// NotEqualValuesf is the same as [NotEqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotEqualValuesf(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotEqualValues(t, expected, actual, forwardArgs(msg, args)) +} + +// NotErrorAsf is the same as [NotErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotErrorAsf(t T, err error, target any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotErrorAs(t, err, target, forwardArgs(msg, args)) +} + +// NotErrorIsf is the same as [NotErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotErrorIsf(t T, err error, target error, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotErrorIs(t, err, target, forwardArgs(msg, args)) +} + +// NotImplementsf is the same as [NotImplements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotImplementsf(t T, interfaceObject any, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotImplements(t, interfaceObject, object, forwardArgs(msg, args)) +} + +// NotNilf is the same as [NotNil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotNilf(t T, object any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotNil(t, object, forwardArgs(msg, args)) +} + +// NotPanicsf is the same as [NotPanics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotPanicsf(t T, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotPanics(t, f, forwardArgs(msg, args)) +} + +// NotRegexpf is the same as [NotRegexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotRegexpf(t T, rx any, str any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotRegexp(t, rx, str, forwardArgs(msg, args)) +} + +// NotSamef is the same as [NotSame], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotSamef(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotSame(t, expected, actual, forwardArgs(msg, args)) +} + +// NotSubsetf is the same as [NotSubset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotSubsetf(t T, list any, subset any, msg string, args ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotSubset(t, list, subset, forwardArgs(msg, args)) +} + +// NotZerof is the same as [NotZero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func NotZerof(t T, i any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.NotZero(t, i, forwardArgs(msg, args)) +} + +// Panicsf is the same as [Panics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Panicsf(t T, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Panics(t, f, forwardArgs(msg, args)) +} + +// PanicsWithErrorf is the same as [PanicsWithError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func PanicsWithErrorf(t T, errString string, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.PanicsWithError(t, errString, f, forwardArgs(msg, args)) +} + +// PanicsWithValuef is the same as [PanicsWithValue], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func PanicsWithValuef(t T, expected any, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.PanicsWithValue(t, expected, f, forwardArgs(msg, args)) +} + +// Positivef is the same as [Positive], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Positivef(t T, e any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Positive(t, e, forwardArgs(msg, args)) +} + +// Regexpf is the same as [Regexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Regexpf(t T, rx any, str any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Regexp(t, rx, str, forwardArgs(msg, args)) +} + +// Samef is the same as [Same], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Samef(t T, expected any, actual any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Same(t, expected, actual, forwardArgs(msg, args)) +} + +// Subsetf is the same as [Subset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Subsetf(t T, list any, subset any, msg string, args ...any) (ok bool) { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Subset(t, list, subset, forwardArgs(msg, args)) +} + +// Truef is the same as [True], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Truef(t T, value bool, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.True(t, value, forwardArgs(msg, args)) +} + +// WithinDurationf is the same as [WithinDuration], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func WithinDurationf(t T, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.WithinDuration(t, expected, actual, delta, forwardArgs(msg, args)) +} + +// WithinRangef is the same as [WithinRange], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func WithinRangef(t T, actual time.Time, start time.Time, end time.Time, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.WithinRange(t, actual, start, end, forwardArgs(msg, args)) +} + +// YAMLEqf is the same as [YAMLEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func YAMLEqf(t T, expected string, actual string, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.YAMLEq(t, expected, actual, forwardArgs(msg, args)) +} + +// Zerof is the same as [Zero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func Zerof(t T, i any, msg string, args ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + return assertions.Zero(t, i, forwardArgs(msg, args)) +} + +func forwardArgs(msg string, args []any) []any { + result := make([]any, len(args)+1) + result[0] = msg + copy(result[1:], args) + + return result +} diff --git a/assert/assert_format_test.go b/assert/assert_format_test.go new file mode 100644 index 000000000..8f35675d0 --- /dev/null +++ b/assert/assert_format_test.go @@ -0,0 +1,1883 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestConditionf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Conditionf(t, func() bool { return true }, "test message") + if !result { + t.Error("Conditionf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Conditionf(mock, func() bool { return false }, "test message") + if result { + t.Error("Conditionf should return false on failure") + } + if !mock.failed { + t.Error("Condition should mark test as failed") + } + }) +} + +func TestContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Containsf(t, []string{"A", "B"}, "A", "test message") + if !result { + t.Error("Containsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Containsf(mock, []string{"A", "B"}, "C", "test message") + if result { + t.Error("Containsf should return false on failure") + } + if !mock.failed { + t.Error("Contains should mark test as failed") + } + }) +} + +func TestDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := DirExistsf(t, filepath.Join(testDataPath(), "existing_dir"), "test message") + if !result { + t.Error("DirExistsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := DirExistsf(mock, filepath.Join(testDataPath(), "non_existing_dir"), "test message") + if result { + t.Error("DirExistsf should return false on failure") + } + if !mock.failed { + t.Error("DirExists should mark test as failed") + } + }) +} + +func TestElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ElementsMatchf(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + if !result { + t.Error("ElementsMatchf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ElementsMatchf(mock, []int{1, 2, 3}, []int{1, 2, 4}, "test message") + if result { + t.Error("ElementsMatchf should return false on failure") + } + if !mock.failed { + t.Error("ElementsMatch should mark test as failed") + } + }) +} + +func TestEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Emptyf(t, "", "test message") + if !result { + t.Error("Emptyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Emptyf(mock, "not empty", "test message") + if result { + t.Error("Emptyf should return false on failure") + } + if !mock.failed { + t.Error("Empty should mark test as failed") + } + }) +} + +func TestEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Equalf(t, 123, 123, "test message") + if !result { + t.Error("Equalf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Equalf(mock, 123, 456, "test message") + if result { + t.Error("Equalf should return false on failure") + } + if !mock.failed { + t.Error("Equal should mark test as failed") + } + }) +} + +func TestEqualErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualErrorf(t, ErrTest, "assert.ErrTest general error for testing", "test message") + if !result { + t.Error("EqualErrorf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualErrorf(mock, ErrTest, "wrong error message", "test message") + if result { + t.Error("EqualErrorf should return false on failure") + } + if !mock.failed { + t.Error("EqualError should mark test as failed") + } + }) +} + +func TestEqualExportedValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualExportedValuesf(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}, "test message") + if !result { + t.Error("EqualExportedValuesf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualExportedValuesf(mock, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}, "test message") + if result { + t.Error("EqualExportedValuesf should return false on failure") + } + if !mock.failed { + t.Error("EqualExportedValues should mark test as failed") + } + }) +} + +func TestEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EqualValuesf(t, uint32(123), int32(123), "test message") + if !result { + t.Error("EqualValuesf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EqualValuesf(mock, uint32(123), int32(456), "test message") + if result { + t.Error("EqualValuesf should return false on failure") + } + if !mock.failed { + t.Error("EqualValues should mark test as failed") + } + }) +} + +func TestErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Errorf(t, ErrTest, "test message") + if !result { + t.Error("Errorf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Errorf(mock, nil, "test message") + if result { + t.Error("Errorf should return false on failure") + } + if !mock.failed { + t.Error("Error should mark test as failed") + } + }) +} + +func TestErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorAsf(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + if !result { + t.Error("ErrorAsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorAsf(mock, ErrTest, new(*dummyError), "test message") + if result { + t.Error("ErrorAsf should return false on failure") + } + if !mock.failed { + t.Error("ErrorAs should mark test as failed") + } + }) +} + +func TestErrorContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorContainsf(t, ErrTest, "general error", "test message") + if !result { + t.Error("ErrorContainsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorContainsf(mock, ErrTest, "not in message", "test message") + if result { + t.Error("ErrorContainsf should return false on failure") + } + if !mock.failed { + t.Error("ErrorContains should mark test as failed") + } + }) +} + +func TestErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := ErrorIsf(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + if !result { + t.Error("ErrorIsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := ErrorIsf(mock, ErrTest, io.EOF, "test message") + if result { + t.Error("ErrorIsf should return false on failure") + } + if !mock.failed { + t.Error("ErrorIs should mark test as failed") + } + }) +} + +func TestEventuallyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Eventuallyf(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("Eventuallyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Eventuallyf(mock, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("Eventuallyf should return false on failure") + } + if !mock.failed { + t.Error("Eventually should mark test as failed") + } + }) +} + +func TestEventuallyWithTf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := EventuallyWithTf(t, func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("EventuallyWithTf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := EventuallyWithTf(mock, func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("EventuallyWithTf should return false on failure") + } + if !mock.failed { + t.Error("EventuallyWithT should mark test as failed") + } + }) +} + +func TestExactlyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Exactlyf(t, int32(123), int32(123), "test message") + if !result { + t.Error("Exactlyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Exactlyf(mock, int32(123), int64(123), "test message") + if result { + t.Error("Exactlyf should return false on failure") + } + if !mock.failed { + t.Error("Exactly should mark test as failed") + } + }) +} + +func TestFailf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Failf(mock, "failed", "test message") + if result { + t.Error("Failf should return false on failure") + } + if !mock.failed { + t.Error("Fail should mark test as failed") + } + }) +} + +func TestFailNowf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + result := FailNowf(mock, "failed", "test message") + if result { + t.Error("FailNowf should return false on failure") + } + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestFalsef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Falsef(t, 1 == 0, "test message") + if !result { + t.Error("Falsef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Falsef(mock, 1 == 1, "test message") + if result { + t.Error("Falsef should return false on failure") + } + if !mock.failed { + t.Error("False should mark test as failed") + } + }) +} + +func TestFileEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileEmptyf(t, filepath.Join(testDataPath(), "empty_file"), "test message") + if !result { + t.Error("FileEmptyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileEmptyf(mock, filepath.Join(testDataPath(), "existing_file"), "test message") + if result { + t.Error("FileEmptyf should return false on failure") + } + if !mock.failed { + t.Error("FileEmpty should mark test as failed") + } + }) +} + +func TestFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileExistsf(t, filepath.Join(testDataPath(), "existing_file"), "test message") + if !result { + t.Error("FileExistsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileExistsf(mock, filepath.Join(testDataPath(), "non_existing_file"), "test message") + if result { + t.Error("FileExistsf should return false on failure") + } + if !mock.failed { + t.Error("FileExists should mark test as failed") + } + }) +} + +func TestFileNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := FileNotEmptyf(t, filepath.Join(testDataPath(), "existing_file"), "test message") + if !result { + t.Error("FileNotEmptyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := FileNotEmptyf(mock, filepath.Join(testDataPath(), "empty_file"), "test message") + if result { + t.Error("FileNotEmptyf should return false on failure") + } + if !mock.failed { + t.Error("FileNotEmpty should mark test as failed") + } + }) +} + +func TestGreaterf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Greaterf(t, 2, 1, "test message") + if !result { + t.Error("Greaterf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Greaterf(mock, 1, 2, "test message") + if result { + t.Error("Greaterf should return false on failure") + } + if !mock.failed { + t.Error("Greater should mark test as failed") + } + }) +} + +func TestGreaterOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := GreaterOrEqualf(t, 2, 1, "test message") + if !result { + t.Error("GreaterOrEqualf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := GreaterOrEqualf(mock, 1, 2, "test message") + if result { + t.Error("GreaterOrEqualf should return false on failure") + } + if !mock.failed { + t.Error("GreaterOrEqual should mark test as failed") + } + }) +} + +func TestHTTPBodyContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPBodyContainsf(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!", "test message") + if !result { + t.Error("HTTPBodyContainsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPBodyContainsf(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!", "test message") + if result { + t.Error("HTTPBodyContainsf should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyContains should mark test as failed") + } + }) +} + +func TestHTTPBodyNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPBodyNotContainsf(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!", "test message") + if !result { + t.Error("HTTPBodyNotContainsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPBodyNotContainsf(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!", "test message") + if result { + t.Error("HTTPBodyNotContainsf should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyNotContains should mark test as failed") + } + }) +} + +func TestHTTPErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPErrorf(t, httpError, "GET", "/", nil, "test message") + if !result { + t.Error("HTTPErrorf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPErrorf(mock, httpOK, "GET", "/", nil, "test message") + if result { + t.Error("HTTPErrorf should return false on failure") + } + if !mock.failed { + t.Error("HTTPError should mark test as failed") + } + }) +} + +func TestHTTPRedirectf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPRedirectf(t, httpRedirect, "GET", "/", nil, "test message") + if !result { + t.Error("HTTPRedirectf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPRedirectf(mock, httpError, "GET", "/", nil, "test message") + if result { + t.Error("HTTPRedirectf should return false on failure") + } + if !mock.failed { + t.Error("HTTPRedirect should mark test as failed") + } + }) +} + +func TestHTTPStatusCodef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPStatusCodef(t, httpOK, "GET", "/", nil, http.StatusOK, "test message") + if !result { + t.Error("HTTPStatusCodef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPStatusCodef(mock, httpError, "GET", "/", nil, http.StatusOK, "test message") + if result { + t.Error("HTTPStatusCodef should return false on failure") + } + if !mock.failed { + t.Error("HTTPStatusCode should mark test as failed") + } + }) +} + +func TestHTTPSuccessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := HTTPSuccessf(t, httpOK, "GET", "/", nil, "test message") + if !result { + t.Error("HTTPSuccessf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := HTTPSuccessf(mock, httpError, "GET", "/", nil, "test message") + if result { + t.Error("HTTPSuccessf should return false on failure") + } + if !mock.failed { + t.Error("HTTPSuccess should mark test as failed") + } + }) +} + +func TestImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Implementsf(t, ptr(dummyInterface), new(testing.T), "test message") + if !result { + t.Error("Implementsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Implementsf(mock, (*error)(nil), new(testing.T), "test message") + if result { + t.Error("Implementsf should return false on failure") + } + if !mock.failed { + t.Error("Implements should mark test as failed") + } + }) +} + +func TestInDeltaf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDeltaf(t, 1.0, 1.01, 0.02, "test message") + if !result { + t.Error("InDeltaf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDeltaf(mock, 1.0, 1.1, 0.05, "test message") + if result { + t.Error("InDeltaf should return false on failure") + } + if !mock.failed { + t.Error("InDelta should mark test as failed") + } + }) +} + +func TestInDeltaMapValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDeltaMapValuesf(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02, "test message") + if !result { + t.Error("InDeltaMapValuesf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDeltaMapValuesf(mock, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05, "test message") + if result { + t.Error("InDeltaMapValuesf should return false on failure") + } + if !mock.failed { + t.Error("InDeltaMapValues should mark test as failed") + } + }) +} + +func TestInDeltaSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InDeltaSlicef(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02, "test message") + if !result { + t.Error("InDeltaSlicef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InDeltaSlicef(mock, []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05, "test message") + if result { + t.Error("InDeltaSlicef should return false on failure") + } + if !mock.failed { + t.Error("InDeltaSlice should mark test as failed") + } + }) +} + +func TestInEpsilonf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InEpsilonf(t, 100.0, 101.0, 0.02, "test message") + if !result { + t.Error("InEpsilonf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InEpsilonf(mock, 100.0, 110.0, 0.05, "test message") + if result { + t.Error("InEpsilonf should return false on failure") + } + if !mock.failed { + t.Error("InEpsilon should mark test as failed") + } + }) +} + +func TestInEpsilonSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := InEpsilonSlicef(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02, "test message") + if !result { + t.Error("InEpsilonSlicef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := InEpsilonSlicef(mock, []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05, "test message") + if result { + t.Error("InEpsilonSlicef should return false on failure") + } + if !mock.failed { + t.Error("InEpsilonSlice should mark test as failed") + } + }) +} + +func TestIsDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsDecreasingf(t, []int{3, 2, 1}, "test message") + if !result { + t.Error("IsDecreasingf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsDecreasingf(mock, []int{1, 2, 3}, "test message") + if result { + t.Error("IsDecreasingf should return false on failure") + } + if !mock.failed { + t.Error("IsDecreasing should mark test as failed") + } + }) +} + +func TestIsIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsIncreasingf(t, []int{1, 2, 3}, "test message") + if !result { + t.Error("IsIncreasingf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsIncreasingf(mock, []int{1, 1, 2}, "test message") + if result { + t.Error("IsIncreasingf should return false on failure") + } + if !mock.failed { + t.Error("IsIncreasing should mark test as failed") + } + }) +} + +func TestIsNonDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNonDecreasingf(t, []int{1, 1, 2}, "test message") + if !result { + t.Error("IsNonDecreasingf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNonDecreasingf(mock, []int{2, 1, 1}, "test message") + if result { + t.Error("IsNonDecreasingf should return false on failure") + } + if !mock.failed { + t.Error("IsNonDecreasing should mark test as failed") + } + }) +} + +func TestIsNonIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNonIncreasingf(t, []int{2, 1, 1}, "test message") + if !result { + t.Error("IsNonIncreasingf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNonIncreasingf(mock, []int{1, 2, 3}, "test message") + if result { + t.Error("IsNonIncreasingf should return false on failure") + } + if !mock.failed { + t.Error("IsNonIncreasing should mark test as failed") + } + }) +} + +func TestIsNotTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsNotTypef(t, int32(123), int64(456), "test message") + if !result { + t.Error("IsNotTypef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsNotTypef(mock, 123, 456, "test message") + if result { + t.Error("IsNotTypef should return false on failure") + } + if !mock.failed { + t.Error("IsNotType should mark test as failed") + } + }) +} + +func TestIsTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := IsTypef(t, 123, 456, "test message") + if !result { + t.Error("IsTypef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := IsTypef(mock, int32(123), int64(456), "test message") + if result { + t.Error("IsTypef should return false on failure") + } + if !mock.failed { + t.Error("IsType should mark test as failed") + } + }) +} + +func TestJSONEqf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "test message") + if !result { + t.Error("JSONEqf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := JSONEqf(mock, `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`, "test message") + if result { + t.Error("JSONEqf should return false on failure") + } + if !mock.failed { + t.Error("JSONEq should mark test as failed") + } + }) +} + +func TestJSONEqBytesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := JSONEqBytesf(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "test message") + if !result { + t.Error("JSONEqBytesf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := JSONEqBytesf(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`), "test message") + if result { + t.Error("JSONEqBytesf should return false on failure") + } + if !mock.failed { + t.Error("JSONEqBytes should mark test as failed") + } + }) +} + +func TestLenf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Lenf(t, []string{"A", "B"}, 2, "test message") + if !result { + t.Error("Lenf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Lenf(mock, []string{"A", "B"}, 1, "test message") + if result { + t.Error("Lenf should return false on failure") + } + if !mock.failed { + t.Error("Len should mark test as failed") + } + }) +} + +func TestLessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Lessf(t, 1, 2, "test message") + if !result { + t.Error("Lessf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Lessf(mock, 2, 1, "test message") + if result { + t.Error("Lessf should return false on failure") + } + if !mock.failed { + t.Error("Less should mark test as failed") + } + }) +} + +func TestLessOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := LessOrEqualf(t, 1, 2, "test message") + if !result { + t.Error("LessOrEqualf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := LessOrEqualf(mock, 2, 1, "test message") + if result { + t.Error("LessOrEqualf should return false on failure") + } + if !mock.failed { + t.Error("LessOrEqual should mark test as failed") + } + }) +} + +func TestNegativef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Negativef(t, -1, "test message") + if !result { + t.Error("Negativef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Negativef(mock, 1, "test message") + if result { + t.Error("Negativef should return false on failure") + } + if !mock.failed { + t.Error("Negative should mark test as failed") + } + }) +} + +func TestNeverf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Neverf(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("Neverf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Neverf(mock, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("Neverf should return false on failure") + } + if !mock.failed { + t.Error("Never should mark test as failed") + } + }) +} + +func TestNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Nilf(t, nil, "test message") + if !result { + t.Error("Nilf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Nilf(mock, "not nil", "test message") + if result { + t.Error("Nilf should return false on failure") + } + if !mock.failed { + t.Error("Nil should mark test as failed") + } + }) +} + +func TestNoDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoDirExistsf(t, filepath.Join(testDataPath(), "non_existing_dir"), "test message") + if !result { + t.Error("NoDirExistsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoDirExistsf(mock, filepath.Join(testDataPath(), "existing_dir"), "test message") + if result { + t.Error("NoDirExistsf should return false on failure") + } + if !mock.failed { + t.Error("NoDirExists should mark test as failed") + } + }) +} + +func TestNoErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoErrorf(t, nil, "test message") + if !result { + t.Error("NoErrorf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoErrorf(mock, ErrTest, "test message") + if result { + t.Error("NoErrorf should return false on failure") + } + if !mock.failed { + t.Error("NoError should mark test as failed") + } + }) +} + +func TestNoFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NoFileExistsf(t, filepath.Join(testDataPath(), "non_existing_file"), "test message") + if !result { + t.Error("NoFileExistsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NoFileExistsf(mock, filepath.Join(testDataPath(), "existing_file"), "test message") + if result { + t.Error("NoFileExistsf should return false on failure") + } + if !mock.failed { + t.Error("NoFileExists should mark test as failed") + } + }) +} + +func TestNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotContainsf(t, []string{"A", "B"}, "C", "test message") + if !result { + t.Error("NotContainsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotContainsf(mock, []string{"A", "B"}, "B", "test message") + if result { + t.Error("NotContainsf should return false on failure") + } + if !mock.failed { + t.Error("NotContains should mark test as failed") + } + }) +} + +func TestNotElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotElementsMatchf(t, []int{1, 2, 3}, []int{1, 2, 4}, "test message") + if !result { + t.Error("NotElementsMatchf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotElementsMatchf(mock, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + if result { + t.Error("NotElementsMatchf should return false on failure") + } + if !mock.failed { + t.Error("NotElementsMatch should mark test as failed") + } + }) +} + +func TestNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEmptyf(t, "not empty", "test message") + if !result { + t.Error("NotEmptyf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEmptyf(mock, "", "test message") + if result { + t.Error("NotEmptyf should return false on failure") + } + if !mock.failed { + t.Error("NotEmpty should mark test as failed") + } + }) +} + +func TestNotEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEqualf(t, 123, 456, "test message") + if !result { + t.Error("NotEqualf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEqualf(mock, 123, 123, "test message") + if result { + t.Error("NotEqualf should return false on failure") + } + if !mock.failed { + t.Error("NotEqual should mark test as failed") + } + }) +} + +func TestNotEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotEqualValuesf(t, uint32(123), int32(456), "test message") + if !result { + t.Error("NotEqualValuesf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotEqualValuesf(mock, uint32(123), int32(123), "test message") + if result { + t.Error("NotEqualValuesf should return false on failure") + } + if !mock.failed { + t.Error("NotEqualValues should mark test as failed") + } + }) +} + +func TestNotErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotErrorAsf(t, ErrTest, new(*dummyError), "test message") + if !result { + t.Error("NotErrorAsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotErrorAsf(mock, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + if result { + t.Error("NotErrorAsf should return false on failure") + } + if !mock.failed { + t.Error("NotErrorAs should mark test as failed") + } + }) +} + +func TestNotErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotErrorIsf(t, ErrTest, io.EOF, "test message") + if !result { + t.Error("NotErrorIsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotErrorIsf(mock, fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + if result { + t.Error("NotErrorIsf should return false on failure") + } + if !mock.failed { + t.Error("NotErrorIs should mark test as failed") + } + }) +} + +func TestNotImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotImplementsf(t, (*error)(nil), new(testing.T), "test message") + if !result { + t.Error("NotImplementsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotImplementsf(mock, ptr(dummyInterface), new(testing.T), "test message") + if result { + t.Error("NotImplementsf should return false on failure") + } + if !mock.failed { + t.Error("NotImplements should mark test as failed") + } + }) +} + +func TestNotNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotNilf(t, "not nil", "test message") + if !result { + t.Error("NotNilf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotNilf(mock, nil, "test message") + if result { + t.Error("NotNilf should return false on failure") + } + if !mock.failed { + t.Error("NotNil should mark test as failed") + } + }) +} + +func TestNotPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotPanicsf(t, func() {}, "test message") + if !result { + t.Error("NotPanicsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotPanicsf(mock, func() { panic("panicking") }, "test message") + if result { + t.Error("NotPanicsf should return false on failure") + } + if !mock.failed { + t.Error("NotPanics should mark test as failed") + } + }) +} + +func TestNotRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotRegexpf(t, "^start", "not starting", "test message") + if !result { + t.Error("NotRegexpf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotRegexpf(mock, "^start", "starting", "test message") + if result { + t.Error("NotRegexpf should return false on failure") + } + if !mock.failed { + t.Error("NotRegexp should mark test as failed") + } + }) +} + +func TestNotSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotSamef(t, &staticVar, ptr("static string"), "test message") + if !result { + t.Error("NotSamef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotSamef(mock, &staticVar, staticVarPtr, "test message") + if result { + t.Error("NotSamef should return false on failure") + } + if !mock.failed { + t.Error("NotSame should mark test as failed") + } + }) +} + +func TestNotSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotSubsetf(t, []int{1, 2, 3}, []int{4, 5}, "test message") + if !result { + t.Error("NotSubsetf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotSubsetf(mock, []int{1, 2, 3}, []int{1, 2}, "test message") + if result { + t.Error("NotSubsetf should return false on failure") + } + if !mock.failed { + t.Error("NotSubset should mark test as failed") + } + }) +} + +func TestNotZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := NotZerof(t, 1, "test message") + if !result { + t.Error("NotZerof should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := NotZerof(mock, 0, "test message") + if result { + t.Error("NotZerof should return false on failure") + } + if !mock.failed { + t.Error("NotZero should mark test as failed") + } + }) +} + +func TestPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Panicsf(t, func() { panic("panicking") }, "test message") + if !result { + t.Error("Panicsf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Panicsf(mock, func() {}, "test message") + if result { + t.Error("Panicsf should return false on failure") + } + if !mock.failed { + t.Error("Panics should mark test as failed") + } + }) +} + +func TestPanicsWithErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := PanicsWithErrorf(t, ErrTest.Error(), func() { panic(ErrTest) }, "test message") + if !result { + t.Error("PanicsWithErrorf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := PanicsWithErrorf(mock, ErrTest.Error(), func() {}, "test message") + if result { + t.Error("PanicsWithErrorf should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithError should mark test as failed") + } + }) +} + +func TestPanicsWithValuef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := PanicsWithValuef(t, "panicking", func() { panic("panicking") }, "test message") + if !result { + t.Error("PanicsWithValuef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := PanicsWithValuef(mock, "panicking", func() {}, "test message") + if result { + t.Error("PanicsWithValuef should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithValue should mark test as failed") + } + }) +} + +func TestPositivef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Positivef(t, 1, "test message") + if !result { + t.Error("Positivef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Positivef(mock, -1, "test message") + if result { + t.Error("Positivef should return false on failure") + } + if !mock.failed { + t.Error("Positive should mark test as failed") + } + }) +} + +func TestRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Regexpf(t, "^start", "starting", "test message") + if !result { + t.Error("Regexpf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Regexpf(mock, "^start", "not starting", "test message") + if result { + t.Error("Regexpf should return false on failure") + } + if !mock.failed { + t.Error("Regexp should mark test as failed") + } + }) +} + +func TestSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Samef(t, &staticVar, staticVarPtr, "test message") + if !result { + t.Error("Samef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Samef(mock, &staticVar, ptr("static string"), "test message") + if result { + t.Error("Samef should return false on failure") + } + if !mock.failed { + t.Error("Same should mark test as failed") + } + }) +} + +func TestSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Subsetf(t, []int{1, 2, 3}, []int{1, 2}, "test message") + if !result { + t.Error("Subsetf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Subsetf(mock, []int{1, 2, 3}, []int{4, 5}, "test message") + if result { + t.Error("Subsetf should return false on failure") + } + if !mock.failed { + t.Error("Subset should mark test as failed") + } + }) +} + +func TestTruef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Truef(t, 1 == 1, "test message") + if !result { + t.Error("Truef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Truef(mock, 1 == 0, "test message") + if result { + t.Error("Truef should return false on failure") + } + if !mock.failed { + t.Error("True should mark test as failed") + } + }) +} + +func TestWithinDurationf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := WithinDurationf(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second, "test message") + if !result { + t.Error("WithinDurationf should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := WithinDurationf(mock, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second, "test message") + if result { + t.Error("WithinDurationf should return false on failure") + } + if !mock.failed { + t.Error("WithinDuration should mark test as failed") + } + }) +} + +func TestWithinRangef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := WithinRangef(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + if !result { + t.Error("WithinRangef should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := WithinRangef(mock, time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + if result { + t.Error("WithinRangef should return false on failure") + } + if !mock.failed { + t.Error("WithinRange should mark test as failed") + } + }) +} + +func TestYAMLEqf(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panicsf(t, func() { + YAMLEqf(t, "key: value", "key: value", "test message") + }, "should panic without the yaml feature enabled") + }) +} + +func TestZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + result := Zerof(t, 0, "test message") + if !result { + t.Error("Zerof should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + result := Zerof(mock, 1, "test message") + if result { + t.Error("Zerof should return false on failure") + } + if !mock.failed { + t.Error("Zero should mark test as failed") + } + }) +} diff --git a/assert/assert_forward.go b/assert/assert_forward.go new file mode 100644 index 000000000..384202c0b --- /dev/null +++ b/assert/assert_forward.go @@ -0,0 +1,1610 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// Assertions exposes all assertion functions as methods. +// +// NOTE: assertion methods with parameterized types (generics) are not supported as methods. +// +// Upon failure, the test [T] is marked as failed and continues execution. +type Assertions struct { + t T +} + +// New makes a new [Assertions] object for the specified [T] (e.g. [testing.T]). +func New(t T) *Assertions { + return &Assertions{ + t: t, + } +} + +// Condition is the same as [Condition], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Condition(comp Comparison, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf is the same as [Assertions.Condition], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Conditionf(comp Comparison, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Condition(a.t, comp, forwardArgs(msg, args)) +} + +// Contains is the same as [Contains], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Contains(s any, contains any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf is the same as [Assertions.Contains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Containsf(s any, contains any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Contains(a.t, s, contains, forwardArgs(msg, args)) +} + +// DirExists is the same as [DirExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) DirExists(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf is the same as [Assertions.DirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) DirExistsf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.DirExists(a.t, path, forwardArgs(msg, args)) +} + +// ElementsMatch is the same as [ElementsMatch], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ElementsMatch(listA any, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf is the same as [Assertions.ElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ElementsMatchf(listA any, listB any, msg string, args ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ElementsMatch(a.t, listA, listB, forwardArgs(msg, args)) +} + +// Empty is the same as [Empty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Empty(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Empty(a.t, object, msgAndArgs...) +} + +// Emptyf is the same as [Assertions.Empty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Emptyf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Empty(a.t, object, forwardArgs(msg, args)) +} + +// Equal is the same as [Equal], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Equal(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Equal(a.t, expected, actual, msgAndArgs...) +} + +// Equalf is the same as [Assertions.Equal], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Equalf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Equal(a.t, expected, actual, forwardArgs(msg, args)) +} + +// EqualError is the same as [EqualError], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf is the same as [Assertions.EqualError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualError(a.t, theError, errString, forwardArgs(msg, args)) +} + +// EqualExportedValues is the same as [EqualExportedValues], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualExportedValues(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualExportedValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualExportedValuesf is the same as [Assertions.EqualExportedValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualExportedValuesf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualExportedValues(a.t, expected, actual, forwardArgs(msg, args)) +} + +// EqualValues is the same as [EqualValues], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualValues(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf is the same as [Assertions.EqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EqualValuesf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EqualValues(a.t, expected, actual, forwardArgs(msg, args)) +} + +// Error is the same as [Error], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Error(err error, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Error(a.t, err, msgAndArgs...) +} + +// Errorf is the same as [Assertions.Error], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Errorf(err error, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Error(a.t, err, forwardArgs(msg, args)) +} + +// ErrorAs is the same as [ErrorAs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorAs(err error, target any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf is the same as [Assertions.ErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorAsf(err error, target any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorAs(a.t, err, target, forwardArgs(msg, args)) +} + +// ErrorContains is the same as [ErrorContains], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf is the same as [Assertions.ErrorContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorContains(a.t, theError, contains, forwardArgs(msg, args)) +} + +// ErrorIs is the same as [ErrorIs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf is the same as [Assertions.ErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.ErrorIs(a.t, err, target, forwardArgs(msg, args)) +} + +// Eventually is the same as [Eventually], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf is the same as [Assertions.Eventually], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Eventually(a.t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// EventuallyWithT is the same as [EventuallyWithT], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// EventuallyWithTf is the same as [Assertions.EventuallyWithT], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.EventuallyWithT(a.t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// Exactly is the same as [Exactly], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Exactly(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf is the same as [Assertions.Exactly], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Exactlyf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Exactly(a.t, expected, actual, forwardArgs(msg, args)) +} + +// Fail is the same as [Fail], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Fail(a.t, failureMessage, msgAndArgs...) +} + +// Failf is the same as [Assertions.Fail], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Failf(failureMessage string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Fail(a.t, failureMessage, forwardArgs(msg, args)) +} + +// FailNow is the same as [FailNow], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf is the same as [Assertions.FailNow], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FailNow(a.t, failureMessage, forwardArgs(msg, args)) +} + +// False is the same as [False], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) False(value bool, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.False(a.t, value, msgAndArgs...) +} + +// Falsef is the same as [Assertions.False], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Falsef(value bool, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.False(a.t, value, forwardArgs(msg, args)) +} + +// FileEmpty is the same as [FileEmpty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileEmpty(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileEmpty(a.t, path, msgAndArgs...) +} + +// FileEmptyf is the same as [Assertions.FileEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileEmptyf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileEmpty(a.t, path, forwardArgs(msg, args)) +} + +// FileExists is the same as [FileExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileExists(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf is the same as [Assertions.FileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileExistsf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileExists(a.t, path, forwardArgs(msg, args)) +} + +// FileNotEmpty is the same as [FileNotEmpty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileNotEmpty(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileNotEmpty(a.t, path, msgAndArgs...) +} + +// FileNotEmptyf is the same as [Assertions.FileNotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) FileNotEmptyf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.FileNotEmpty(a.t, path, forwardArgs(msg, args)) +} + +// Greater is the same as [Greater], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Greater(e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Greater(a.t, e1, e2, msgAndArgs...) +} + +// Greaterf is the same as [Assertions.Greater], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Greaterf(e1 any, e2 any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Greater(a.t, e1, e2, forwardArgs(msg, args)) +} + +// GreaterOrEqual is the same as [GreaterOrEqual], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) GreaterOrEqual(e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf is the same as [Assertions.GreaterOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) GreaterOrEqualf(e1 any, e2 any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.GreaterOrEqual(a.t, e1, e2, forwardArgs(msg, args)) +} + +// HTTPBodyContains is the same as [HTTPBodyContains], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf is the same as [Assertions.HTTPBodyContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyContains(a.t, handler, method, url, values, str, forwardArgs(msg, args)) +} + +// HTTPBodyNotContains is the same as [HTTPBodyNotContains], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf is the same as [Assertions.HTTPBodyNotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPBodyNotContains(a.t, handler, method, url, values, str, forwardArgs(msg, args)) +} + +// HTTPError is the same as [HTTPError], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf is the same as [Assertions.HTTPError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPError(a.t, handler, method, url, values, forwardArgs(msg, args)) +} + +// HTTPRedirect is the same as [HTTPRedirect], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf is the same as [Assertions.HTTPRedirect], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPRedirect(a.t, handler, method, url, values, forwardArgs(msg, args)) +} + +// HTTPStatusCode is the same as [HTTPStatusCode], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef is the same as [Assertions.HTTPStatusCode], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPStatusCode(a.t, handler, method, url, values, statuscode, forwardArgs(msg, args)) +} + +// HTTPSuccess is the same as [HTTPSuccess], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf is the same as [Assertions.HTTPSuccess], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.HTTPSuccess(a.t, handler, method, url, values, forwardArgs(msg, args)) +} + +// Implements is the same as [Implements], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Implements(interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf is the same as [Assertions.Implements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Implementsf(interfaceObject any, object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Implements(a.t, interfaceObject, object, forwardArgs(msg, args)) +} + +// InDelta is the same as [InDelta], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDelta(expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaf is the same as [Assertions.InDelta], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDeltaf(expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDelta(a.t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InDeltaMapValues is the same as [InDeltaMapValues], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDeltaMapValues(expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as [Assertions.InDeltaMapValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDeltaMapValuesf(expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDeltaMapValues(a.t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InDeltaSlice is the same as [InDeltaSlice], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDeltaSlice(expected any, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as [Assertions.InDeltaSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InDeltaSlicef(expected any, actual any, delta float64, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InDeltaSlice(a.t, expected, actual, delta, forwardArgs(msg, args)) +} + +// InEpsilon is the same as [InEpsilon], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InEpsilon(expected any, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonf is the same as [Assertions.InEpsilon], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InEpsilonf(expected any, actual any, epsilon float64, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InEpsilon(a.t, expected, actual, epsilon, forwardArgs(msg, args)) +} + +// InEpsilonSlice is the same as [InEpsilonSlice], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InEpsilonSlice(expected any, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as [Assertions.InEpsilonSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) InEpsilonSlicef(expected any, actual any, epsilon float64, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.InEpsilonSlice(a.t, expected, actual, epsilon, forwardArgs(msg, args)) +} + +// IsDecreasing is the same as [IsDecreasing], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsDecreasing(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf is the same as [Assertions.IsDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsDecreasingf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsDecreasing(a.t, object, forwardArgs(msg, args)) +} + +// IsIncreasing is the same as [IsIncreasing], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsIncreasing(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf is the same as [Assertions.IsIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsIncreasingf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsIncreasing(a.t, object, forwardArgs(msg, args)) +} + +// IsNonDecreasing is the same as [IsNonDecreasing], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNonDecreasing(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf is the same as [Assertions.IsNonDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNonDecreasingf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNonDecreasing(a.t, object, forwardArgs(msg, args)) +} + +// IsNonIncreasing is the same as [IsNonIncreasing], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNonIncreasing(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf is the same as [Assertions.IsNonIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNonIncreasingf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNonIncreasing(a.t, object, forwardArgs(msg, args)) +} + +// IsNotType is the same as [IsNotType], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNotType(theType any, object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNotType(a.t, theType, object, msgAndArgs...) +} + +// IsNotTypef is the same as [Assertions.IsNotType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsNotTypef(theType any, object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsNotType(a.t, theType, object, forwardArgs(msg, args)) +} + +// IsType is the same as [IsType], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsType(expectedType any, object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef is the same as [Assertions.IsType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) IsTypef(expectedType any, object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.IsType(a.t, expectedType, object, forwardArgs(msg, args)) +} + +// JSONEq is the same as [JSONEq], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf is the same as [Assertions.JSONEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.JSONEq(a.t, expected, actual, forwardArgs(msg, args)) +} + +// JSONEqBytes is the same as [JSONEqBytes], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) JSONEqBytes(expected []byte, actual []byte, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.JSONEqBytes(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqBytesf is the same as [Assertions.JSONEqBytes], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) JSONEqBytesf(expected []byte, actual []byte, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.JSONEqBytes(a.t, expected, actual, forwardArgs(msg, args)) +} + +// Len is the same as [Len], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Len(object any, length int, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Len(a.t, object, length, msgAndArgs...) +} + +// Lenf is the same as [Assertions.Len], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Lenf(object any, length int, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Len(a.t, object, length, forwardArgs(msg, args)) +} + +// Less is the same as [Less], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Less(e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Less(a.t, e1, e2, msgAndArgs...) +} + +// Lessf is the same as [Assertions.Less], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Lessf(e1 any, e2 any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Less(a.t, e1, e2, forwardArgs(msg, args)) +} + +// LessOrEqual is the same as [LessOrEqual], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) LessOrEqual(e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf is the same as [Assertions.LessOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) LessOrEqualf(e1 any, e2 any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.LessOrEqual(a.t, e1, e2, forwardArgs(msg, args)) +} + +// Negative is the same as [Negative], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Negative(e any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Negative(a.t, e, msgAndArgs...) +} + +// Negativef is the same as [Assertions.Negative], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Negativef(e any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Negative(a.t, e, forwardArgs(msg, args)) +} + +// Never is the same as [Never], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf is the same as [Assertions.Never], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Never(a.t, condition, waitFor, tick, forwardArgs(msg, args)) +} + +// Nil is the same as [Nil], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Nil(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Nil(a.t, object, msgAndArgs...) +} + +// Nilf is the same as [Assertions.Nil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Nilf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Nil(a.t, object, forwardArgs(msg, args)) +} + +// NoDirExists is the same as [NoDirExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf is the same as [Assertions.NoDirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoDirExists(a.t, path, forwardArgs(msg, args)) +} + +// NoError is the same as [NoError], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoError(err error, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf is the same as [Assertions.NoError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoErrorf(err error, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoError(a.t, err, forwardArgs(msg, args)) +} + +// NoFileExists is the same as [NoFileExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf is the same as [Assertions.NoFileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NoFileExists(a.t, path, forwardArgs(msg, args)) +} + +// NotContains is the same as [NotContains], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotContains(s any, contains any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf is the same as [Assertions.NotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotContainsf(s any, contains any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotContains(a.t, s, contains, forwardArgs(msg, args)) +} + +// NotElementsMatch is the same as [NotElementsMatch], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotElementsMatch(listA any, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// NotElementsMatchf is the same as [Assertions.NotElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotElementsMatchf(listA any, listB any, msg string, args ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotElementsMatch(a.t, listA, listB, forwardArgs(msg, args)) +} + +// NotEmpty is the same as [NotEmpty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEmpty(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf is the same as [Assertions.NotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEmptyf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEmpty(a.t, object, forwardArgs(msg, args)) +} + +// NotEqual is the same as [NotEqual], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEqual(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualf is the same as [Assertions.NotEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEqualf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEqual(a.t, expected, actual, forwardArgs(msg, args)) +} + +// NotEqualValues is the same as [NotEqualValues], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEqualValues(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf is the same as [Assertions.NotEqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotEqualValuesf(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotEqualValues(a.t, expected, actual, forwardArgs(msg, args)) +} + +// NotErrorAs is the same as [NotErrorAs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotErrorAs(err error, target any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotErrorAs(a.t, err, target, msgAndArgs...) +} + +// NotErrorAsf is the same as [Assertions.NotErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotErrorAsf(err error, target any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotErrorAs(a.t, err, target, forwardArgs(msg, args)) +} + +// NotErrorIs is the same as [NotErrorIs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf is the same as [Assertions.NotErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotErrorIs(a.t, err, target, forwardArgs(msg, args)) +} + +// NotImplements is the same as [NotImplements], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotImplements(interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotImplements(a.t, interfaceObject, object, msgAndArgs...) +} + +// NotImplementsf is the same as [Assertions.NotImplements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotImplementsf(interfaceObject any, object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotImplements(a.t, interfaceObject, object, forwardArgs(msg, args)) +} + +// NotNil is the same as [NotNil], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotNil(object any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf is the same as [Assertions.NotNil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotNilf(object any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotNil(a.t, object, forwardArgs(msg, args)) +} + +// NotPanics is the same as [NotPanics], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotPanics(f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf is the same as [Assertions.NotPanics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotPanicsf(f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotPanics(a.t, f, forwardArgs(msg, args)) +} + +// NotRegexp is the same as [NotRegexp], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotRegexp(rx any, str any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf is the same as [Assertions.NotRegexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotRegexpf(rx any, str any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotRegexp(a.t, rx, str, forwardArgs(msg, args)) +} + +// NotSame is the same as [NotSame], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotSame(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef is the same as [Assertions.NotSame], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotSamef(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotSame(a.t, expected, actual, forwardArgs(msg, args)) +} + +// NotSubset is the same as [NotSubset], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotSubset(list any, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf is the same as [Assertions.NotSubset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotSubsetf(list any, subset any, msg string, args ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotSubset(a.t, list, subset, forwardArgs(msg, args)) +} + +// NotZero is the same as [NotZero], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotZero(i any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof is the same as [Assertions.NotZero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) NotZerof(i any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.NotZero(a.t, i, forwardArgs(msg, args)) +} + +// Panics is the same as [Panics], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Panics(f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Panics(a.t, f, msgAndArgs...) +} + +// Panicsf is the same as [Assertions.Panics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Panicsf(f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Panics(a.t, f, forwardArgs(msg, args)) +} + +// PanicsWithError is the same as [PanicsWithError], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) PanicsWithError(errString string, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf is the same as [Assertions.PanicsWithError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) PanicsWithErrorf(errString string, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.PanicsWithError(a.t, errString, f, forwardArgs(msg, args)) +} + +// PanicsWithValue is the same as [PanicsWithValue], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) PanicsWithValue(expected any, f assertions.PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef is the same as [Assertions.PanicsWithValue], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) PanicsWithValuef(expected any, f assertions.PanicTestFunc, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.PanicsWithValue(a.t, expected, f, forwardArgs(msg, args)) +} + +// Positive is the same as [Positive], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Positive(e any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Positive(a.t, e, msgAndArgs...) +} + +// Positivef is the same as [Assertions.Positive], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Positivef(e any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Positive(a.t, e, forwardArgs(msg, args)) +} + +// Regexp is the same as [Regexp], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Regexp(rx any, str any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf is the same as [Assertions.Regexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Regexpf(rx any, str any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Regexp(a.t, rx, str, forwardArgs(msg, args)) +} + +// Same is the same as [Same], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Same(expected any, actual any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef is the same as [Assertions.Same], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Samef(expected any, actual any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Same(a.t, expected, actual, forwardArgs(msg, args)) +} + +// Subset is the same as [Subset], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Subset(list any, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf is the same as [Assertions.Subset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Subsetf(list any, subset any, msg string, args ...any) (ok bool) { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Subset(a.t, list, subset, forwardArgs(msg, args)) +} + +// True is the same as [True], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) True(value bool, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.True(a.t, value, msgAndArgs...) +} + +// Truef is the same as [Assertions.True], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Truef(value bool, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.True(a.t, value, forwardArgs(msg, args)) +} + +// WithinDuration is the same as [WithinDuration], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf is the same as [Assertions.WithinDuration], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.WithinDuration(a.t, expected, actual, delta, forwardArgs(msg, args)) +} + +// WithinRange is the same as [WithinRange], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.WithinRange(a.t, actual, start, end, msgAndArgs...) +} + +// WithinRangef is the same as [Assertions.WithinRange], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.WithinRange(a.t, actual, start, end, forwardArgs(msg, args)) +} + +// YAMLEq is the same as [YAMLEq], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf is the same as [Assertions.YAMLEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.YAMLEq(a.t, expected, actual, forwardArgs(msg, args)) +} + +// Zero is the same as [Zero], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Zero(i any, msgAndArgs ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Zero(a.t, i, msgAndArgs...) +} + +// Zerof is the same as [Assertions.Zero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and continues execution. +func (a *Assertions) Zerof(i any, msg string, args ...any) bool { + if h, ok := a.t.(H); ok { + h.Helper() + } + return assertions.Zero(a.t, i, forwardArgs(msg, args)) +} diff --git a/assert/assert_forward_test.go b/assert/assert_forward_test.go new file mode 100644 index 000000000..a4a3d0b2e --- /dev/null +++ b/assert/assert_forward_test.go @@ -0,0 +1,4215 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestAssertionsCondition(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Condition(func() bool { return true }) + if !result { + t.Error("Assertions.Condition should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Condition(func() bool { return false }) + if result { + t.Error("Assertions.Condition should return false on failure") + } + if !mock.failed { + t.Error("Condition should mark test as failed") + } + }) +} + +func TestAssertionsConditionf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Conditionf(func() bool { return true }, "test message") + if !result { + t.Error("Assertions.Condition should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Conditionf(func() bool { return false }, "test message") + if result { + t.Error("Assertions.Condition should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Condition should mark test as failed") + } + }) +} + +func TestAssertionsContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Contains([]string{"A", "B"}, "A") + if !result { + t.Error("Assertions.Contains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Contains([]string{"A", "B"}, "C") + if result { + t.Error("Assertions.Contains should return false on failure") + } + if !mock.failed { + t.Error("Contains should mark test as failed") + } + }) +} + +func TestAssertionsContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Containsf([]string{"A", "B"}, "A", "test message") + if !result { + t.Error("Assertions.Contains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Containsf([]string{"A", "B"}, "C", "test message") + if result { + t.Error("Assertions.Contains should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Contains should mark test as failed") + } + }) +} + +func TestAssertionsDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.DirExists(filepath.Join(testDataPath(), "existing_dir")) + if !result { + t.Error("Assertions.DirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.DirExists(filepath.Join(testDataPath(), "non_existing_dir")) + if result { + t.Error("Assertions.DirExists should return false on failure") + } + if !mock.failed { + t.Error("DirExists should mark test as failed") + } + }) +} + +func TestAssertionsDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.DirExistsf(filepath.Join(testDataPath(), "existing_dir"), "test message") + if !result { + t.Error("Assertions.DirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.DirExistsf(filepath.Join(testDataPath(), "non_existing_dir"), "test message") + if result { + t.Error("Assertions.DirExists should return false on failure") + } + if !mock.failed { + t.Error("Assertions.DirExists should mark test as failed") + } + }) +} + +func TestAssertionsElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ElementsMatch([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + if !result { + t.Error("Assertions.ElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ElementsMatch([]int{1, 2, 3}, []int{1, 2, 4}) + if result { + t.Error("Assertions.ElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("ElementsMatch should mark test as failed") + } + }) +} + +func TestAssertionsElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ElementsMatchf([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + if !result { + t.Error("Assertions.ElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ElementsMatchf([]int{1, 2, 3}, []int{1, 2, 4}, "test message") + if result { + t.Error("Assertions.ElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("Assertions.ElementsMatch should mark test as failed") + } + }) +} + +func TestAssertionsEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Empty("") + if !result { + t.Error("Assertions.Empty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Empty("not empty") + if result { + t.Error("Assertions.Empty should return false on failure") + } + if !mock.failed { + t.Error("Empty should mark test as failed") + } + }) +} + +func TestAssertionsEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Emptyf("", "test message") + if !result { + t.Error("Assertions.Empty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Emptyf("not empty", "test message") + if result { + t.Error("Assertions.Empty should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Empty should mark test as failed") + } + }) +} + +func TestAssertionsEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Equal(123, 123) + if !result { + t.Error("Assertions.Equal should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Equal(123, 456) + if result { + t.Error("Assertions.Equal should return false on failure") + } + if !mock.failed { + t.Error("Equal should mark test as failed") + } + }) +} + +func TestAssertionsEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Equalf(123, 123, "test message") + if !result { + t.Error("Assertions.Equal should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Equalf(123, 456, "test message") + if result { + t.Error("Assertions.Equal should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Equal should mark test as failed") + } + }) +} + +func TestAssertionsEqualError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualError(ErrTest, "assert.ErrTest general error for testing") + if !result { + t.Error("Assertions.EqualError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualError(ErrTest, "wrong error message") + if result { + t.Error("Assertions.EqualError should return false on failure") + } + if !mock.failed { + t.Error("EqualError should mark test as failed") + } + }) +} + +func TestAssertionsEqualErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualErrorf(ErrTest, "assert.ErrTest general error for testing", "test message") + if !result { + t.Error("Assertions.EqualError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualErrorf(ErrTest, "wrong error message", "test message") + if result { + t.Error("Assertions.EqualError should return false on failure") + } + if !mock.failed { + t.Error("Assertions.EqualError should mark test as failed") + } + }) +} + +func TestAssertionsEqualExportedValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualExportedValues(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + if !result { + t.Error("Assertions.EqualExportedValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualExportedValues(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}) + if result { + t.Error("Assertions.EqualExportedValues should return false on failure") + } + if !mock.failed { + t.Error("EqualExportedValues should mark test as failed") + } + }) +} + +func TestAssertionsEqualExportedValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualExportedValuesf(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}, "test message") + if !result { + t.Error("Assertions.EqualExportedValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualExportedValuesf(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}, "test message") + if result { + t.Error("Assertions.EqualExportedValues should return false on failure") + } + if !mock.failed { + t.Error("Assertions.EqualExportedValues should mark test as failed") + } + }) +} + +func TestAssertionsEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualValues(uint32(123), int32(123)) + if !result { + t.Error("Assertions.EqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualValues(uint32(123), int32(456)) + if result { + t.Error("Assertions.EqualValues should return false on failure") + } + if !mock.failed { + t.Error("EqualValues should mark test as failed") + } + }) +} + +func TestAssertionsEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EqualValuesf(uint32(123), int32(123), "test message") + if !result { + t.Error("Assertions.EqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EqualValuesf(uint32(123), int32(456), "test message") + if result { + t.Error("Assertions.EqualValues should return false on failure") + } + if !mock.failed { + t.Error("Assertions.EqualValues should mark test as failed") + } + }) +} + +func TestAssertionsError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Error(ErrTest) + if !result { + t.Error("Assertions.Error should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Error(nil) + if result { + t.Error("Assertions.Error should return false on failure") + } + if !mock.failed { + t.Error("Error should mark test as failed") + } + }) +} + +func TestAssertionsErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Errorf(ErrTest, "test message") + if !result { + t.Error("Assertions.Error should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Errorf(nil, "test message") + if result { + t.Error("Assertions.Error should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Error should mark test as failed") + } + }) +} + +func TestAssertionsErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorAs(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + if !result { + t.Error("Assertions.ErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorAs(ErrTest, new(*dummyError)) + if result { + t.Error("Assertions.ErrorAs should return false on failure") + } + if !mock.failed { + t.Error("ErrorAs should mark test as failed") + } + }) +} + +func TestAssertionsErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorAsf(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + if !result { + t.Error("Assertions.ErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorAsf(ErrTest, new(*dummyError), "test message") + if result { + t.Error("Assertions.ErrorAs should return false on failure") + } + if !mock.failed { + t.Error("Assertions.ErrorAs should mark test as failed") + } + }) +} + +func TestAssertionsErrorContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorContains(ErrTest, "general error") + if !result { + t.Error("Assertions.ErrorContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorContains(ErrTest, "not in message") + if result { + t.Error("Assertions.ErrorContains should return false on failure") + } + if !mock.failed { + t.Error("ErrorContains should mark test as failed") + } + }) +} + +func TestAssertionsErrorContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorContainsf(ErrTest, "general error", "test message") + if !result { + t.Error("Assertions.ErrorContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorContainsf(ErrTest, "not in message", "test message") + if result { + t.Error("Assertions.ErrorContains should return false on failure") + } + if !mock.failed { + t.Error("Assertions.ErrorContains should mark test as failed") + } + }) +} + +func TestAssertionsErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorIs(fmt.Errorf("wrap: %w", io.EOF), io.EOF) + if !result { + t.Error("Assertions.ErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorIs(ErrTest, io.EOF) + if result { + t.Error("Assertions.ErrorIs should return false on failure") + } + if !mock.failed { + t.Error("ErrorIs should mark test as failed") + } + }) +} + +func TestAssertionsErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.ErrorIsf(fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + if !result { + t.Error("Assertions.ErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.ErrorIsf(ErrTest, io.EOF, "test message") + if result { + t.Error("Assertions.ErrorIs should return false on failure") + } + if !mock.failed { + t.Error("Assertions.ErrorIs should mark test as failed") + } + }) +} + +func TestAssertionsEventually(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Eventually(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("Assertions.Eventually should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Eventually(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("Assertions.Eventually should return false on failure") + } + if !mock.failed { + t.Error("Eventually should mark test as failed") + } + }) +} + +func TestAssertionsEventuallyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Eventuallyf(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("Assertions.Eventually should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Eventuallyf(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("Assertions.Eventually should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Eventually should mark test as failed") + } + }) +} + +func TestAssertionsEventuallyWithT(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EventuallyWithT(func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("Assertions.EventuallyWithT should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EventuallyWithT(func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("Assertions.EventuallyWithT should return false on failure") + } + if !mock.failed { + t.Error("EventuallyWithT should mark test as failed") + } + }) +} + +func TestAssertionsEventuallyWithTf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.EventuallyWithTf(func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("Assertions.EventuallyWithT should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.EventuallyWithTf(func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("Assertions.EventuallyWithT should return false on failure") + } + if !mock.failed { + t.Error("Assertions.EventuallyWithT should mark test as failed") + } + }) +} + +func TestAssertionsExactly(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Exactly(int32(123), int32(123)) + if !result { + t.Error("Assertions.Exactly should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Exactly(int32(123), int64(123)) + if result { + t.Error("Assertions.Exactly should return false on failure") + } + if !mock.failed { + t.Error("Exactly should mark test as failed") + } + }) +} + +func TestAssertionsExactlyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Exactlyf(int32(123), int32(123), "test message") + if !result { + t.Error("Assertions.Exactly should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Exactlyf(int32(123), int64(123), "test message") + if result { + t.Error("Assertions.Exactly should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Exactly should mark test as failed") + } + }) +} + +func TestAssertionsFail(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Fail("failed") + if result { + t.Error("Assertions.Fail should return false on failure") + } + if !mock.failed { + t.Error("Fail should mark test as failed") + } + }) +} + +func TestAssertionsFailf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Failf("failed", "test message") + if result { + t.Error("Assertions.Fail should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Fail should mark test as failed") + } + }) +} + +func TestAssertionsFailNow(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + result := a.FailNow("failed") + if result { + t.Error("Assertions.FailNow should return false on failure") + } + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestAssertionsFailNowf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + result := a.FailNowf("failed", "test message") + if result { + t.Error("Assertions.FailNow should return false on failure") + } + if !mock.failed { + t.Error("Assertions.FailNow should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.FailNowf should call FailNow()") + } + }) +} + +func TestAssertionsFalse(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.False(1 == 0) + if !result { + t.Error("Assertions.False should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.False(1 == 1) + if result { + t.Error("Assertions.False should return false on failure") + } + if !mock.failed { + t.Error("False should mark test as failed") + } + }) +} + +func TestAssertionsFalsef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Falsef(1 == 0, "test message") + if !result { + t.Error("Assertions.False should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Falsef(1 == 1, "test message") + if result { + t.Error("Assertions.False should return false on failure") + } + if !mock.failed { + t.Error("Assertions.False should mark test as failed") + } + }) +} + +func TestAssertionsFileEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileEmpty(filepath.Join(testDataPath(), "empty_file")) + if !result { + t.Error("Assertions.FileEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileEmpty(filepath.Join(testDataPath(), "existing_file")) + if result { + t.Error("Assertions.FileEmpty should return false on failure") + } + if !mock.failed { + t.Error("FileEmpty should mark test as failed") + } + }) +} + +func TestAssertionsFileEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileEmptyf(filepath.Join(testDataPath(), "empty_file"), "test message") + if !result { + t.Error("Assertions.FileEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileEmptyf(filepath.Join(testDataPath(), "existing_file"), "test message") + if result { + t.Error("Assertions.FileEmpty should return false on failure") + } + if !mock.failed { + t.Error("Assertions.FileEmpty should mark test as failed") + } + }) +} + +func TestAssertionsFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileExists(filepath.Join(testDataPath(), "existing_file")) + if !result { + t.Error("Assertions.FileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileExists(filepath.Join(testDataPath(), "non_existing_file")) + if result { + t.Error("Assertions.FileExists should return false on failure") + } + if !mock.failed { + t.Error("FileExists should mark test as failed") + } + }) +} + +func TestAssertionsFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileExistsf(filepath.Join(testDataPath(), "existing_file"), "test message") + if !result { + t.Error("Assertions.FileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileExistsf(filepath.Join(testDataPath(), "non_existing_file"), "test message") + if result { + t.Error("Assertions.FileExists should return false on failure") + } + if !mock.failed { + t.Error("Assertions.FileExists should mark test as failed") + } + }) +} + +func TestAssertionsFileNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileNotEmpty(filepath.Join(testDataPath(), "existing_file")) + if !result { + t.Error("Assertions.FileNotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileNotEmpty(filepath.Join(testDataPath(), "empty_file")) + if result { + t.Error("Assertions.FileNotEmpty should return false on failure") + } + if !mock.failed { + t.Error("FileNotEmpty should mark test as failed") + } + }) +} + +func TestAssertionsFileNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.FileNotEmptyf(filepath.Join(testDataPath(), "existing_file"), "test message") + if !result { + t.Error("Assertions.FileNotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.FileNotEmptyf(filepath.Join(testDataPath(), "empty_file"), "test message") + if result { + t.Error("Assertions.FileNotEmpty should return false on failure") + } + if !mock.failed { + t.Error("Assertions.FileNotEmpty should mark test as failed") + } + }) +} + +func TestAssertionsGreater(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Greater(2, 1) + if !result { + t.Error("Assertions.Greater should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Greater(1, 2) + if result { + t.Error("Assertions.Greater should return false on failure") + } + if !mock.failed { + t.Error("Greater should mark test as failed") + } + }) +} + +func TestAssertionsGreaterf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Greaterf(2, 1, "test message") + if !result { + t.Error("Assertions.Greater should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Greaterf(1, 2, "test message") + if result { + t.Error("Assertions.Greater should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Greater should mark test as failed") + } + }) +} + +func TestAssertionsGreaterOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.GreaterOrEqual(2, 1) + if !result { + t.Error("Assertions.GreaterOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.GreaterOrEqual(1, 2) + if result { + t.Error("Assertions.GreaterOrEqual should return false on failure") + } + if !mock.failed { + t.Error("GreaterOrEqual should mark test as failed") + } + }) +} + +func TestAssertionsGreaterOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.GreaterOrEqualf(2, 1, "test message") + if !result { + t.Error("Assertions.GreaterOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.GreaterOrEqualf(1, 2, "test message") + if result { + t.Error("Assertions.GreaterOrEqual should return false on failure") + } + if !mock.failed { + t.Error("Assertions.GreaterOrEqual should mark test as failed") + } + }) +} + +func TestAssertionsHTTPBodyContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPBodyContains(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + if !result { + t.Error("Assertions.HTTPBodyContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPBodyContains(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!") + if result { + t.Error("Assertions.HTTPBodyContains should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyContains should mark test as failed") + } + }) +} + +func TestAssertionsHTTPBodyContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPBodyContainsf(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!", "test message") + if !result { + t.Error("Assertions.HTTPBodyContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPBodyContainsf(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!", "test message") + if result { + t.Error("Assertions.HTTPBodyContains should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPBodyContains should mark test as failed") + } + }) +} + +func TestAssertionsHTTPBodyNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPBodyNotContains(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + if !result { + t.Error("Assertions.HTTPBodyNotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPBodyNotContains(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!") + if result { + t.Error("Assertions.HTTPBodyNotContains should return false on failure") + } + if !mock.failed { + t.Error("HTTPBodyNotContains should mark test as failed") + } + }) +} + +func TestAssertionsHTTPBodyNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPBodyNotContainsf(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!", "test message") + if !result { + t.Error("Assertions.HTTPBodyNotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPBodyNotContainsf(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!", "test message") + if result { + t.Error("Assertions.HTTPBodyNotContains should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPBodyNotContains should mark test as failed") + } + }) +} + +func TestAssertionsHTTPError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPError(httpError, "GET", "/", nil) + if !result { + t.Error("Assertions.HTTPError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPError(httpOK, "GET", "/", nil) + if result { + t.Error("Assertions.HTTPError should return false on failure") + } + if !mock.failed { + t.Error("HTTPError should mark test as failed") + } + }) +} + +func TestAssertionsHTTPErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPErrorf(httpError, "GET", "/", nil, "test message") + if !result { + t.Error("Assertions.HTTPError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPErrorf(httpOK, "GET", "/", nil, "test message") + if result { + t.Error("Assertions.HTTPError should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPError should mark test as failed") + } + }) +} + +func TestAssertionsHTTPRedirect(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPRedirect(httpRedirect, "GET", "/", nil) + if !result { + t.Error("Assertions.HTTPRedirect should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPRedirect(httpError, "GET", "/", nil) + if result { + t.Error("Assertions.HTTPRedirect should return false on failure") + } + if !mock.failed { + t.Error("HTTPRedirect should mark test as failed") + } + }) +} + +func TestAssertionsHTTPRedirectf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPRedirectf(httpRedirect, "GET", "/", nil, "test message") + if !result { + t.Error("Assertions.HTTPRedirect should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPRedirectf(httpError, "GET", "/", nil, "test message") + if result { + t.Error("Assertions.HTTPRedirect should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPRedirect should mark test as failed") + } + }) +} + +func TestAssertionsHTTPStatusCode(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPStatusCode(httpOK, "GET", "/", nil, http.StatusOK) + if !result { + t.Error("Assertions.HTTPStatusCode should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPStatusCode(httpError, "GET", "/", nil, http.StatusOK) + if result { + t.Error("Assertions.HTTPStatusCode should return false on failure") + } + if !mock.failed { + t.Error("HTTPStatusCode should mark test as failed") + } + }) +} + +func TestAssertionsHTTPStatusCodef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPStatusCodef(httpOK, "GET", "/", nil, http.StatusOK, "test message") + if !result { + t.Error("Assertions.HTTPStatusCode should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPStatusCodef(httpError, "GET", "/", nil, http.StatusOK, "test message") + if result { + t.Error("Assertions.HTTPStatusCode should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPStatusCode should mark test as failed") + } + }) +} + +func TestAssertionsHTTPSuccess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPSuccess(httpOK, "GET", "/", nil) + if !result { + t.Error("Assertions.HTTPSuccess should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPSuccess(httpError, "GET", "/", nil) + if result { + t.Error("Assertions.HTTPSuccess should return false on failure") + } + if !mock.failed { + t.Error("HTTPSuccess should mark test as failed") + } + }) +} + +func TestAssertionsHTTPSuccessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.HTTPSuccessf(httpOK, "GET", "/", nil, "test message") + if !result { + t.Error("Assertions.HTTPSuccess should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.HTTPSuccessf(httpError, "GET", "/", nil, "test message") + if result { + t.Error("Assertions.HTTPSuccess should return false on failure") + } + if !mock.failed { + t.Error("Assertions.HTTPSuccess should mark test as failed") + } + }) +} + +func TestAssertionsImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Implements(ptr(dummyInterface), new(testing.T)) + if !result { + t.Error("Assertions.Implements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Implements((*error)(nil), new(testing.T)) + if result { + t.Error("Assertions.Implements should return false on failure") + } + if !mock.failed { + t.Error("Implements should mark test as failed") + } + }) +} + +func TestAssertionsImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Implementsf(ptr(dummyInterface), new(testing.T), "test message") + if !result { + t.Error("Assertions.Implements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Implementsf((*error)(nil), new(testing.T), "test message") + if result { + t.Error("Assertions.Implements should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Implements should mark test as failed") + } + }) +} + +func TestAssertionsInDelta(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDelta(1.0, 1.01, 0.02) + if !result { + t.Error("Assertions.InDelta should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDelta(1.0, 1.1, 0.05) + if result { + t.Error("Assertions.InDelta should return false on failure") + } + if !mock.failed { + t.Error("InDelta should mark test as failed") + } + }) +} + +func TestAssertionsInDeltaf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDeltaf(1.0, 1.01, 0.02, "test message") + if !result { + t.Error("Assertions.InDelta should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDeltaf(1.0, 1.1, 0.05, "test message") + if result { + t.Error("Assertions.InDelta should return false on failure") + } + if !mock.failed { + t.Error("Assertions.InDelta should mark test as failed") + } + }) +} + +func TestAssertionsInDeltaMapValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDeltaMapValues(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + if !result { + t.Error("Assertions.InDeltaMapValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDeltaMapValues(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05) + if result { + t.Error("Assertions.InDeltaMapValues should return false on failure") + } + if !mock.failed { + t.Error("InDeltaMapValues should mark test as failed") + } + }) +} + +func TestAssertionsInDeltaMapValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDeltaMapValuesf(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02, "test message") + if !result { + t.Error("Assertions.InDeltaMapValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDeltaMapValuesf(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05, "test message") + if result { + t.Error("Assertions.InDeltaMapValues should return false on failure") + } + if !mock.failed { + t.Error("Assertions.InDeltaMapValues should mark test as failed") + } + }) +} + +func TestAssertionsInDeltaSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDeltaSlice([]float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + if !result { + t.Error("Assertions.InDeltaSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDeltaSlice([]float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05) + if result { + t.Error("Assertions.InDeltaSlice should return false on failure") + } + if !mock.failed { + t.Error("InDeltaSlice should mark test as failed") + } + }) +} + +func TestAssertionsInDeltaSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InDeltaSlicef([]float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02, "test message") + if !result { + t.Error("Assertions.InDeltaSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InDeltaSlicef([]float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05, "test message") + if result { + t.Error("Assertions.InDeltaSlice should return false on failure") + } + if !mock.failed { + t.Error("Assertions.InDeltaSlice should mark test as failed") + } + }) +} + +func TestAssertionsInEpsilon(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InEpsilon(100.0, 101.0, 0.02) + if !result { + t.Error("Assertions.InEpsilon should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InEpsilon(100.0, 110.0, 0.05) + if result { + t.Error("Assertions.InEpsilon should return false on failure") + } + if !mock.failed { + t.Error("InEpsilon should mark test as failed") + } + }) +} + +func TestAssertionsInEpsilonf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InEpsilonf(100.0, 101.0, 0.02, "test message") + if !result { + t.Error("Assertions.InEpsilon should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InEpsilonf(100.0, 110.0, 0.05, "test message") + if result { + t.Error("Assertions.InEpsilon should return false on failure") + } + if !mock.failed { + t.Error("Assertions.InEpsilon should mark test as failed") + } + }) +} + +func TestAssertionsInEpsilonSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InEpsilonSlice([]float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + if !result { + t.Error("Assertions.InEpsilonSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InEpsilonSlice([]float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05) + if result { + t.Error("Assertions.InEpsilonSlice should return false on failure") + } + if !mock.failed { + t.Error("InEpsilonSlice should mark test as failed") + } + }) +} + +func TestAssertionsInEpsilonSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.InEpsilonSlicef([]float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02, "test message") + if !result { + t.Error("Assertions.InEpsilonSlice should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.InEpsilonSlicef([]float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05, "test message") + if result { + t.Error("Assertions.InEpsilonSlice should return false on failure") + } + if !mock.failed { + t.Error("Assertions.InEpsilonSlice should mark test as failed") + } + }) +} + +func TestAssertionsIsDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsDecreasing([]int{3, 2, 1}) + if !result { + t.Error("Assertions.IsDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsDecreasing([]int{1, 2, 3}) + if result { + t.Error("Assertions.IsDecreasing should return false on failure") + } + if !mock.failed { + t.Error("IsDecreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsDecreasingf([]int{3, 2, 1}, "test message") + if !result { + t.Error("Assertions.IsDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsDecreasingf([]int{1, 2, 3}, "test message") + if result { + t.Error("Assertions.IsDecreasing should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsDecreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsIncreasing([]int{1, 2, 3}) + if !result { + t.Error("Assertions.IsIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsIncreasing([]int{1, 1, 2}) + if result { + t.Error("Assertions.IsIncreasing should return false on failure") + } + if !mock.failed { + t.Error("IsIncreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsIncreasingf([]int{1, 2, 3}, "test message") + if !result { + t.Error("Assertions.IsIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsIncreasingf([]int{1, 1, 2}, "test message") + if result { + t.Error("Assertions.IsIncreasing should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsIncreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsNonDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNonDecreasing([]int{1, 1, 2}) + if !result { + t.Error("Assertions.IsNonDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNonDecreasing([]int{2, 1, 1}) + if result { + t.Error("Assertions.IsNonDecreasing should return false on failure") + } + if !mock.failed { + t.Error("IsNonDecreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsNonDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNonDecreasingf([]int{1, 1, 2}, "test message") + if !result { + t.Error("Assertions.IsNonDecreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNonDecreasingf([]int{2, 1, 1}, "test message") + if result { + t.Error("Assertions.IsNonDecreasing should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsNonDecreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsNonIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNonIncreasing([]int{2, 1, 1}) + if !result { + t.Error("Assertions.IsNonIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNonIncreasing([]int{1, 2, 3}) + if result { + t.Error("Assertions.IsNonIncreasing should return false on failure") + } + if !mock.failed { + t.Error("IsNonIncreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsNonIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNonIncreasingf([]int{2, 1, 1}, "test message") + if !result { + t.Error("Assertions.IsNonIncreasing should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNonIncreasingf([]int{1, 2, 3}, "test message") + if result { + t.Error("Assertions.IsNonIncreasing should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsNonIncreasing should mark test as failed") + } + }) +} + +func TestAssertionsIsNotType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNotType(int32(123), int64(456)) + if !result { + t.Error("Assertions.IsNotType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNotType(123, 456) + if result { + t.Error("Assertions.IsNotType should return false on failure") + } + if !mock.failed { + t.Error("IsNotType should mark test as failed") + } + }) +} + +func TestAssertionsIsNotTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsNotTypef(int32(123), int64(456), "test message") + if !result { + t.Error("Assertions.IsNotType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsNotTypef(123, 456, "test message") + if result { + t.Error("Assertions.IsNotType should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsNotType should mark test as failed") + } + }) +} + +func TestAssertionsIsType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsType(123, 456) + if !result { + t.Error("Assertions.IsType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsType(int32(123), int64(456)) + if result { + t.Error("Assertions.IsType should return false on failure") + } + if !mock.failed { + t.Error("IsType should mark test as failed") + } + }) +} + +func TestAssertionsIsTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.IsTypef(123, 456, "test message") + if !result { + t.Error("Assertions.IsType should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.IsTypef(int32(123), int64(456), "test message") + if result { + t.Error("Assertions.IsType should return false on failure") + } + if !mock.failed { + t.Error("Assertions.IsType should mark test as failed") + } + }) +} + +func TestAssertionsJSONEq(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + if !result { + t.Error("Assertions.JSONEq should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.JSONEq(`{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`) + if result { + t.Error("Assertions.JSONEq should return false on failure") + } + if !mock.failed { + t.Error("JSONEq should mark test as failed") + } + }) +} + +func TestAssertionsJSONEqf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "test message") + if !result { + t.Error("Assertions.JSONEq should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`, "test message") + if result { + t.Error("Assertions.JSONEq should return false on failure") + } + if !mock.failed { + t.Error("Assertions.JSONEq should mark test as failed") + } + }) +} + +func TestAssertionsJSONEqBytes(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + if !result { + t.Error("Assertions.JSONEqBytes should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`)) + if result { + t.Error("Assertions.JSONEqBytes should return false on failure") + } + if !mock.failed { + t.Error("JSONEqBytes should mark test as failed") + } + }) +} + +func TestAssertionsJSONEqBytesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "test message") + if !result { + t.Error("Assertions.JSONEqBytes should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`), "test message") + if result { + t.Error("Assertions.JSONEqBytes should return false on failure") + } + if !mock.failed { + t.Error("Assertions.JSONEqBytes should mark test as failed") + } + }) +} + +func TestAssertionsLen(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Len([]string{"A", "B"}, 2) + if !result { + t.Error("Assertions.Len should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Len([]string{"A", "B"}, 1) + if result { + t.Error("Assertions.Len should return false on failure") + } + if !mock.failed { + t.Error("Len should mark test as failed") + } + }) +} + +func TestAssertionsLenf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Lenf([]string{"A", "B"}, 2, "test message") + if !result { + t.Error("Assertions.Len should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Lenf([]string{"A", "B"}, 1, "test message") + if result { + t.Error("Assertions.Len should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Len should mark test as failed") + } + }) +} + +func TestAssertionsLess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Less(1, 2) + if !result { + t.Error("Assertions.Less should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Less(2, 1) + if result { + t.Error("Assertions.Less should return false on failure") + } + if !mock.failed { + t.Error("Less should mark test as failed") + } + }) +} + +func TestAssertionsLessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Lessf(1, 2, "test message") + if !result { + t.Error("Assertions.Less should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Lessf(2, 1, "test message") + if result { + t.Error("Assertions.Less should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Less should mark test as failed") + } + }) +} + +func TestAssertionsLessOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.LessOrEqual(1, 2) + if !result { + t.Error("Assertions.LessOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.LessOrEqual(2, 1) + if result { + t.Error("Assertions.LessOrEqual should return false on failure") + } + if !mock.failed { + t.Error("LessOrEqual should mark test as failed") + } + }) +} + +func TestAssertionsLessOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.LessOrEqualf(1, 2, "test message") + if !result { + t.Error("Assertions.LessOrEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.LessOrEqualf(2, 1, "test message") + if result { + t.Error("Assertions.LessOrEqual should return false on failure") + } + if !mock.failed { + t.Error("Assertions.LessOrEqual should mark test as failed") + } + }) +} + +func TestAssertionsNegative(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Negative(-1) + if !result { + t.Error("Assertions.Negative should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Negative(1) + if result { + t.Error("Assertions.Negative should return false on failure") + } + if !mock.failed { + t.Error("Negative should mark test as failed") + } + }) +} + +func TestAssertionsNegativef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Negativef(-1, "test message") + if !result { + t.Error("Assertions.Negative should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Negativef(1, "test message") + if result { + t.Error("Assertions.Negative should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Negative should mark test as failed") + } + }) +} + +func TestAssertionsNever(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Never(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + if !result { + t.Error("Assertions.Never should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Never(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + if result { + t.Error("Assertions.Never should return false on failure") + } + if !mock.failed { + t.Error("Never should mark test as failed") + } + }) +} + +func TestAssertionsNeverf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Neverf(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if !result { + t.Error("Assertions.Never should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Neverf(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + if result { + t.Error("Assertions.Never should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Never should mark test as failed") + } + }) +} + +func TestAssertionsNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Nil(nil) + if !result { + t.Error("Assertions.Nil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Nil("not nil") + if result { + t.Error("Assertions.Nil should return false on failure") + } + if !mock.failed { + t.Error("Nil should mark test as failed") + } + }) +} + +func TestAssertionsNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Nilf(nil, "test message") + if !result { + t.Error("Assertions.Nil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Nilf("not nil", "test message") + if result { + t.Error("Assertions.Nil should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Nil should mark test as failed") + } + }) +} + +func TestAssertionsNoDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoDirExists(filepath.Join(testDataPath(), "non_existing_dir")) + if !result { + t.Error("Assertions.NoDirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoDirExists(filepath.Join(testDataPath(), "existing_dir")) + if result { + t.Error("Assertions.NoDirExists should return false on failure") + } + if !mock.failed { + t.Error("NoDirExists should mark test as failed") + } + }) +} + +func TestAssertionsNoDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoDirExistsf(filepath.Join(testDataPath(), "non_existing_dir"), "test message") + if !result { + t.Error("Assertions.NoDirExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoDirExistsf(filepath.Join(testDataPath(), "existing_dir"), "test message") + if result { + t.Error("Assertions.NoDirExists should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NoDirExists should mark test as failed") + } + }) +} + +func TestAssertionsNoError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoError(nil) + if !result { + t.Error("Assertions.NoError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoError(ErrTest) + if result { + t.Error("Assertions.NoError should return false on failure") + } + if !mock.failed { + t.Error("NoError should mark test as failed") + } + }) +} + +func TestAssertionsNoErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoErrorf(nil, "test message") + if !result { + t.Error("Assertions.NoError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoErrorf(ErrTest, "test message") + if result { + t.Error("Assertions.NoError should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NoError should mark test as failed") + } + }) +} + +func TestAssertionsNoFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoFileExists(filepath.Join(testDataPath(), "non_existing_file")) + if !result { + t.Error("Assertions.NoFileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoFileExists(filepath.Join(testDataPath(), "existing_file")) + if result { + t.Error("Assertions.NoFileExists should return false on failure") + } + if !mock.failed { + t.Error("NoFileExists should mark test as failed") + } + }) +} + +func TestAssertionsNoFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NoFileExistsf(filepath.Join(testDataPath(), "non_existing_file"), "test message") + if !result { + t.Error("Assertions.NoFileExists should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NoFileExistsf(filepath.Join(testDataPath(), "existing_file"), "test message") + if result { + t.Error("Assertions.NoFileExists should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NoFileExists should mark test as failed") + } + }) +} + +func TestAssertionsNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotContains([]string{"A", "B"}, "C") + if !result { + t.Error("Assertions.NotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotContains([]string{"A", "B"}, "B") + if result { + t.Error("Assertions.NotContains should return false on failure") + } + if !mock.failed { + t.Error("NotContains should mark test as failed") + } + }) +} + +func TestAssertionsNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotContainsf([]string{"A", "B"}, "C", "test message") + if !result { + t.Error("Assertions.NotContains should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotContainsf([]string{"A", "B"}, "B", "test message") + if result { + t.Error("Assertions.NotContains should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotContains should mark test as failed") + } + }) +} + +func TestAssertionsNotElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotElementsMatch([]int{1, 2, 3}, []int{1, 2, 4}) + if !result { + t.Error("Assertions.NotElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotElementsMatch([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + if result { + t.Error("Assertions.NotElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("NotElementsMatch should mark test as failed") + } + }) +} + +func TestAssertionsNotElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotElementsMatchf([]int{1, 2, 3}, []int{1, 2, 4}, "test message") + if !result { + t.Error("Assertions.NotElementsMatch should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotElementsMatchf([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + if result { + t.Error("Assertions.NotElementsMatch should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotElementsMatch should mark test as failed") + } + }) +} + +func TestAssertionsNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEmpty("not empty") + if !result { + t.Error("Assertions.NotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEmpty("") + if result { + t.Error("Assertions.NotEmpty should return false on failure") + } + if !mock.failed { + t.Error("NotEmpty should mark test as failed") + } + }) +} + +func TestAssertionsNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEmptyf("not empty", "test message") + if !result { + t.Error("Assertions.NotEmpty should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEmptyf("", "test message") + if result { + t.Error("Assertions.NotEmpty should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotEmpty should mark test as failed") + } + }) +} + +func TestAssertionsNotEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEqual(123, 456) + if !result { + t.Error("Assertions.NotEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEqual(123, 123) + if result { + t.Error("Assertions.NotEqual should return false on failure") + } + if !mock.failed { + t.Error("NotEqual should mark test as failed") + } + }) +} + +func TestAssertionsNotEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEqualf(123, 456, "test message") + if !result { + t.Error("Assertions.NotEqual should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEqualf(123, 123, "test message") + if result { + t.Error("Assertions.NotEqual should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotEqual should mark test as failed") + } + }) +} + +func TestAssertionsNotEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEqualValues(uint32(123), int32(456)) + if !result { + t.Error("Assertions.NotEqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEqualValues(uint32(123), int32(123)) + if result { + t.Error("Assertions.NotEqualValues should return false on failure") + } + if !mock.failed { + t.Error("NotEqualValues should mark test as failed") + } + }) +} + +func TestAssertionsNotEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotEqualValuesf(uint32(123), int32(456), "test message") + if !result { + t.Error("Assertions.NotEqualValues should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotEqualValuesf(uint32(123), int32(123), "test message") + if result { + t.Error("Assertions.NotEqualValues should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotEqualValues should mark test as failed") + } + }) +} + +func TestAssertionsNotErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotErrorAs(ErrTest, new(*dummyError)) + if !result { + t.Error("Assertions.NotErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotErrorAs(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + if result { + t.Error("Assertions.NotErrorAs should return false on failure") + } + if !mock.failed { + t.Error("NotErrorAs should mark test as failed") + } + }) +} + +func TestAssertionsNotErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotErrorAsf(ErrTest, new(*dummyError), "test message") + if !result { + t.Error("Assertions.NotErrorAs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotErrorAsf(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + if result { + t.Error("Assertions.NotErrorAs should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotErrorAs should mark test as failed") + } + }) +} + +func TestAssertionsNotErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotErrorIs(ErrTest, io.EOF) + if !result { + t.Error("Assertions.NotErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotErrorIs(fmt.Errorf("wrap: %w", io.EOF), io.EOF) + if result { + t.Error("Assertions.NotErrorIs should return false on failure") + } + if !mock.failed { + t.Error("NotErrorIs should mark test as failed") + } + }) +} + +func TestAssertionsNotErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotErrorIsf(ErrTest, io.EOF, "test message") + if !result { + t.Error("Assertions.NotErrorIs should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotErrorIsf(fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + if result { + t.Error("Assertions.NotErrorIs should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotErrorIs should mark test as failed") + } + }) +} + +func TestAssertionsNotImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotImplements((*error)(nil), new(testing.T)) + if !result { + t.Error("Assertions.NotImplements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotImplements(ptr(dummyInterface), new(testing.T)) + if result { + t.Error("Assertions.NotImplements should return false on failure") + } + if !mock.failed { + t.Error("NotImplements should mark test as failed") + } + }) +} + +func TestAssertionsNotImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotImplementsf((*error)(nil), new(testing.T), "test message") + if !result { + t.Error("Assertions.NotImplements should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotImplementsf(ptr(dummyInterface), new(testing.T), "test message") + if result { + t.Error("Assertions.NotImplements should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotImplements should mark test as failed") + } + }) +} + +func TestAssertionsNotNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotNil("not nil") + if !result { + t.Error("Assertions.NotNil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotNil(nil) + if result { + t.Error("Assertions.NotNil should return false on failure") + } + if !mock.failed { + t.Error("NotNil should mark test as failed") + } + }) +} + +func TestAssertionsNotNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotNilf("not nil", "test message") + if !result { + t.Error("Assertions.NotNil should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotNilf(nil, "test message") + if result { + t.Error("Assertions.NotNil should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotNil should mark test as failed") + } + }) +} + +func TestAssertionsNotPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotPanics(func() {}) + if !result { + t.Error("Assertions.NotPanics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotPanics(func() { panic("panicking") }) + if result { + t.Error("Assertions.NotPanics should return false on failure") + } + if !mock.failed { + t.Error("NotPanics should mark test as failed") + } + }) +} + +func TestAssertionsNotPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotPanicsf(func() {}, "test message") + if !result { + t.Error("Assertions.NotPanics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotPanicsf(func() { panic("panicking") }, "test message") + if result { + t.Error("Assertions.NotPanics should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotPanics should mark test as failed") + } + }) +} + +func TestAssertionsNotRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotRegexp("^start", "not starting") + if !result { + t.Error("Assertions.NotRegexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotRegexp("^start", "starting") + if result { + t.Error("Assertions.NotRegexp should return false on failure") + } + if !mock.failed { + t.Error("NotRegexp should mark test as failed") + } + }) +} + +func TestAssertionsNotRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotRegexpf("^start", "not starting", "test message") + if !result { + t.Error("Assertions.NotRegexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotRegexpf("^start", "starting", "test message") + if result { + t.Error("Assertions.NotRegexp should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotRegexp should mark test as failed") + } + }) +} + +func TestAssertionsNotSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotSame(&staticVar, ptr("static string")) + if !result { + t.Error("Assertions.NotSame should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotSame(&staticVar, staticVarPtr) + if result { + t.Error("Assertions.NotSame should return false on failure") + } + if !mock.failed { + t.Error("NotSame should mark test as failed") + } + }) +} + +func TestAssertionsNotSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotSamef(&staticVar, ptr("static string"), "test message") + if !result { + t.Error("Assertions.NotSame should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotSamef(&staticVar, staticVarPtr, "test message") + if result { + t.Error("Assertions.NotSame should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotSame should mark test as failed") + } + }) +} + +func TestAssertionsNotSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotSubset([]int{1, 2, 3}, []int{4, 5}) + if !result { + t.Error("Assertions.NotSubset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotSubset([]int{1, 2, 3}, []int{1, 2}) + if result { + t.Error("Assertions.NotSubset should return false on failure") + } + if !mock.failed { + t.Error("NotSubset should mark test as failed") + } + }) +} + +func TestAssertionsNotSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotSubsetf([]int{1, 2, 3}, []int{4, 5}, "test message") + if !result { + t.Error("Assertions.NotSubset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotSubsetf([]int{1, 2, 3}, []int{1, 2}, "test message") + if result { + t.Error("Assertions.NotSubset should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotSubset should mark test as failed") + } + }) +} + +func TestAssertionsNotZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotZero(1) + if !result { + t.Error("Assertions.NotZero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotZero(0) + if result { + t.Error("Assertions.NotZero should return false on failure") + } + if !mock.failed { + t.Error("NotZero should mark test as failed") + } + }) +} + +func TestAssertionsNotZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.NotZerof(1, "test message") + if !result { + t.Error("Assertions.NotZero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.NotZerof(0, "test message") + if result { + t.Error("Assertions.NotZero should return false on failure") + } + if !mock.failed { + t.Error("Assertions.NotZero should mark test as failed") + } + }) +} + +func TestAssertionsPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Panics(func() { panic("panicking") }) + if !result { + t.Error("Assertions.Panics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Panics(func() {}) + if result { + t.Error("Assertions.Panics should return false on failure") + } + if !mock.failed { + t.Error("Panics should mark test as failed") + } + }) +} + +func TestAssertionsPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Panicsf(func() { panic("panicking") }, "test message") + if !result { + t.Error("Assertions.Panics should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Panicsf(func() {}, "test message") + if result { + t.Error("Assertions.Panics should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Panics should mark test as failed") + } + }) +} + +func TestAssertionsPanicsWithError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.PanicsWithError(ErrTest.Error(), func() { panic(ErrTest) }) + if !result { + t.Error("Assertions.PanicsWithError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.PanicsWithError(ErrTest.Error(), func() {}) + if result { + t.Error("Assertions.PanicsWithError should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithError should mark test as failed") + } + }) +} + +func TestAssertionsPanicsWithErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.PanicsWithErrorf(ErrTest.Error(), func() { panic(ErrTest) }, "test message") + if !result { + t.Error("Assertions.PanicsWithError should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.PanicsWithErrorf(ErrTest.Error(), func() {}, "test message") + if result { + t.Error("Assertions.PanicsWithError should return false on failure") + } + if !mock.failed { + t.Error("Assertions.PanicsWithError should mark test as failed") + } + }) +} + +func TestAssertionsPanicsWithValue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.PanicsWithValue("panicking", func() { panic("panicking") }) + if !result { + t.Error("Assertions.PanicsWithValue should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.PanicsWithValue("panicking", func() {}) + if result { + t.Error("Assertions.PanicsWithValue should return false on failure") + } + if !mock.failed { + t.Error("PanicsWithValue should mark test as failed") + } + }) +} + +func TestAssertionsPanicsWithValuef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.PanicsWithValuef("panicking", func() { panic("panicking") }, "test message") + if !result { + t.Error("Assertions.PanicsWithValue should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.PanicsWithValuef("panicking", func() {}, "test message") + if result { + t.Error("Assertions.PanicsWithValue should return false on failure") + } + if !mock.failed { + t.Error("Assertions.PanicsWithValue should mark test as failed") + } + }) +} + +func TestAssertionsPositive(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Positive(1) + if !result { + t.Error("Assertions.Positive should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Positive(-1) + if result { + t.Error("Assertions.Positive should return false on failure") + } + if !mock.failed { + t.Error("Positive should mark test as failed") + } + }) +} + +func TestAssertionsPositivef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Positivef(1, "test message") + if !result { + t.Error("Assertions.Positive should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Positivef(-1, "test message") + if result { + t.Error("Assertions.Positive should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Positive should mark test as failed") + } + }) +} + +func TestAssertionsRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Regexp("^start", "starting") + if !result { + t.Error("Assertions.Regexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Regexp("^start", "not starting") + if result { + t.Error("Assertions.Regexp should return false on failure") + } + if !mock.failed { + t.Error("Regexp should mark test as failed") + } + }) +} + +func TestAssertionsRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Regexpf("^start", "starting", "test message") + if !result { + t.Error("Assertions.Regexp should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Regexpf("^start", "not starting", "test message") + if result { + t.Error("Assertions.Regexp should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Regexp should mark test as failed") + } + }) +} + +func TestAssertionsSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Same(&staticVar, staticVarPtr) + if !result { + t.Error("Assertions.Same should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Same(&staticVar, ptr("static string")) + if result { + t.Error("Assertions.Same should return false on failure") + } + if !mock.failed { + t.Error("Same should mark test as failed") + } + }) +} + +func TestAssertionsSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Samef(&staticVar, staticVarPtr, "test message") + if !result { + t.Error("Assertions.Same should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Samef(&staticVar, ptr("static string"), "test message") + if result { + t.Error("Assertions.Same should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Same should mark test as failed") + } + }) +} + +func TestAssertionsSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Subset([]int{1, 2, 3}, []int{1, 2}) + if !result { + t.Error("Assertions.Subset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Subset([]int{1, 2, 3}, []int{4, 5}) + if result { + t.Error("Assertions.Subset should return false on failure") + } + if !mock.failed { + t.Error("Subset should mark test as failed") + } + }) +} + +func TestAssertionsSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Subsetf([]int{1, 2, 3}, []int{1, 2}, "test message") + if !result { + t.Error("Assertions.Subset should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Subsetf([]int{1, 2, 3}, []int{4, 5}, "test message") + if result { + t.Error("Assertions.Subset should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Subset should mark test as failed") + } + }) +} + +func TestAssertionsTrue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.True(1 == 1) + if !result { + t.Error("Assertions.True should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.True(1 == 0) + if result { + t.Error("Assertions.True should return false on failure") + } + if !mock.failed { + t.Error("True should mark test as failed") + } + }) +} + +func TestAssertionsTruef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Truef(1 == 1, "test message") + if !result { + t.Error("Assertions.True should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Truef(1 == 0, "test message") + if result { + t.Error("Assertions.True should return false on failure") + } + if !mock.failed { + t.Error("Assertions.True should mark test as failed") + } + }) +} + +func TestAssertionsWithinDuration(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.WithinDuration(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + if !result { + t.Error("Assertions.WithinDuration should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.WithinDuration(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second) + if result { + t.Error("Assertions.WithinDuration should return false on failure") + } + if !mock.failed { + t.Error("WithinDuration should mark test as failed") + } + }) +} + +func TestAssertionsWithinDurationf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.WithinDurationf(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second, "test message") + if !result { + t.Error("Assertions.WithinDuration should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.WithinDurationf(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second, "test message") + if result { + t.Error("Assertions.WithinDuration should return false on failure") + } + if !mock.failed { + t.Error("Assertions.WithinDuration should mark test as failed") + } + }) +} + +func TestAssertionsWithinRange(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.WithinRange(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + if !result { + t.Error("Assertions.WithinRange should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.WithinRange(time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + if result { + t.Error("Assertions.WithinRange should return false on failure") + } + if !mock.failed { + t.Error("WithinRange should mark test as failed") + } + }) +} + +func TestAssertionsWithinRangef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.WithinRangef(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + if !result { + t.Error("Assertions.WithinRange should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.WithinRangef(time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + if result { + t.Error("Assertions.WithinRange should return false on failure") + } + if !mock.failed { + t.Error("Assertions.WithinRange should mark test as failed") + } + }) +} + +func TestAssertionsYAMLEq(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.YAMLEq("key: value", "key: value") + }, "should panic without the yaml feature enabled") + }) +} + +func TestAssertionsYAMLEqf(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.YAMLEqf("key: value", "key: value", "test message") + }, "should panic without the yaml feature enabled") + }) +} + +func TestAssertionsZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Zero(0) + if !result { + t.Error("Assertions.Zero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Zero(1) + if result { + t.Error("Assertions.Zero should return false on failure") + } + if !mock.failed { + t.Error("Zero should mark test as failed") + } + }) +} + +func TestAssertionsZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + result := a.Zerof(0, "test message") + if !result { + t.Error("Assertions.Zero should return true on success") + } + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockT) + a := New(mock) + result := a.Zerof(1, "test message") + if result { + t.Error("Assertions.Zero should return false on failure") + } + if !mock.failed { + t.Error("Assertions.Zero should mark test as failed") + } + }) +} diff --git a/assert/assert_helpers.go b/assert/assert_helpers.go new file mode 100644 index 000000000..9abad028e --- /dev/null +++ b/assert/assert_helpers.go @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "net/http" + "net/url" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// 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 { + return assertions.CallerInfo() +} + +// HTTPBody is a helper that returns the HTTP body of the response. +// It returns the empty string if building a new request fails. +func HTTPBody(handler http.HandlerFunc, method string, url string, values url.Values) string { + return assertions.HTTPBody(handler, method, url, values) +} + +// ObjectsAreEqual determines if two objects are considered equal. +// +// This function does no assertion of any kind. +func ObjectsAreEqual(expected any, actual any) bool { + return assertions.ObjectsAreEqual(expected, actual) +} + +// ObjectsAreEqualValues gets whether two objects are equal, or if their +// values are equal. +func ObjectsAreEqualValues(expected any, actual any) bool { + return assertions.ObjectsAreEqualValues(expected, actual) +} + +// 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 any, actual any) bool { + return assertions.ObjectsExportedFieldsAreEqual(expected, actual) +} diff --git a/assert/assert_helpers_test.go b/assert/assert_helpers_test.go new file mode 100644 index 000000000..2462d7469 --- /dev/null +++ b/assert/assert_helpers_test.go @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "testing" +) + +func TestCallerInfof(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestHTTPBodyf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsAreEqualf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsAreEqualValuesf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsExportedFieldsAreEqualf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} diff --git a/assert/assert_types.go b/assert/assert_types.go new file mode 100644 index 000000000..3d872082f --- /dev/null +++ b/assert/assert_types.go @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package assert + +import ( + "github.com/go-openapi/testify/v2/internal/assertions" +) + +var ( + // ErrTest 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. + ErrTest = assertions.ErrTest +) + +type ( + // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful + // for table driven tests. + BoolAssertionFunc = assertions.BoolAssertionFunc + + // CollectT implements the T interface and collects all errors. + CollectT = assertions.CollectT + + // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it. + CompareType = assertions.CompareType + + // Comparison is a custom function that returns true on success and false on failure. + Comparison = assertions.Comparison + + // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful + // for table driven tests. + ComparisonAssertionFunc = assertions.ComparisonAssertionFunc + + // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful + // for table driven tests. + ErrorAssertionFunc = assertions.ErrorAssertionFunc + + // H is an interface for types that implement the Helper method. + // This allows marking functions as test helpers. + H = assertions.H + + // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful + // for table driven tests. + PanicAssertionFunc = assertions.PanicAssertionFunc + + // 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. + PanicTestFunc = assertions.PanicTestFunc + + // T is an interface wrapper around [testing.T]. + T = assertions.T + + // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful + // for table driven tests. + ValueAssertionFunc = assertions.ValueAssertionFunc +) + +// Type declarations for backward compatibility. +type ( + // TestingT is like [T] and is declared here to remain compatible with previous versions of this package. + // + // Most users should not be affected, as the implementation of [T] that is widely used is [testing.T]. + // + // Deprecated: use [T] as a more concise alternative. + TestingT = T +) diff --git a/assert/assertion_compare_test.go b/assert/assertion_compare_test.go deleted file mode 100644 index 4ab50d6c2..000000000 --- a/assert/assertion_compare_test.go +++ /dev/null @@ -1,474 +0,0 @@ -package assert - -import ( - "bytes" - "fmt" - "iter" - "reflect" - "runtime" - "slices" - "strings" - "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 any - greater any - 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"}, - { - // using time.Local is ok in this context: this is precisely the goal of this test - less: time.Date(2024, 0, 0, 0, 0, 0, 0, time.Local), //nolint:gosmopolitan // ok. See above - greater: time.Date(2263, 0, 0, 0, 0, 0, 0, time.Local), //nolint:gosmopolitan // ok. See above - 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 %s", currCase.cType) - } - - resEqual, isComparable := compare(currCase.less, currCase.less, reflect.ValueOf(currCase.less).Kind()) - if !isComparable { - t.Errorf("object are comparable for type %s", currCase.cType) - } - - if resEqual != 0 { - t.Errorf("objects should be equal for type %s", currCase.cType) - } - } -} - -type outputT struct { - buf *bytes.Buffer - helpers map[string]struct{} -} - -// Implements TestingT. -func (t *outputT) Errorf(format string, args ...any) { - 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 -} - -type compareFixture struct { - less any - greater any - msg string -} - -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 compareIncreasingFixtures() { - 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/go-openapi/testify/v2/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 compareIncreasingFixtures() { - out := &outputT{buf: bytes.NewBuffer(nil)} - False(t, GreaterOrEqual(out, currCase.less, currCase.greater)) - Contains(t, out.buf.String(), strings.ReplaceAll(currCase.msg, "than", "than or equal to")) - Contains(t, out.helpers, "github.com/go-openapi/testify/v2/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 compareIncreasingFixtures3() { - 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/go-openapi/testify/v2/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 compareIncreasingFixtures3() { - out := &outputT{buf: bytes.NewBuffer(nil)} - False(t, LessOrEqual(out, currCase.greater, currCase.less)) - Contains(t, out.buf.String(), strings.ReplaceAll(currCase.msg, "than", "than or equal to")) - Contains(t, out.helpers, "github.com/go-openapi/testify/v2/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 any - 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/go-openapi/testify/v2/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 any - 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/go-openapi/testify/v2/assert.Negative") - } -} - -func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) { - t.Parallel() - - mockT := new(testing.T) - - for _, currCase := range []struct { - v1 any - v2 any - 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 any - v2 any - }{ - {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 any - v2 any - 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 := []any{"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) - } -} - -//nolint:dupl // factoring further the message to save a little duplication would make the test harder to read -func compareIncreasingFixtures() iter.Seq[compareFixture] { - return slices.Values( - []compareFixture{ - {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]"`}, - }, - ) -} - -//nolint:dupl // factoring further the message to save a little duplication would make the test harder to read -func compareIncreasingFixtures3() iter.Seq[compareFixture] { - return slices.Values( - []compareFixture{ - {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]"`}, - }, - ) -} diff --git a/assert/assertion_format.go b/assert/assertion_format.go deleted file mode 100644 index 729b8f439..000000000 --- a/assert/assertion_format.go +++ /dev/null @@ -1,906 +0,0 @@ -// Code generated with github.com/go-openapi/testify/v2/_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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Condition(t, comp, append([]any{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 any, contains any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Contains(t, s, contains, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return DirExists(t, path, append([]any{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 any, listB any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return ElementsMatch(t, listA, listB, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Empty(t, object, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Equal(t, expected, actual, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EqualError(t, theError, errString, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EqualExportedValues(t, expected, actual, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EqualValues(t, expected, actual, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Error(t, err, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return ErrorAs(t, err, target, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return ErrorContains(t, theError, contains, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return ErrorIs(t, err, target, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Eventually(t, condition, waitFor, tick, append([]any{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, "error message %s", "formatted") { -// // 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 EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return EventuallyWithT(t, condition, waitFor, tick, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Exactly(t, expected, actual, append([]any{msg}, args...)...) -} - -// Failf reports a failure through. -func Failf(t TestingT, failureMessage string, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Fail(t, failureMessage, append([]any{msg}, args...)...) -} - -// FailNowf fails test. -func FailNowf(t TestingT, failureMessage string, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return FailNow(t, failureMessage, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return False(t, value, append([]any{msg}, args...)...) -} - -// FileEmptyf checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func FileEmptyf(t TestingT, path string, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return FileEmpty(t, path, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return FileExists(t, path, append([]any{msg}, args...)...) -} - -// FileNotEmptyf checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func FileNotEmptyf(t TestingT, path string, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return FileNotEmpty(t, path, append([]any{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 any, e2 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Greater(t, e1, e2, append([]any{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 any, e2 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return GreaterOrEqual(t, e1, e2, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPBodyContains(t, handler, method, url, values, str, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPBodyNotContains(t, handler, method, url, values, str, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPError(t, handler, method, url, values, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPRedirect(t, handler, method, url, values, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return HTTPSuccess(t, handler, method, url, values, append([]any{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 any, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Implements(t, interfaceObject, object, append([]any{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 any, actual any, delta float64, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return InDelta(t, expected, actual, delta, append([]any{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 any, actual any, delta float64, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return InDeltaMapValues(t, expected, actual, delta, append([]any{msg}, args...)...) -} - -// InDeltaSlicef is the same as InDelta, except it compares two slices. -func InDeltaSlicef(t TestingT, expected any, actual any, delta float64, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return InDeltaSlice(t, expected, actual, delta, append([]any{msg}, args...)...) -} - -// InEpsilonf asserts that expected and actual have a relative error less than epsilon. -func InEpsilonf(t TestingT, expected any, actual any, epsilon float64, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return InEpsilon(t, expected, actual, epsilon, append([]any{msg}, args...)...) -} - -// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. -func InEpsilonSlicef(t TestingT, expected any, actual any, epsilon float64, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return InEpsilonSlice(t, expected, actual, epsilon, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsDecreasing(t, object, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsIncreasing(t, object, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsNonDecreasing(t, object, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsNonIncreasing(t, object, append([]any{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 any, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsNotType(t, theType, object, append([]any{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 any, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return IsType(t, expectedType, object, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return JSONEq(t, expected, actual, append([]any{msg}, args...)...) -} - -// JSONEqBytesf asserts that two JSON byte slices are equivalent. -// -// assert.JSONEqBytesf(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "error message %s", "formatted") -func JSONEqBytesf(t TestingT, expected []byte, actual []byte, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return JSONEqBytes(t, expected, actual, append([]any{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 any, length int, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Len(t, object, length, append([]any{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 any, e2 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Less(t, e1, e2, append([]any{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 any, e2 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return LessOrEqual(t, e1, e2, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Negative(t, e, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Never(t, condition, waitFor, tick, append([]any{msg}, args...)...) -} - -// Nilf asserts that the specified object is nil. -// -// assert.Nilf(t, err, "error message %s", "formatted") -func Nilf(t TestingT, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Nil(t, object, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NoDirExists(t, path, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NoError(t, err, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NoFileExists(t, path, append([]any{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 any, contains any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotContains(t, s, contains, append([]any{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 any, listB any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotElementsMatch(t, listA, listB, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotEmpty(t, object, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotEqual(t, expected, actual, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotEqualValues(t, expected, actual, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotErrorAs(t, err, target, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotErrorIs(t, err, target, append([]any{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 any, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotImplements(t, interfaceObject, object, append([]any{msg}, args...)...) -} - -// NotNilf asserts that the specified object is not nil. -// -// assert.NotNilf(t, err, "error message %s", "formatted") -func NotNilf(t TestingT, object any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotNil(t, object, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotPanics(t, f, append([]any{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 any, str any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotRegexp(t, rx, str, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotSame(t, expected, actual, append([]any{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 any, subset any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotSubset(t, list, subset, append([]any{msg}, args...)...) -} - -// NotZerof asserts that i is not the zero value for its type. -func NotZerof(t TestingT, i any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return NotZero(t, i, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Panics(t, f, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return PanicsWithError(t, errString, f, append([]any{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 any, f PanicTestFunc, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return PanicsWithValue(t, expected, f, append([]any{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 any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Positive(t, e, append([]any{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 any, str any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Regexp(t, rx, str, append([]any{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 any, actual any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Same(t, expected, actual, append([]any{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 any, subset any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Subset(t, list, subset, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return True(t, value, append([]any{msg}, args...)...) -} - -// WithinDurationf asserts that the two times are within duration delta of each other. -// -// assert.WithinDurationf(t, 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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return WithinDuration(t, expected, actual, delta, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return WithinRange(t, actual, start, end, append([]any{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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return YAMLEq(t, expected, actual, append([]any{msg}, args...)...) -} - -// Zerof asserts that i is the zero value for its type. -func Zerof(t TestingT, i any, msg string, args ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Zero(t, i, append([]any{msg}, args...)...) -} diff --git a/assert/assertion_format.go.tmpl b/assert/assertion_format.go.tmpl deleted file mode 100644 index d2bb0b817..000000000 --- a/assert/assertion_format.go.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -{{.CommentFormat}} -func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { - if h, ok := t.(tHelper); ok { h.Helper() } - return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) -} diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go deleted file mode 100644 index 2fe26d5d2..000000000 --- a/assert/assertion_forward.go +++ /dev/null @@ -1,1803 +0,0 @@ -// Code generated with github.com/go-openapi/testify/v2/_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 ...any) 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 ...any) 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 any, contains any, msgAndArgs ...any) 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 any, contains any, msg string, args ...any) 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 ...any) 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 ...any) 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 any, listB any, msgAndArgs ...any) 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 any, listB any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, actual any, msgAndArgs ...any) 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 ...any) 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 ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 any, actual any, msg string, args ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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, "error message %s", "formatted") { -// // 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) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) 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 ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return Falsef(a.t, value, msg, args...) -} - -// FileEmpty checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func (a *Assertions) FileEmpty(path string, msgAndArgs ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return FileEmpty(a.t, path, msgAndArgs...) -} - -// FileEmptyf checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func (a *Assertions) FileEmptyf(path string, msg string, args ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return FileEmptyf(a.t, path, 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 ...any) 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 ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return FileExistsf(a.t, path, msg, args...) -} - -// FileNotEmpty checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func (a *Assertions) FileNotEmpty(path string, msgAndArgs ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return FileNotEmpty(a.t, path, msgAndArgs...) -} - -// FileNotEmptyf checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func (a *Assertions) FileNotEmptyf(path string, msg string, args ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return FileNotEmptyf(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 any, e2 any, msgAndArgs ...any) 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 any, e2 any, msgAndArgs ...any) 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 any, e2 any, msg string, args ...any) 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 any, e2 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 any, object any, msgAndArgs ...any) 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 any, object any, msg string, args ...any) 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 any, actual any, delta float64, msgAndArgs ...any) 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 any, actual any, delta float64, msgAndArgs ...any) 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 any, actual any, delta float64, msg string, args ...any) 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 any, actual any, delta float64, msgAndArgs ...any) 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 any, actual any, delta float64, msg string, args ...any) 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 any, actual any, delta float64, msg string, args ...any) 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 any, actual any, epsilon float64, msgAndArgs ...any) 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 any, actual any, epsilon float64, msgAndArgs ...any) 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 any, actual any, epsilon float64, msg string, args ...any) 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 any, actual any, epsilon float64, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, object any, msgAndArgs ...any) 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 any, object any, msg string, args ...any) 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 any, object any, msgAndArgs ...any) 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 any, object any, msg string, args ...any) 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 ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return JSONEq(a.t, expected, actual, msgAndArgs...) -} - -// JSONEqBytes asserts that two JSON byte slices are equivalent. -// -// a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) -func (a *Assertions) JSONEqBytes(expected []byte, actual []byte, msgAndArgs ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return JSONEqBytes(a.t, expected, actual, msgAndArgs...) -} - -// JSONEqBytesf asserts that two JSON byte slices are equivalent. -// -// a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "error message %s", "formatted") -func (a *Assertions) JSONEqBytesf(expected []byte, actual []byte, msg string, args ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return JSONEqBytesf(a.t, expected, actual, msg, args...) -} - -// 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 ...any) 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 any, length int, msgAndArgs ...any) 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 any, length int, msg string, args ...any) 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 any, e2 any, msgAndArgs ...any) 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 any, e2 any, msgAndArgs ...any) 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 any, e2 any, msg string, args ...any) 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 any, e2 any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 any, contains any, msgAndArgs ...any) 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 any, contains any, msg string, args ...any) 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 any, listB any, msgAndArgs ...any) 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 any, listB any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 any, actual any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 any, object any, msgAndArgs ...any) 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 any, object any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 any, str any, msgAndArgs ...any) 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 any, str any, msg string, args ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 any, subset any, msgAndArgs ...any) 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 any, subset any, msg string, args ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 any, f PanicTestFunc, msgAndArgs ...any) 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 any, f PanicTestFunc, msg string, args ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) 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 any, str any, msgAndArgs ...any) 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 any, str any, msg string, args ...any) 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 any, actual any, msgAndArgs ...any) 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 any, actual any, msg string, args ...any) 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 any, subset any, msgAndArgs ...any) 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 any, subset any, msg string, args ...any) 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 ...any) 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 ...any) 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(), 10*time.Second) -func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) 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(), 10*time.Second, "error message %s", "formatted") -func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msg string, args ...any) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return Zerof(a.t, i, msg, args...) -} diff --git a/assert/assertion_forward.go.tmpl b/assert/assertion_forward.go.tmpl deleted file mode 100644 index 188bb9e17..000000000 --- a/assert/assertion_forward.go.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -{{.CommentWithoutT "a"}} -func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { - if h, ok := a.t.(tHelper); ok { h.Helper() } - return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) -} diff --git a/assert/assertions.go b/assert/assertions.go deleted file mode 100644 index d4093317d..000000000 --- a/assert/assertions.go +++ /dev/null @@ -1,2402 +0,0 @@ -package assert - -import ( - "bufio" - "bytes" - "encoding/json" - "errors" - "fmt" - "io/fs" - "math" - "os" - "reflect" - "regexp" - "runtime" - "runtime/debug" - "strings" - "time" - "unicode" - "unicode/utf8" - - "github.com/go-openapi/testify/v2/assert/yaml" - "github.com/go-openapi/testify/v2/internal/difflib" - "github.com/go-openapi/testify/v2/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 ...any) -} - -// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful -// for table driven tests. -type ComparisonAssertionFunc func(TestingT, any, any, ...any) bool - -// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful -// for table driven tests. -type ValueAssertionFunc func(TestingT, any, ...any) bool - -// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful -// for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...any) bool - -// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful -// for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...any) 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 ...any) 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 any) 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 any) any { - 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 := range expectedType.NumField() { - 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.Pointer: - 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 := range expectedValue.Len() { - 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 any) 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 any) 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 ...any) 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 { - format, ok := msgAndArgs[0].(string) - if ok { - return fmt.Sprintf(format, 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 ...any) 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 ...any) 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 strings.Builder - for _, v := range content { - output.WriteString("\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n") - } - return output.String() -} - -// Implements asserts that an object is implemented by the specified interface. -// -// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) -func Implements(t TestingT, interfaceObject any, object any, msgAndArgs ...any) 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 any, object any, msgAndArgs ...any) 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 any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any) (same bool, ok bool) { - firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) - if firstPtr.Kind() != reflect.Pointer || secondPtr.Kind() != reflect.Pointer { - 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 any) (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) - default: - 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 any) string { - const maxMessageSize = bufio.MaxScanTokenSize/2 - 100 - - value := fmt.Sprintf(format, data) - // Give us space for two truncated objects and the surrounding sentence. - 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any) 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() - default: - return false - } -} - -// Nil asserts that the specified object is nil. -// -// assert.Nil(t, err) -func Nil(t TestingT, object any, msgAndArgs ...any) bool { - if isNil(object) { - return true - } - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Fail(t, "Expected nil, but got: "+truncatingFormat("%#v", object), msgAndArgs...) -} - -// isEmpty gets whether the specified object is considered empty or not. -func isEmpty(object any) 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()) - default: - 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 any, msgAndArgs ...any) bool { - pass := isEmpty(object) - if !pass { - if h, ok := t.(tHelper); ok { - h.Helper() - } - Fail(t, "Should be empty, but was "+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 any, msgAndArgs ...any) 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 any) (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 any, length int, msgAndArgs ...any) 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 ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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 any, element any) (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 := range mapKeys { - if ObjectsAreEqual(mapKeys[i].Interface(), element) { - return true, true - } - } - return true, false - } - - for i := range listValue.Len() { - 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - ok, found := containsElement(s, contains) - if !ok { - return Fail(t, truncatingFormat("%#v", s)+" could not be applied builtin len()", 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - ok, found := containsElement(s, contains) - if !ok { - return Fail(t, truncatingFormat("%#v", s)+" could not be applied builtin len()", 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 any, msgAndArgs ...any) (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([]any, subsetList.Len()) - for idx, key := range subsetList.MapKeys() { - keys[idx] = key.Interface() - } - subsetList = reflect.ValueOf(keys) - } - - for i := range subsetList.Len() { - 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 any, msgAndArgs ...any) (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([]any, subsetList.Len()) - for idx, key := range subsetList.MapKeys() { - keys[idx] = key.Interface() - } - subsetList = reflect.ValueOf(keys) - } - for i := range subsetList.Len() { - 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 any, msgAndArgs ...any) (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 any, msgAndArgs ...any) (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 any) (extraA, extraB []any) { - 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 := range aLen { - element := aValue.Index(i).Interface() - found := false - for j := range bLen { - 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 := range bLen { - if visited[j] { - continue - } - extraB = append(extraB, bValue.Index(j).Interface()) - } - - return extraA, extraB -} - -func formatListDiff(listA, listB any, extraA, extraB []any) 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 any, msgAndArgs ...any) (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 ...any) 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 any, stack string) { - didPanic = true - - defer func() { - message = recover() - if didPanic { - stack = string(debug.Stack()) - } - // Go 1.21 introduces runtime.PanicNilError on panic(nil), - // so maintain the same logic going forward (https://github.com/golang/go/issues/25448). - if err, ok := message.(error); ok { - if err.Error() == "panic called with nil argument" { - message = nil - } - } - }() - - // 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 ...any) 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 any, f PanicTestFunc, msgAndArgs ...any) 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 ...any) 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 ...any) 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(), 10*time.Second) -func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...any) 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 ...any) 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 any) (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 any, delta float64, msgAndArgs ...any) 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 any, delta float64, msgAndArgs ...any) 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 := range actualSlice.Len() { - 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 any, delta float64, msgAndArgs ...any) 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 any) (float64, error) { - af, aok := toFloat(expected) - bf, bok := toFloat(actual) - if !aok || !bok { - return 0, errors.New("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, errors.New("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 any, epsilon float64, msgAndArgs ...any) 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 any, epsilon float64, msgAndArgs ...any) 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 := range expectedLen { - 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 ...any) bool { - if err != nil { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Fail(t, "Received unexpected error:\n"+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 ...any) 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 ...any) 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 ...any) 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 any, str any) 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 any, str any, msgAndArgs ...any) 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 any, str any, msgAndArgs ...any) 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { - return Fail(t, "Should be zero, but was "+truncatingFormat("%v", i), msgAndArgs...) - } - return true -} - -// NotZero asserts that i is not the zero value for its type. -func NotZero(t TestingT, i any, msgAndArgs ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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...) -} - -// FileEmpty checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func FileEmpty(t TestingT, path string, msgAndArgs ...any) 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...) - } - if info.Mode()&fs.ModeSymlink > 0 { - target, err := os.Readlink(path) - if err != nil { - return Fail(t, fmt.Sprintf("could not resolve symlink %q", path), msgAndArgs...) - } - return FileEmpty(t, target, msgAndArgs...) - } - - if info.Size() > 0 { - return Fail(t, fmt.Sprintf("%q is not empty", path), msgAndArgs...) - } - - return true -} - -// FileNotEmpty checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func FileNotEmpty(t TestingT, path string, msgAndArgs ...any) 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...) - } - if info.Mode()&fs.ModeSymlink > 0 { - target, err := os.Readlink(path) - if err != nil { - return Fail(t, fmt.Sprintf("could not resolve symlink %q", path), msgAndArgs...) - } - return FileNotEmpty(t, target, msgAndArgs...) - } - - if info.Size() == 0 { - return Fail(t, fmt.Sprintf("%q is empty", path), msgAndArgs...) - } - - return true -} - -// JSONEqBytes asserts that two JSON byte slices are equivalent. -// -// assert.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) -func JSONEqBytes(t TestingT, expected, actual []byte, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - var expectedJSONAsInterface, actualJSONAsInterface any - - if err := json.Unmarshal(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 bytes.Equal(actual, expected) { - return true - } - - if err := json.Unmarshal(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...) -} - -// JSONEq asserts that two JSON strings are equivalent. -// -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -func JSONEq(t TestingT, expected, actual string, msgAndArgs ...any) bool { - return JSONEqBytes(t, []byte(expected), []byte(actual), 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 ...any) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - var expectedYAMLAsInterface, actualYAMLAsInterface any - - 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 any) (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 any, actual any) 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.TypeFor[string](): - e = reflect.ValueOf(expected).String() - a = reflect.ValueOf(actual).String() - case reflect.TypeFor[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 any) bool { - if arg == nil { - return false - } - return reflect.TypeOf(arg).Kind() == reflect.Func -} - -const spewMaxDepth = 10 - -//nolint:gochecknoglobals // spew is more easily configured using a global default config. This is okay in this context. -var ( - spewConfig = spew.ConfigState{ - Indent: " ", - DisablePointerAddresses: true, - DisableCapacities: true, - SortKeys: true, - DisableMethods: true, - MaxDepth: spewMaxDepth, - } - - spewConfigStringerEnabled = spew.ConfigState{ - Indent: " ", - DisablePointerAddresses: true, - DisableCapacities: true, - SortKeys: true, - MaxDepth: spewMaxDepth, - } -) - -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 ...any) 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 ...any) { - 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 any, msgAndArgs ...any) 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 any, msgAndArgs ...any) 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) { //nolint:errorlint // false positive: this type switch is checking for interfaces - 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 strings.Builder - errs := unwrapAll(err) - for i := range errs { - if i != 0 { - chain.WriteString("\n\t") - } - chain.WriteString(fmt.Sprintf("%q", errs[i].Error())) - if withType { - chain.WriteString(fmt.Sprintf(" (%T)", errs[i])) - } - } - return chain.String() -} diff --git a/assert/assertions_test.go b/assert/assertions_test.go deleted file mode 100644 index 2b47f105c..000000000 --- a/assert/assertions_test.go +++ /dev/null @@ -1,4159 +0,0 @@ -package assert - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "math" - "os" - "path/filepath" - "reflect" - "regexp" - "runtime" - "strings" - "testing" - "time" -) - -//nolint:gochecknoglobals // private globals to store zero values. Not exposed, not mutated: should be fine -var ( - i any - zeros = []any{ - 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]any{}, - []any(nil), - struct{ x int }{}, - (*any)(nil), - (func())(nil), - nil, - any(nil), - map[any]any(nil), - (chan any)(nil), - (<-chan any)(nil), - (chan<- any)(nil), - } - nonZeros = []any{ - 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]any{1}, - []any{}, - struct{ x int }{1}, - (&i), - (func() {}), - any(1), - map[any]any{}, - (make(chan any)), - (<-chan any)(make(chan any)), - (chan<- any)(make(chan any)), - } -) - -// 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 any - actual any - 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 any - actual any - result bool - }{ - {uint32(10), int32(10), true}, - {0, nil, false}, - {nil, 0, false}, - // should not be time zone independent - {now, now.In(time.Local), false}, //nolint:gosmopolitan // ok in this context: this is precisely the goal of this test - {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 any - notExported any -} - -type S struct { - Exported1 any - Exported2 Nested - notExported1 any - notExported2 Nested -} - -type S2 struct { - foo any -} - -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 any - actual any - 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[any]*Nested{nil: nil}, 2}, - Nested{map[any]*Nested{nil: nil}, 2}, - true, - }, - { - Nested{map[any]*Nested{"a": nil}, 2}, - Nested{map[any]*Nested{"a": nil}, 2}, - true, - }, - { - Nested{map[any]*Nested{"a": nil}, 2}, - Nested{map[any]*Nested{"a": {1, 2}}, 2}, - false, - }, - { - Nested{map[any]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, - Nested{map[any]Nested{"a": {1, 5}, "b": {3, 7}}, 2}, - true, - }, - { - Nested{map[any]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, - Nested{map[any]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 any - expected any - }{ - { - 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 any - value2 any - 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]any - - cases := []struct { - expected any - actual any - 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 any - second any - } - 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 ...any) { - // 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 []any - 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 []any - 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: []any{"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: []any{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: []any{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 any - actual any - 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 any - actual any - 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 any - actual any - 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[any]any{"Foo": "Bar"} - var zeroMap map[any]any - - cases := []struct { - expected any - actual any - 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 any, msgAndArgs ...any) bool - container any - instance any - 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 any - subset any - 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[any]any{"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 any - actual any - 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 any - listB any - extraA []any - extraB []any - }{ - { - 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: []any{"hello"}, - extraB: nil, - }, - { - name: "extra A twice", - listA: []string{"hello", "hello", "hello", "world"}, - listB: []string{"hello", "world"}, - extraA: []any{"hello", "hello"}, - extraB: nil, - }, - { - name: "extra B", - listA: []string{"hello", "world"}, - listB: []string{"hello", "hello", "world"}, - extraA: nil, - extraB: []any{"hello"}, - }, - { - name: "extra B twice", - listA: []string{"hello", "world"}, - listB: []string{"hello", "hello", "world", "hello"}, - extraA: nil, - extraB: []any{"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: []any{1}, - extraB: []any{2}, - }, - } - for _, test := range tests { - - 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 any - actual any - 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") - } - - { - funcDidPanic, msg, _ := didPanic(func() { - err := errors.New("test") - panic(err) // nil is no longer supported as a panic value and returns a runtime.PanicNil error - }) - if !funcDidPanic { - t.Error("didPanic should have panicked") - } - if msg == nil { - t.Errorf("didPanic should have returned something, but got 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") - } - - { - err := errors.New("test") - if !PanicsWithValue(mockT, err, func() { - panic(err) // panic no longer supports a nil argument - }) { - 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(&PanicsWrapperError{"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 PanicsWrapperError struct { - Prefix string - Err error -} - -func (e PanicsWrapperError) 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([]any(nil))) - True(t, isEmpty([]any{})) - 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) - - for b.Loop() { - 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 any - 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 { - - 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 any - 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 { - - 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 := []any{ - 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 any - 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 any - 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 any - 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 any - actual any - f func(TestingT, bool, ...any) 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 any - 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 any - 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, filepath.Base(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 TestFileEmpty(t *testing.T) { - t.Parallel() - - mockT := new(testing.T) - True(t, FileEmpty(mockT, filepath.Join("testdata", "empty_file"))) - - mockT = new(testing.T) - False(t, FileEmpty(mockT, "assertions.go")) - - mockT = new(testing.T) - False(t, FileEmpty(mockT, "random_file")) - - mockT = new(testing.T) - False(t, FileEmpty(mockT, "../_codegen")) - - link := getTempSymlinkPath(t, filepath.Join("testdata", "empty_file")) - mockT = new(testing.T) - True(t, FileEmpty(mockT, link)) - - link = getTempSymlinkPath(t, "assertions.go") - mockT = new(testing.T) - False(t, FileEmpty(mockT, link)) - - link = getTempSymlinkPath(t, "non_existent_file") - mockT = new(testing.T) - False(t, FileEmpty(mockT, link)) -} - -func TestFileNotEmpty(t *testing.T) { - t.Parallel() - - mockT := new(testing.T) - True(t, FileNotEmpty(mockT, "assertions.go")) - - mockT = new(testing.T) - False(t, FileNotEmpty(mockT, filepath.Join("testdata", "empty_file"))) - - mockT = new(testing.T) - False(t, FileNotEmpty(mockT, "non_existent_file")) - - mockT = new(testing.T) - False(t, FileNotEmpty(mockT, "../_codegen")) - - link := getTempSymlinkPath(t, filepath.Join("testdata", "empty_file")) - mockT = new(testing.T) - False(t, FileNotEmpty(mockT, link)) - - link = getTempSymlinkPath(t, "assertions.go") - mockT = new(testing.T) - True(t, FileNotEmpty(mockT, link)) - - link = getTempSymlinkPath(t, "non_existent_file") - mockT = new(testing.T) - False(t, NoFileExists(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 TestJSONEqBytes_EqualSONString(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEqBytes(mockT, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"hello": "world", "foo": "bar"}`))) -} - -func TestJSONEqBytes_EquivalentButNotEqual(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEqBytes(mockT, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`))) -} - -func TestJSONEqBytes_HashOfArraysAndHashes(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEqBytes(mockT, []byte("{\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}"), - []byte("{\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 TestJSONEqBytes_Array(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEqBytes(mockT, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`["foo", {"nested": "hash", "hello": "world"}]`))) -} - -func TestJSONEqBytes_HashAndArrayNotEquivalent(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`{"foo": "bar", {"nested": "hash", "hello": "world"}}`))) -} - -func TestJSONEqBytes_HashesNotEquivalent(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte(`{"foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`))) -} - -func TestJSONEqBytes_ActualIsNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte(`{"foo": "bar"}`), []byte("Not JSON"))) -} - -func TestJSONEqBytes_ExpectedIsNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte("Not JSON"), []byte(`{"foo": "bar", "hello": "world"}`))) -} - -func TestJSONEqBytes_ExpectedAndActualNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte("Not JSON"), []byte("Not JSON"))) -} - -func TestJSONEqBytes_ArraysOfDifferentOrder(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEqBytes(mockT, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`[{ "hello": "world", "nested": "hash"}, "foo"]`))) -} - -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 []any -} - -// Helper is like [testing.T.Helper] but does nothing. -func (mockTestingT) Helper() {} - -func (m *mockTestingT) Errorf(format string, args ...any) { - m.errorFmt = format - m.args = args -} - -func (m *mockTestingT) Failed() bool { - return m.errorFmt != "" -} - -func (m *mockTestingT) errorString() string { - return fmt.Sprintf(m.errorFmt, m.args...) -} - -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 ...any) { - _ = format - _ = args -} - -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{} - - for b.Loop() { - Equal(mockT, s, s2) - } -} - -func BenchmarkNotNil(b *testing.B) { - for b.Loop() { - NotNil(b, b) - } -} - -func TestComparisonAssertionFunc(t *testing.T) { - t.Parallel() - - type iface interface { - Name() string - } - - tests := []struct { - name string - expect any - got any - 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 TestValueAssertionFunc(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - value any - 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 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 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 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++ - }() - 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 ...any) { - 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++ - 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(*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 += "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 ...any) { - 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 { - - 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 { - - 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 { - - 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 { - - 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>") -} diff --git a/assert/doc.go b/assert/doc.go index a1f167755..63f3bcd6c 100644 --- a/assert/doc.go +++ b/assert/doc.go @@ -1,50 +1 @@ -// 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/go-openapi/testify/v2/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/go-openapi/testify/v2/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 diff --git a/assert/enable/yaml/enable_yaml.go b/assert/enable/yaml/enable_yaml.go new file mode 100644 index 000000000..c0a67c736 --- /dev/null +++ b/assert/enable/yaml/enable_yaml.go @@ -0,0 +1,23 @@ +// Package yaml is an indirection to handle YAML deserialization. +// +// This package allows the builder to override the indirection with an alternative implementation +// of YAML deserialization. +package yaml + +import ( + yamlstub "github.com/go-openapi/testify/v2/internal/assertions/enable/yaml" +) + +// EnableYAMLWithUnmarshal registers a YAML-capable unmarshaler. +// +// This is not intended for concurrent use. +// +// Most users would register using a init() function or enabling the +// registered library provided when importing "github.com/go-openapi/testify/enable/yaml/v2" like so. +// +// import( +// _ "github.com/go-openapi/testify/enable/yaml/v2" +// ) +func EnableYAMLWithUnmarshal(unmarshaller func([]byte, any) error) { + yamlstub.EnableYAMLWithUnmarshal(unmarshaller) +} diff --git a/assert/errors.go b/assert/errors.go deleted file mode 100644 index dd62c22d6..000000000 --- a/assert/errors.go +++ /dev/null @@ -1,12 +0,0 @@ -package assert - -import ( - "errors" -) - -// ErrTest 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 ErrTest = errors.New("assert.ErrTest general error for testing") diff --git a/assert/examples_test.go b/assert/examples_test.go deleted file mode 100644 index 81fa92b7e..000000000 --- a/assert/examples_test.go +++ /dev/null @@ -1,135 +0,0 @@ -//nolint:testableexamples // not possible at this moment to build a testable example that involves testing.T -package assert - -import ( - "encoding/json" - "testing" -) - -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 ExampleValueAssertionFunc() { - t := &testing.T{} // provided by test - - dumbParse := func(input string) any { - var x any - _ = 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 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 ExampleErrorAssertionFunc() { - t := &testing.T{} // provided by test - - dumbParseNum := func(input string, v any) 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 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) - }) - } -} diff --git a/assert/forward_assertions.go b/assert/forward_assertions.go deleted file mode 100644 index df189d234..000000000 --- a/assert/forward_assertions.go +++ /dev/null @@ -1,16 +0,0 @@ -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" diff --git a/assert/forward_assertions_test.go b/assert/forward_assertions_test.go deleted file mode 100644 index fd098458c..000000000 --- a/assert/forward_assertions_test.go +++ /dev/null @@ -1,725 +0,0 @@ -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 any - 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 any - 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 any - 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 any - 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") - } -} diff --git a/assert/http_assertions_test.go b/assert/http_assertions_test.go deleted file mode 100644 index 933fe4eb3..000000000 --- a/assert/http_assertions_test.go +++ /dev/null @@ -1,232 +0,0 @@ -package assert - -import ( - "fmt" - "io" - "net/http" - "net/url" - "testing" -) - -func httpOK(w http.ResponseWriter, _ *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, _ *http.Request) { - w.WriteHeader(http.StatusTemporaryRedirect) -} - -func httpError(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) -} - -func httpStatusCode(w http.ResponseWriter, _ *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")) -} diff --git a/assert/yaml/yaml_default.go b/assert/yaml/yaml_default.go deleted file mode 100644 index f45b5041b..000000000 --- a/assert/yaml/yaml_default.go +++ /dev/null @@ -1,29 +0,0 @@ -// 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]). -package yaml - -var EnableYAMLUnmarshal func([]byte, any) error //nolint:gochecknoglobals // in this particular case, we need a global to enable the feature from another module - -// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. -func Unmarshal(in []byte, out any) error { - if EnableYAMLUnmarshal == nil { - panic(` -YAML is not enabled yet! - -You should enable a YAML library before running this test, -e.g. by adding the following to your imports: - -import ( - _ "github.com/go-openapi/testify/enable/yaml/v2" -) -`, - ) - - } - return EnableYAMLUnmarshal(in, out) -} diff --git a/codegen/.gitignore b/codegen/.gitignore new file mode 100644 index 000000000..e3a114014 --- /dev/null +++ b/codegen/.gitignore @@ -0,0 +1 @@ +codegen diff --git a/codegen/go.mod b/codegen/go.mod new file mode 100644 index 000000000..ba63fc337 --- /dev/null +++ b/codegen/go.mod @@ -0,0 +1,15 @@ +module github.com/go-openapi/testify/v2/codegen + +go 1.24.0 + +toolchain go1.25.0 + +require ( + github.com/go-openapi/testify/v2 v2.0.2 + golang.org/x/tools v0.40.0 +) + +require ( + golang.org/x/mod v0.31.0 // indirect + golang.org/x/sync v0.19.0 // indirect +) diff --git a/codegen/go.sum b/codegen/go.sum new file mode 100644 index 000000000..26ca4bf3b --- /dev/null +++ b/codegen/go.sum @@ -0,0 +1,10 @@ +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= diff --git a/codegen/internal/generator/doc.go b/codegen/internal/generator/doc.go new file mode 100644 index 000000000..05646320b --- /dev/null +++ b/codegen/internal/generator/doc.go @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Package generator generates the testify public API. +// +// It adapts the internal testify API from github.com/go-openapi/testify/v2/internal/assertions +// and generates the content in packages "assert" and "require". +package generator diff --git a/codegen/internal/generator/funcmap.go b/codegen/internal/generator/funcmap.go new file mode 100644 index 000000000..e780c1831 --- /dev/null +++ b/codegen/internal/generator/funcmap.go @@ -0,0 +1,201 @@ +package generator + +import ( + "fmt" + "path" + "path/filepath" + "regexp" + "sort" + "strings" + "text/template" + + "github.com/go-openapi/testify/v2/codegen/internal/model" +) + +func funcMap() template.FuncMap { + return map[string]any{ + "imports": printImports, + "comment": comment, + "params": params, + "forward": forward, + "docStringFor": docStringFor, + "docStringPackage": docStringPackage, + "returns": printReturns, + "concat": concatStrings, + "pathparts": pathParts, + "relocate": relocate, + "hasSuffix": strings.HasSuffix, + } +} + +func printImports(in model.ImportMap) string { + list := make([]string, 0, len(in)) + + for k, v := range in { + if k == path.Base(v) { + // no alias + list = append(list, "\t\""+v+"\"") + + continue + } + + list = append(list, "\t"+k+"\t\""+v+"\"") + } + + sort.Strings(list) + + return strings.Join(list, "\n") +} + +func comment(str string) string { + if str == "" { + return "" + } + + lines := rTrimEmpty(strings.Split(str, "\n")) + + return "// " + strings.Join(lines, "\n// ") +} + +func rTrimEmpty(lines []string) []string { + var i int + for i = len(lines) - 1; i >= 0; i-- { + if lines[i] != "" { + break + } + } + + return lines[:i+1] +} + +func params(args model.Parameters) string { + var b strings.Builder + l := len(args) + + if l == 0 { + return "" + } + + b.WriteString(args[0].Name) + b.WriteByte(' ') + if strings.HasSuffix(args[0].GoType, "Func") && args[0].Selector == assertions { + b.WriteString(args[0].Selector + ".") // for xxxFunc types, backward-compatibility imposes to use the "assert-like" type definition + } + b.WriteString(args[0].GoType) + + for _, v := range args[1:] { + b.WriteString(", ") + b.WriteString(v.Name) + b.WriteByte(' ') + if strings.HasSuffix(v.GoType, "Func") && v.Selector == assertions { + b.WriteString(v.Selector + ".") // for xxxFunc types, backward-compatibility imposes to use the "assert-like" type definition + } + b.WriteString(v.GoType) + } + + return b.String() +} + +func forward(args model.Parameters) string { + var b strings.Builder + l := len(args) + + if l == 0 { + return "" + } + + b.WriteString(args[0].Name) + if args[0].IsVariadic { + b.WriteString("...") + } + + for _, v := range args[1:] { + b.WriteString(", ") + b.WriteString(v.Name) + if v.IsVariadic { + b.WriteString("...") + } + } + + return b.String() +} + +// docStringFor adds an extra comment for context. +func docStringFor(usage, name string) string { + parts := strings.Split(name, ".") + basename := parts[len(parts)-1] + + switch usage { + case "format": + return comment( + fmt.Sprintf( + "%sf is the same as [%s], but accepts a format msg string to format arguments like [fmt.Printf].", + basename, + name, + ), + ) + case "forward": + return comment( + fmt.Sprintf( + "%s is the same as [%s], as a method rather than a package-level function.", + basename, + name), + ) + default: + return "" + } +} + +// docStringPackage adds an additional comment specific to the target package. +func docStringPackage(pkg string) string { + switch pkg { + case pkgAssert: + return `// Upon failure, the test [T] is marked as failed and continues execution.` + case pkgRequire: + return `// Upon failure, the test [T] is marked as failed and stops execution.` + default: + return "" + } +} + +func printReturns(in model.Parameters) string { + return fmt.Sprintf("%v", in) +} + +func concatStrings(in ...string) string { + return strings.Join(in, "") +} + +func pathParts(in string) string { + parts := strings.FieldsFunc(filepath.Clean(in), func(r rune) bool { return r == filepath.Separator }) + + for i := range parts { + parts[i] = fmt.Sprintf("%q", parts[i]) + } + + return strings.Join(parts, ",") +} + +// relocate handles special cases in testable examples. +// +// It rewrites specific values to be run from a {{ .Package }}_test external package. +// +// Since there are only a few such edge cases, we hard-code this is this funcmap +// rather than indulging into a full-fleged go value parsing and package relocating. +func relocate(in, pkg string) string { + if pkg == "" { + return in + } + + replaced := errTestRex.ReplaceAllString(in, "${1}"+pkg+".${2}") + replaced = collectTRex.ReplaceAllString(replaced, "${1}"+pkg+".${2}") + replaced = trueRex.ReplaceAllString(replaced, "${1}"+pkg+".${2}") + + return replaced +} + +var ( + errTestRex = regexp.MustCompile(`(^|[^\.])(ErrTest)`) + collectTRex = regexp.MustCompile(`(^|[^\.])(CollectT)`) + trueRex = regexp.MustCompile(`(^|[^\.])(True\(c)`) +) diff --git a/codegen/internal/generator/generator.go b/codegen/internal/generator/generator.go new file mode 100644 index 000000000..bd63989d2 --- /dev/null +++ b/codegen/internal/generator/generator.go @@ -0,0 +1,444 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package generator + +import ( + "bytes" + "embed" + "errors" + "fmt" + "os" + "path" + "path/filepath" + "sort" + "text/template" + + "github.com/go-openapi/testify/v2/codegen/internal/model" + "golang.org/x/tools/imports" +) + +const ( + pkgRequire = "require" + pkgAssert = "assert" + assertions = "assertions" +) + +const ( + dirPermissions = 0750 + filePermissions = 0600 +) + +var ( + //go:embed templates/*.gotmpl + templatesFS embed.FS +) + +// Generator generates testify packages (assert, require) from the internal assertions package. +type Generator struct { + options + + source *model.AssertionPackage + ctx *genCtx +} + +type genCtx struct { + generateOptions + + index map[string]string + templates map[string]*template.Template + target *model.AssertionPackage + targetBase string +} + +func New(source *model.AssertionPackage, opts ...Option) *Generator { + return &Generator{ + options: optionsWithDefaults(opts), + source: source, + } +} + +func (g *Generator) Generate(opts ...GenerateOption) error { + if err := g.initContext(opts); err != nil { + return err + } + defer func() { + g.ctx = nil + }() + + if err := g.loadTemplates(); err != nil { + return err + } + + if err := g.transformModel(); err != nil { + return err + } + + { + // auto-generated assertions + + if err := g.generateTypes(); err != nil { + // assertion_types.gotmpl + return err + } + + if err := g.generateAssertions(); err != nil { + return err + } + + if err := g.generateFormatFuncs(); err != nil { + // assertion_format.gotmpl + // requirement_format.gotmpl + return err + } + + if err := g.generateForwardFuncs(); err != nil { + // assertion_forward.gotmpl + // requirement_forward.gotmpl + return err + } + + if err := g.generateHelpers(); err != nil { + return err + } + } + + { + // auto-generated tests + + if err := g.generateAssertionsTests(); err != nil { + return err + } + + if err := g.generateFormatTests(); err != nil { + return err + } + + if err := g.generateForwardTests(); err != nil { + return err + } + + if err := g.generateExampleTests(); err != nil { + return err + } + + return g.generateHelpersTests() + } +} + +func (g *Generator) initContext(opts []GenerateOption) error { + // prepare options + g.ctx = &genCtx{ + generateOptions: generateOptionsWithDefaults(opts), + } + if g.ctx.targetPkg == "" { + return errors.New("a target package is required") + } + g.ctx.targetBase = path.Base(g.ctx.targetPkg) // perhaps find a better name + + if g.ctx.targetBase != pkgAssert && g.ctx.targetBase != pkgRequire { + return fmt.Errorf(`unsupported target package. Expect pkgAssert or pkgRequire but got: %q`, g.ctx.targetBase) + } + + if err := os.MkdirAll(filepath.Join(g.ctx.targetRoot, g.ctx.targetBase), dirPermissions); err != nil { + return fmt.Errorf("can't make target folder: %w", err) + } + + return nil +} + +func (g *Generator) loadTemplates() error { + const expectedTemplates = 10 + index := make(map[string]string, expectedTemplates) + + switch g.ctx.targetBase { + case pkgAssert: + g.loadAssertTemplates(index) + case pkgRequire: + g.loadRequireTemplates(index) + default: + panic(fmt.Errorf("internal error: invalid targetBase: %q", g.ctx.targetBase)) + } + + g.ctx.index = index + needed := make([]string, 0, len(index)) + for _, v := range index { + needed = append(needed, v) + } + sort.Strings(needed) + + g.ctx.templates = make(map[string]*template.Template, len(needed)) + for _, name := range needed { + file := name + ".gotmpl" + tpl, err := template.New(file).Funcs(funcMap()).ParseFS(templatesFS, path.Join("templates", file)) + if err != nil { + return fmt.Errorf("failed to load template %q from %q: %w", name, file, err) + } + + g.ctx.templates[name] = tpl + } + + return nil +} + +func (g *Generator) loadAssertTemplates(index map[string]string) { + index["types"] = "assertion_types" + index["assertions"] = "assertion_assertions" + + if g.ctx.generateTests { + index["assertions_test"] = "assertion_assertions_test" + } + + if g.ctx.generateHelpers { + index["helpers"] = "assertion_helpers" + if g.ctx.generateTests { + index["helpers_test"] = "assertion_helpers_test" + } + } + + if g.ctx.generateExamples { + index["examples_test"] = "assertion_examples_test" + } + + if g.ctx.enableForward { + index["forward"] = "assertion_forward" + if g.ctx.generateTests { + index["forward_test"] = "assertion_forward_test" + } + } + + if g.ctx.enableFormat { + index["format"] = "assertion_format" + if g.ctx.generateTests { + index["format_test"] = "assertion_format_test" + } + } +} + +func (g *Generator) loadRequireTemplates(index map[string]string) { + index["types"] = "assertion_types" + index["assertions"] = "requirement_assertions" + + if g.ctx.generateTests { + index["assertions_test"] = "assertion_assertions_test" + } + + if g.ctx.generateHelpers { + index["helpers"] = "assertion_helpers" + if g.ctx.generateTests { + index["helpers_test"] = "assertion_helpers_test" + } + } + + if g.ctx.generateExamples { + index["examples_test"] = "assertion_examples_test" + } + + if g.ctx.enableForward { + index["forward"] = "requirement_forward" + if g.ctx.generateTests { + index["forward_test"] = "assertion_forward_test" + } + } + + if g.ctx.enableFormat { + index["format"] = "requirement_format" + if g.ctx.generateTests { + index["format_test"] = "assertion_format_test" + } + } +} + +func (g *Generator) transformModel() error { + tgt := g.source.Clone() + + tgt.Package = g.ctx.targetBase + tgt.Receiver = "Assertions" + tgt.EnableFormat = g.ctx.enableFormat + tgt.EnableForward = g.ctx.enableForward + tgt.EnableGenerics = g.ctx.enableGenerics + tgt.EnableExamples = g.ctx.generateExamples + tgt.RunnableExamples = g.ctx.runnableExamples + if tgt.Imports == nil { + tgt.Imports = make(model.ImportMap, 1) + } + tgt.Imports[assertions] = g.source.Package // add the import of our internal assertions package + absRoot, err := filepath.Abs(g.ctx.targetRoot) + if err != nil { + return err + } + + testdata, err := filepath.Rel(filepath.Join(absRoot, g.ctx.targetBase), g.source.TestDataPath) + if err != nil { + return err + } + tgt.TestDataPath = testdata + + for i, fn := range tgt.Functions { + tgt.Functions[i] = g.transformFunc(fn) + } + + for i, vr := range tgt.Vars { + if vr.Function == nil { + continue + } + + fn := g.transformFunc(*vr.Function) + vr.Function = &fn + tgt.Vars[i] = vr + } + + for i, typ := range tgt.Types { + if typ.Function == nil { + continue + } + + fn := g.transformFunc(*typ.Function) + typ.Function = &fn + tgt.Types[i] = typ + } + + g.ctx.target = tgt + + return nil +} + +func (g *Generator) transformFunc(fn model.Function) model.Function { + fn.Params = g.transformArgs(fn.Params) + fn.AllParams = g.transformArgs(fn.AllParams) + fn.Returns = g.transformArgs(fn.Returns) + if fn.Name == "FailNow" || g.ctx.targetBase == pkgRequire { + fn.UseMock = "mockFailNowT" + } else { + fn.UseMock = "mockT" + } + + return fn +} + +func (g *Generator) generateTypes() error { + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_types.go") + + return g.render("types", file, g.ctx.target) +} + +func (g *Generator) generateAssertions() error { + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_assertions.go") + + return g.render("assertions", file, g.ctx.target) +} + +func (g *Generator) generateFormatFuncs() error { + if !g.ctx.enableFormat { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_format.go") + + return g.render("format", file, g.ctx.target) +} + +func (g *Generator) generateForwardFuncs() error { + if !g.ctx.enableForward { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_forward.go") + + return g.render("forward", file, g.ctx.target) +} + +func (g *Generator) generateHelpers() error { + if !g.ctx.generateHelpers { + return nil + } + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_helpers.go") + + return g.render("helpers", file, g.ctx.target) +} + +func (g *Generator) generateAssertionsTests() error { + if !g.ctx.generateTests { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_assertions_test.go") + + return g.render("assertions_test", file, g.ctx.target) +} + +func (g *Generator) generateFormatTests() error { + if !g.ctx.enableFormat || !g.ctx.generateTests { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_format_test.go") + + return g.render("format_test", file, g.ctx.target) +} + +func (g *Generator) generateForwardTests() error { + if !g.ctx.enableForward || !g.ctx.generateTests { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_forward_test.go") + + return g.render("forward_test", file, g.ctx.target) +} + +func (g *Generator) generateExampleTests() error { + if !g.ctx.generateExamples { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_examples_test.go") + + return g.render("examples_test", file, g.ctx.target) +} + +func (g *Generator) generateHelpersTests() error { + if !g.ctx.generateHelpers || !g.ctx.generateTests { + return nil + } + + file := filepath.Join(g.ctx.targetRoot, g.ctx.targetBase, g.ctx.targetBase+"_helpers_test.go") + + return g.render("helpers_test", file, g.ctx.target) +} + +func (g *Generator) render(name string, target string, data any) error { + tplName, ok := g.ctx.index[name] + if !ok { + panic(fmt.Errorf("internal error: expect template name %q", name)) + } + + tpl, ok := g.ctx.templates[tplName] + if !ok { + panic(fmt.Errorf("internal error: expect template %q", name)) + } + + var buffer bytes.Buffer + if err := tpl.Execute(&buffer, data); err != nil { + return fmt.Errorf("error executing template %q (%s): %w", name, tplName, err) + } + + formatted, err := imports.Process(target, buffer.Bytes(), g.ctx.formatOptions) + if err != nil { + _ = os.WriteFile(target, buffer.Bytes(), filePermissions) + return fmt.Errorf("error formatting go code: %w:%w", err, fmt.Errorf("details available at: %v", target)) + } + + return os.WriteFile(target, formatted, filePermissions) +} + +func (g *Generator) transformArgs(in model.Parameters) model.Parameters { + for j, arg := range in { + if arg.Selector == "" { + arg.Selector = assertions + } + in[j] = arg + } + + return in +} diff --git a/codegen/internal/generator/generator_test.go b/codegen/internal/generator/generator_test.go new file mode 100644 index 000000000..d6dda42e7 --- /dev/null +++ b/codegen/internal/generator/generator_test.go @@ -0,0 +1,256 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package generator + +import ( + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/codegen/internal/model" +) + +const ( + pkgSource = "github.com/go-openapi/testify/v2/internal/assertions" +) + +// TestNew verifies that New creates a valid Generator instance. +func TestNew(t *testing.T) { + t.Parallel() + + source := model.New() + source.Package = pkgSource + source.DocString = "Package assertions provides test assertions" + source.Copyright = "Copyright 2025" + + gen := New(source) + + if gen == nil { + t.Fatal("New() returned nil") + } + + if gen.source != source { + t.Error("Generator source not set correctly") + } +} + +// TestGeneratorInitContext verifies context initialization. +func TestGeneratorInitContext(t *testing.T) { + t.Parallel() + source := model.New() + source.Package = pkgSource + + for tt := range generatorCases(t) { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + gen := New(source) + err := gen.initContext(tt.opts) + + if tt.expectError { + if err == nil { + t.Error("Expected error but got nil") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if tt.checkFunc != nil { + tt.checkFunc(t, gen) + } + } + }) + } +} + +// TestTransformArgs verifies argument transformation for generation. +func TestTransformArgs(t *testing.T) { + t.Parallel() + + source := model.New() + gen := New(source) + + for tt := range transformCases() { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + params := gen.transformArgs(tt.input) + result := params.String() + + if result != tt.expected { + t.Errorf("Expected %q, got %q", tt.expected, result) + } + }) + } +} + +// TestLoadTemplates verifies template loading for assert and require packages. +func TestLoadTemplates(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + targetPkg string + expectError bool + checkFunc func(*testing.T, *Generator) + }{ + { + name: "load assert templates", + targetPkg: pkgAssert, + expectError: false, + checkFunc: func(t *testing.T, g *Generator) { + t.Helper() + + if len(g.ctx.templates) == 0 { + t.Error("No templates loaded") + } + if _, ok := g.ctx.templates["assertion_assertions"]; !ok { + t.Error("Missing assertion_assertions template") + } + }, + }, + { + name: "load require templates", + targetPkg: pkgRequire, + expectError: false, + checkFunc: func(t *testing.T, g *Generator) { + t.Helper() + + if len(g.ctx.templates) == 0 { + t.Error("No templates loaded") + } + if _, ok := g.ctx.templates["requirement_assertions"]; !ok { + t.Error("Missing requirement_assertions template") + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + source := model.New() + source.Package = pkgSource + + gen := New(source) + err := gen.initContext([]GenerateOption{ + WithTargetPackage(tt.targetPkg), + WithTargetRoot(t.TempDir()), + }) + if err != nil { + t.Fatalf("Failed to init context: %v", err) + } + + err = gen.loadTemplates() + + if tt.expectError { + if err == nil { + t.Error("Expected error but got nil") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if tt.checkFunc != nil { + tt.checkFunc(t, gen) + } + } + }) + } +} + +type generatorCase struct { + name string + opts []GenerateOption + expectError bool + checkFunc func(*testing.T, *Generator) +} + +func generatorCases(t *testing.T) iter.Seq[generatorCase] { + t.Helper() + + return slices.Values([]generatorCase{ + { + name: "missing target package", + opts: []GenerateOption{}, + expectError: true, + }, + { + name: "invalid target package", + opts: []GenerateOption{ + WithTargetPackage("invalid"), + }, + expectError: true, + }, + { + name: "valid assert package", + opts: []GenerateOption{ + WithTargetPackage(pkgAssert), + WithTargetRoot(t.TempDir()), + }, + expectError: false, + checkFunc: func(t *testing.T, g *Generator) { + t.Helper() + + if g.ctx.targetBase != pkgAssert { + t.Errorf("Expected targetBase '%s', got %q", pkgAssert, g.ctx.targetBase) + } + }, + }, + { + name: "valid require package", + opts: []GenerateOption{ + WithTargetPackage(pkgRequire), + WithTargetRoot(t.TempDir()), + }, + expectError: false, + checkFunc: func(t *testing.T, g *Generator) { + t.Helper() + + if g.ctx.targetBase != pkgRequire { + t.Errorf("Expected targetBase '%s', got %q", pkgRequire, g.ctx.targetBase) + } + }, + }, + }) +} + +type transformCase struct { + name string + input model.Parameters + expected string +} + +func transformCases() iter.Seq[transformCase] { + return slices.Values([]transformCase{ + { + name: "empty parameters", + input: model.Parameters{}, + expected: "", + }, + { + name: "single parameter without name", + input: model.Parameters{ + {GoType: "bool"}, + }, + expected: "bool", + }, + { + name: "single parameter with name", + input: model.Parameters{ + {Name: "value", GoType: "bool"}, + }, + expected: "(value bool)", + }, + { + name: "multiple parameters", + input: model.Parameters{ + {Name: "expected", GoType: "any"}, + {Name: "actual", GoType: "any"}, + }, + expected: "(expected any, actual any)", + }, + }) +} diff --git a/codegen/internal/generator/options.go b/codegen/internal/generator/options.go new file mode 100644 index 000000000..3a5d3686c --- /dev/null +++ b/codegen/internal/generator/options.go @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package generator + +import "golang.org/x/tools/imports" + +// GenerateOption is an option for code generation. +type GenerateOption func(*generateOptions) + +// Option is a general option for the generator. +// +// Currently unused (reserved for future use). +type Option func(*options) + +func WithTargetRoot(root string) GenerateOption { + return func(o *generateOptions) { + o.targetRoot = root + } +} + +func WithTargetPackage(pkg string) GenerateOption { + return func(o *generateOptions) { + o.targetPkg = pkg + } +} + +func WithIncludeFormatFuncs(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.enableFormat = enabled + } +} + +func WithIncludeForwardFuncs(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.enableForward = enabled + } +} + +func WithIncludeTests(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.generateTests = enabled + } +} + +func WithIncludeGenerics(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.enableGenerics = enabled + } +} + +func WithIncludeHelpers(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.generateHelpers = enabled + } +} + +func WithIncludeExamples(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.generateExamples = enabled + } +} + +func WithRunnableExamples(enabled bool) GenerateOption { + return func(o *generateOptions) { + o.runnableExamples = enabled + } +} + +type generateOptions struct { + targetPkg string + targetRoot string + enableForward bool + enableFormat bool + enableGenerics bool + generateHelpers bool + generateTests bool + generateExamples bool + runnableExamples bool + formatOptions *imports.Options +} + +type options struct { +} + +func generateOptionsWithDefaults(opts []GenerateOption) generateOptions { + o := generateOptions{ + targetRoot: ".", + enableForward: true, + enableFormat: true, + enableGenerics: false, + generateHelpers: true, + generateTests: false, + generateExamples: false, + runnableExamples: false, + } + + for _, apply := range opts { + apply(&o) + } + + return o +} + +func optionsWithDefaults(_ []Option) options { + return options{} +} diff --git a/codegen/internal/generator/templates/assertion_assertions.gotmpl b/codegen/internal/generator/templates/assertion_assertions.gotmpl new file mode 100644 index 000000000..1ff267d77 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_assertions.gotmpl @@ -0,0 +1,29 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +{{ comment .DocString }} +// +{{ docStringPackage $.Package }} +func {{ .Name }}({{ params .AllParams }}) {{ returns .Returns }} { + if h, ok := t.(H); ok { + h.Helper() + } + return {{ .TargetPackage }}.{{ .Name }}({{ forward .AllParams }}) +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_assertions_test.gotmpl b/codegen/internal/generator/templates/assertion_assertions_test.gotmpl new file mode 100644 index 000000000..bff7995f0 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_assertions_test.gotmpl @@ -0,0 +1,150 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +import ( + "net/http" + "path/filepath" + "testing" +{{ imports .Imports }} +) + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +func Test{{ .Name }}(t *testing.T) { + t.Parallel() + + {{- if (not .HasTest) }}{{/* no testcases captured from the Example section of the original function */}} + t.Skip() // this function doesn't have tests yet: feed the original function with examples to test. + {{- else }} + {{- $fn := . }} + {{- $isRequire := (eq $.Package "require") }} + {{- $first := true }} + {{- range .Tests }} + {{- if eq .ExpectedOutcome 0 }}{{/* TestSuccess */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("success", func(t *testing.T) { + t.Parallel() + + {{- if $isRequire }} + {{ $fn.Name }}(t, {{ .TestedValue }}) + // require functions don't return a value + {{- else }} + result := {{ $fn.Name }}(t, {{ .TestedValue }}) + if !result { + t.Error("{{ $fn.Name }} should return true on success") + } + {{- end }} + }) + {{- else if eq .ExpectedOutcome 1 }}{{/* TestFailure */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new({{ $fn.UseMock }}) + {{- if $isRequire }} + {{ $fn.Name }}(mock, {{ .TestedValue }}) + // require functions don't return a value + {{- else }} + result := {{ $fn.Name }}(mock, {{ .TestedValue }}) + if result { + t.Error("{{ $fn.Name }} should return false on failure") + } + {{- end }} + if !mock.failed { + t.Error("{{ $fn.Name }} {{ if eq $fn.UseMock "mockFailNowT" }}should call FailNow(){{ else }}should mark test as failed{{ end }}") + } + }) + {{- else if eq .ExpectedOutcome 2 }}{{/* TestPanic */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panics(t, func() { + {{ $fn.Name }}(t, {{ .TestedValue }}) + }, "{{ .AssertionMessage }}") + }) + {{- end }} + {{- end }} + {{- end }} +} + {{- end }} + {{- end }} +{{- end }} + +// mockT is a mock testing.T for assertion tests +type mockT struct { + failed bool +} + +func (m *mockT) Helper() {} + +func (m *mockT) Errorf(format string, args ...any) { + m.failed = true +} + +type mockFailNowT struct { + failed bool +} + +// Helper is like [testing.T.Helper] but does nothing. +func (mockFailNowT) Helper() {} + +func (m *mockFailNowT) Errorf(format string, args ...any) { + _ = format + _ = args +} + +func (m *mockFailNowT) FailNow() { + m.failed = true +} + +func testDataPath() string { + return filepath.Join({{ pathparts .TestDataPath }}) +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/codegen/internal/generator/templates/assertion_examples_test.gotmpl b/codegen/internal/generator/templates/assertion_examples_test.gotmpl new file mode 100644 index 000000000..df4acb2d3 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_examples_test.gotmpl @@ -0,0 +1,108 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }}_test + +import ( + "fmt" + "net/http" + "path/filepath" + "testing" + "github.com/go-openapi/testify/v2/{{ .Package }}" +{{ imports .Imports }} +) + +{{- $pkg := .Package }} +{{- $runnable := .RunnableExamples }} +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + {{- if not .HasSuccessTest }} + +// func Example{{ .Name }}() { +// no success example available. Please add some examples to produce a testable example. +// } + {{- else }} + +func Example{{ .Name }}() { + {{- $fn := . }} + {{- $isRequire := (eq $.Package "require") }} + {{- $first := true }} + {{- range .Tests }} + {{- if eq .ExpectedOutcome 0 }}{{/* TestSuccess */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t := new(testing.T) + {{- if $isRequire }} + {{ $pkg }}.{{ $fn.Name }}(t, {{ relocate .TestedValue $pkg }}) + fmt.Println("passed") + {{- if $runnable }} + + // Output: passed + {{- end }} + {{- else }} + success := {{ $pkg }}.{{ $fn.Name }}(t, {{ relocate .TestedValue $pkg }}) + fmt.Printf("success: %t\n", success) + {{- if $runnable }} + + // Output: success: true + {{- end }} + {{- end }} + {{- end }} + {{- break }}{{/* just produce one single example, in case there are multiple success examples */}} + {{- end }} +} + {{- end }} + {{- end }} + {{- end }} +{{- end }} + +// Test helpers (also in the tests for package {{ .Package }} +// +// This code is duplicated because the current test is run as a separate test package: {{ .Package }}_test + +func testDataPath() string { + return filepath.Join({{ pathparts .TestDataPath }}) +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface {{ .Package }}.T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/codegen/internal/generator/templates/assertion_format.gotmpl b/codegen/internal/generator/templates/assertion_format.gotmpl new file mode 100644 index 000000000..d0f57e604 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_format.gotmpl @@ -0,0 +1,35 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +{{ docStringFor "format" .Name }} +// +{{ docStringPackage $.Package }} +func {{ .Name }}f(t T, {{ params .Params }}, msg string, args ...any) {{ returns .Returns }} { + if h, ok := t.(H); ok { h.Helper() } + return {{ .TargetPackage }}.{{ .Name }}(t, {{ forward .Params }}, forwardArgs(msg, args)) +} + {{- end }} + {{- end }} +{{- end }} + +func forwardArgs(msg string, args []any) []any { + result := make([]any, len(args)+1) + result[0]=msg + copy(result[1:], args) + + return result +} diff --git a/codegen/internal/generator/templates/assertion_format_test.gotmpl b/codegen/internal/generator/templates/assertion_format_test.gotmpl new file mode 100644 index 000000000..9af9c3bd9 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_format_test.gotmpl @@ -0,0 +1,78 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( + "testing" +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +func Test{{ .Name }}f(t *testing.T) { + t.Parallel() + + {{- if (not .HasTest) }}{{/* no testcases captured from the Example section of the original function */}} + t.Skip() // this function doesn't have tests yet: feed the original function with examples to test. + {{- else }} + {{- $fn := . }} + {{- $isRequire := (eq $.Package "require") }} + {{- $first := true }} + {{- range .Tests }} + {{- if eq .ExpectedOutcome 0 }}{{/* TestSuccess */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("success", func(t *testing.T) { + t.Parallel() + +{{- if $isRequire }} + {{ $fn.Name }}f(t, {{ .TestedValue }}, "test message") + // require functions don't return a value +{{- else }} + result := {{ $fn.Name }}f(t, {{ .TestedValue }}, "test message") + if !result { + t.Error("{{ $fn.Name }}f should return true on success") + } +{{- end }} + }) + {{- else if eq .ExpectedOutcome 1 }}{{/* TestFailure */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new({{ $fn.UseMock }}) + {{- if $isRequire }} + {{ $fn.Name }}f(mock, {{ .TestedValue }}, "test message") + // require functions don't return a value + {{- else }} + result := {{ $fn.Name }}f(mock, {{ .TestedValue }}, "test message") + if result { + t.Error("{{ $fn.Name }}f should return false on failure") + } + {{- end }} + if !mock.failed { + t.Error("{{ $fn.Name }} {{ if eq $fn.UseMock "mockFailNowT" }}should call FailNow(){{ else }}should mark test as failed{{ end }}") + } + }) + {{- else if eq .ExpectedOutcome 2 }}{{/* TestPanic */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panicsf(t, func() { + {{ $fn.Name }}f(t, {{ .TestedValue }}, "test message") + }, "{{ .AssertionMessage }}") + }) + {{- end }} + {{- end }} + {{- end }} +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_forward.gotmpl b/codegen/internal/generator/templates/assertion_forward.gotmpl new file mode 100644 index 000000000..0a7fb23a9 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_forward.gotmpl @@ -0,0 +1,51 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +// {{ .Receiver }} exposes all assertion functions as methods. +// +// NOTE: assertion methods with parameterized types (generics) are not supported as methods. +// +{{ docStringPackage .Package }} +type {{ .Receiver }} struct { + t T +} + +// New makes a new [{{ .Receiver }}] object for the specified [T] (e.g. [testing.T]). +func New(t T) *{{ .Receiver }} { + return &{{ .Receiver }}{ + t: t, + } +} + +{{- range .Functions }} + {{- if and (not .IsGeneric) (not .IsHelper) (not .IsConstructor) }}{{/* generics can't be added to the receiver */}} + +{{ docStringFor "forward" .Name }} +// +{{ docStringPackage $.Package }} +func (a *{{ $.Receiver }}) {{.Name}}({{ params .Params }}, msgAndArgs ...any) {{ returns .Returns }} { + if h, ok := a.t.(H); ok { h.Helper() } + return {{ .TargetPackage }}.{{.Name}}(a.t, {{ forward .Params }}, msgAndArgs...) +} + {{- if $.EnableFormat }} + +{{ docStringFor "format" (concat $.Receiver "." .Name ) }} +// +{{ docStringPackage $.Package }} +func (a *{{ $.Receiver }}){{ .Name }}f({{ params .Params }}, msg string, args ...any) {{ returns .Returns }} { + if h, ok := a.t.(H); ok { h.Helper() } + return {{ .TargetPackage }}.{{ .Name }}(a.t, {{ forward .Params }}, forwardArgs(msg, args)) +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_forward_test.gotmpl b/codegen/internal/generator/templates/assertion_forward_test.gotmpl new file mode 100644 index 000000000..548e81e49 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_forward_test.gotmpl @@ -0,0 +1,147 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( + "testing" +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if and (not .IsGeneric) (not .IsHelper) (not .IsConstructor) }}{{/* generics can't be added to the receiver */}} + +func Test{{ $.Receiver }}{{ .Name }}(t *testing.T) { + t.Parallel() + + {{- if (not .HasTest) }}{{/* no testcases captured from the Example section of the original function */}} + t.Skip() // this function doesn't have tests yet: feed the original function with examples to test. + {{- else }} + {{- $fn := . }} + {{- $isRequire := (eq $.Package "require") }} + {{- $first := true }} + {{- range .Tests }} + {{- if eq .ExpectedOutcome 0 }}{{/* TestSuccess */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) +{{- if $isRequire }} + a.{{ $fn.Name }}({{ .TestedValue }}) + // require functions don't return a value +{{- else }} + result := a.{{ $fn.Name }}({{ .TestedValue }}) + if !result { + t.Error("{{ $.Receiver }}.{{ $fn.Name }} should return true on success") + } +{{- end }} + }) + {{- else if eq .ExpectedOutcome 1 }}{{/* TestFailure */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new({{ $fn.UseMock }}) + a := New(mock) + {{- if $isRequire }} + a.{{ $fn.Name }}({{ .TestedValue }}) + // require functions don't return a value + {{- else }} + result := a.{{ $fn.Name }}({{ .TestedValue }}) + if result { + t.Error("{{ $.Receiver }}.{{ $fn.Name }} should return false on failure") + } + {{- end }} + if !mock.failed { + t.Error("{{ $fn.Name }} {{ if eq $fn.UseMock "mockFailNowT" }}should call FailNow(){{ else }}should mark test as failed{{ end }}") + } + }) + {{- else if eq .ExpectedOutcome 2 }}{{/* TestPanic */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.{{ $fn.Name }}({{ .TestedValue }}) + }, "{{ .AssertionMessage }}") + }) + {{- end }} + {{- end }} + {{- end }} +} + {{- if $.EnableFormat }} + +func Test{{ $.Receiver }}{{ .Name }}f(t *testing.T) { + t.Parallel() + + {{- if (not .HasTest) }}{{/* no testcases captured from the Example section of the original function */}} + t.Skip() // this function doesn't have tests yet: feed the original function with examples to test. + {{- else }} + {{- $fn := . }} + {{- $isRequire := (eq $.Package "require") }} + {{- $first := true }} + {{- range .Tests }} + {{- if eq .ExpectedOutcome 0 }}{{/* TestSuccess */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) +{{- if $isRequire }} + a.{{ $fn.Name }}f({{ .TestedValue }}, "test message") + // require functions don't return a value +{{- else }} + result := a.{{ $fn.Name }}f({{ .TestedValue }}, "test message") + if !result { + t.Error("{{ $.Receiver }}.{{ $fn.Name }} should return true on success") + } +{{- end }} + }) + {{- else if eq .ExpectedOutcome 1 }}{{/* TestFailure */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new({{ $fn.UseMock }}) + a := New(mock) +{{- if $isRequire }} + a.{{ $fn.Name }}f({{ .TestedValue }}, "test message") + // require functions don't return a value +{{- else }} + result := a.{{ $fn.Name }}f({{ .TestedValue }}, "test message") + if result { + t.Error("{{ $.Receiver }}.{{ $fn.Name }} should return false on failure") + } +{{- end }} + if !mock.failed { + t.Error("{{ $.Receiver }}.{{ $fn.Name }} should mark test as failed") + } +{{- if eq $fn.UseMock "mockFailNowT" }} + if !mock.failed { + t.Error("{{ $.Receiver }}.{{ $fn.Name }}f should call FailNow()") + } +{{- end }} + }) + {{- else if eq .ExpectedOutcome 2 }}{{/* TestPanic */}} + {{- if (not $first) }}{{ println "" }}{{- end }}{{ $first = false }} + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.{{ $fn.Name }}f({{ .TestedValue }}, "test message") + }, "{{ .AssertionMessage }}") + }) + {{- end }} + {{- end }} + {{- end }} +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_helpers.gotmpl b/codegen/internal/generator/templates/assertion_helpers.gotmpl new file mode 100644 index 000000000..bbea35ef8 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_helpers.gotmpl @@ -0,0 +1,22 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if .IsHelper }} + +{{ comment .DocString }} +func {{ .Name }}({{ params .AllParams }}) {{ returns .Returns }} { + return {{ .TargetPackage }}.{{ .Name }}({{ forward .AllParams }}) +} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_helpers_test.gotmpl b/codegen/internal/generator/templates/assertion_helpers_test.gotmpl new file mode 100644 index 000000000..bd7ca5a2c --- /dev/null +++ b/codegen/internal/generator/templates/assertion_helpers_test.gotmpl @@ -0,0 +1,26 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( + "testing" +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if .IsHelper }} + +func Test{{ .Name }}f(t *testing.T) { + {{- if (not .HasTest) }} + t.Skip() // this function doesn't have tests yet + {{- else }} + // TODO + {{- end }} +} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/assertion_types.gotmpl b/codegen/internal/generator/templates/assertion_types.gotmpl new file mode 100644 index 000000000..d298221a5 --- /dev/null +++ b/codegen/internal/generator/templates/assertion_types.gotmpl @@ -0,0 +1,73 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- with .Consts }} + +const ( + {{- range $i,$v := . }} + {{- if gt $i 0 }}{{ println "" }}{{- end }} + {{- with $v }} + {{ comment .DocString }} + {{ .Name }} = {{ .TargetPackage }}.{{ .Name }} + {{- end }} + {{- end }} +) +{{- end }} + +{{- with .Vars }} + +var ( + {{- range $i,$v := . }} + {{- if gt $i 0 }}{{ println "" }}{{- end }} + {{- with $v }} + {{ comment .DocString }} + {{ .Name }} = {{ .TargetPackage }}.{{ .Name }} + {{- end }} + {{- end }} +) +{{- end }} + +{{- with .Types }} + +type ( + {{- $first := true }} + {{- $isRequire := (eq $.Package "require") }} + {{- range . }} + {{- if not (eq .Name $.Receiver) }}{{/* we declare that type separately */}} + {{- if not $first }}{{ println "" }}{{- end }} + {{- $first = false }} + {{ comment .DocString }} + {{- if and (eq .Name "T") (eq $.Package "require") }}{{/* to use with require, T must support FailNow() */}} + {{ .Name }} interface { + {{ .TargetPackage }}.{{ .Name }} + FailNow() + } + {{- else if and $isRequire .Function ( hasSuffix .Name "Func" ) (gt (len .Function.Returns) 0) }}{{/* special override with require of function types */}} + {{ .Name }} func({{ params .Function.AllParams }}) + {{- else }} + {{ .Name }} = {{ .TargetPackage }}.{{ .Name }} + {{- end }} + {{- end }} + {{- end }} +) +{{- end }} + +// Type declarations for backward compatibility. +type ( + // TestingT is like [T] and is declared here to remain compatible with previous versions of this package. + // + // Most users should not be affected, as the implementation of [T] that is widely used is [testing.T]. + // + // Deprecated: use [T] as a more concise alternative. + TestingT = T +) diff --git a/codegen/internal/generator/templates/requirement_assertions.gotmpl b/codegen/internal/generator/templates/requirement_assertions.gotmpl new file mode 100644 index 000000000..f97d57e11 --- /dev/null +++ b/codegen/internal/generator/templates/requirement_assertions.gotmpl @@ -0,0 +1,35 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +{{ comment .DocString }} +// +{{ docStringPackage $.Package }} +func {{ .Name }}({{ params .AllParams }}) { + if h, ok := t.(H); ok { h.Helper() } + {{- if or (eq .Name "Fail") (eq .Name "FailNow") }}{{/* special semantics for these two, which can only fail */}} + _ = {{ .TargetPackage }}.{{ .Name }}({{ forward .AllParams }}) + {{- else }} + if {{ .TargetPackage }}.{{ .Name }}({{ forward .AllParams }}) { + return + } + {{- end }} + + t.FailNow() +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/generator/templates/requirement_format.gotmpl b/codegen/internal/generator/templates/requirement_format.gotmpl new file mode 100644 index 000000000..47ef5f37f --- /dev/null +++ b/codegen/internal/generator/templates/requirement_format.gotmpl @@ -0,0 +1,43 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +{{- range .Functions }} + {{- if or (not .IsGeneric) ($.EnableGenerics) }} + {{- if and (not .IsHelper) (not .IsConstructor) }} + +{{ docStringFor "format" .Name }} +// +{{ docStringPackage $.Package }} +func {{ .Name }}f(t T, {{ params .Params }}, msg string, args ...any) { + if h, ok := t.(H); ok { h.Helper() } + {{- if or (eq .Name "Fail") (eq .Name "FailNow") }}{{/* special semantics for these two, which can only fail */}} + _ = {{ .TargetPackage }}.{{ .Name }}(t, {{ forward .Params }}, forwardArgs(msg, args)) + {{- else }} + if {{ .TargetPackage }}.{{ .Name }}(t, {{ forward .Params }}, forwardArgs(msg, args)) { + return + } + {{- end }} + + t.FailNow() +} + {{- end }} + {{- end }} +{{- end }} + +func forwardArgs(msg string, args []any) []any { + result := make([]any, len(args)+1) + result[0]=msg + copy(result[1:], args) + + return result +} diff --git a/codegen/internal/generator/templates/requirement_forward.gotmpl b/codegen/internal/generator/templates/requirement_forward.gotmpl new file mode 100644 index 000000000..cd5614dcf --- /dev/null +++ b/codegen/internal/generator/templates/requirement_forward.gotmpl @@ -0,0 +1,69 @@ +{{ comment .Copyright }} + +// Code generated with {{ .Tool }}; DO NOT EDIT. + +package {{ .Package }} + +{{- if .Imports.HasImports }} + +import ( +{{ imports .Imports }} +) +{{- end }} + +// {{ .Receiver }} exposes all assertion functions as methods. +// +// NOTE: assertion methods with parameterized types (generics) are not supported as methods. +// +{{ docStringPackage .Package }} +type {{ .Receiver }} struct { + t T +} + +// New makes a new [{{ .Receiver }}] object for the specified [T] (e.g. [testing.T]). +func New(t T) *{{ .Receiver }} { + return &{{ .Receiver }}{ + t: t, + } +} + +{{- range .Functions }} + {{- if and (not .IsGeneric) (not .IsHelper) (not .IsConstructor) }}{{/* generics can't be added to the receiver */}} + +{{ docStringFor "forward" .Name }} +// +{{ docStringPackage $.Package }} +func (a *{{ $.Receiver }}) {{.Name}}({{ params .Params }}, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } + {{- if or (eq .Name "Fail") (eq .Name "FailNow") }}{{/* special semantics for these two, which can only fail */}} + _ = {{ .TargetPackage }}.{{.Name}}(a.t, {{ forward .Params }}, msgAndArgs...) + {{- else }} + if {{ .TargetPackage }}.{{.Name}}(a.t, {{ forward .Params }}, msgAndArgs...) { + return + } + {{- end }} + + a.t.FailNow() +} + {{- if $.EnableFormat }} + +{{ docStringFor "format" (concat $.Receiver "." .Name) }} +// +{{ docStringPackage $.Package }} +func (a *{{ $.Receiver }}){{ .Name }}f({{ params .Params }}, msg string, args ...any) { + if h, ok := a.t.(H); ok { + h.Helper() + } + {{- if or (eq .Name "Fail") (eq .Name "FailNow") }}{{/* special semantics for these two, which can only fail */}} + _ = {{ .TargetPackage }}.{{ .Name }}(a.t, {{ forward .Params }}, forwardArgs(msg, args)) + {{- else }} + if {{ .TargetPackage }}.{{ .Name }}(a.t, {{ forward .Params }}, forwardArgs(msg, args)) { + return + } + {{- end }} + + a.t.FailNow() +} + {{- end }} + {{- end }} +{{- end }} diff --git a/codegen/internal/model/model.go b/codegen/internal/model/model.go new file mode 100644 index 000000000..856baa2c9 --- /dev/null +++ b/codegen/internal/model/model.go @@ -0,0 +1,160 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package model + +import ( + "maps" + "slices" + "strings" +) + +// AssertionPackage describes the internal/assertions package. +type AssertionPackage struct { + Tool string + Package string + DocString string + Copyright string + Receiver string + TestDataPath string + Imports ImportMap + EnableFormat bool + EnableForward bool + EnableGenerics bool + EnableExamples bool + RunnableExamples bool + + Functions []Function + Types []Ident + Consts []Ident + Vars []Ident +} + +// New empty [AssertionPackage]. +func New() *AssertionPackage { + const ( + allocatedFuncs = 100 + allocatedIdents = 50 + ) + + return &AssertionPackage{ + // preallocate with sensible defaults for our package + Functions: make([]Function, 0, allocatedFuncs), + Types: make([]Ident, 0, allocatedIdents), + Consts: make([]Ident, 0, allocatedIdents), + Vars: make([]Ident, 0, allocatedIdents), + } +} + +func (a *AssertionPackage) Clone() *AssertionPackage { + b := *a + maps.Copy(b.Imports, a.Imports) + + return &b +} + +// ImportMap represents the imports for the analyzed package. +type ImportMap map[string]string + +func (m ImportMap) HasImports() bool { + return len(m) > 0 +} + +// Function represents an assertion function extracted from the source package. +type Function struct { + ID string + Name string + SourcePackage string + TargetPackage string + DocString string + UseMock string + Params Parameters + AllParams Parameters + Returns Parameters + IsGeneric bool + IsHelper bool + IsConstructor bool + Tests []Test +} + +func (f Function) HasTest() bool { + return len(f.Tests) > 0 +} + +func (f Function) HasSuccessTest() bool { + return slices.ContainsFunc(f.Tests, func(e Test) bool { + return e.ExpectedOutcome == TestSuccess + }) +} + +type Parameters []Parameter + +func (vars Parameters) String() string { + var b strings.Builder + l := len(vars) + + if l == 0 { + return "" + } + + if l > 1 || vars[0].Name != "" { + b.WriteByte('(') + } + + if vars[0].Name != "" { + b.WriteString(vars[0].Name) + b.WriteByte(' ') + } + b.WriteString(vars[0].GoType) + + for _, v := range vars[1:] { + b.WriteByte(',') + b.WriteByte(' ') + if v.Name != "" { + b.WriteString(v.Name) + b.WriteByte(' ') + } + b.WriteString(v.GoType) + + } + + if l > 1 || vars[0].Name != "" { + b.WriteByte(')') + } + + return b.String() +} + +// Parameter represents a function parameter or return value. +type Parameter struct { + Name string + GoType string + Selector string + IsVariadic bool +} + +// Ident represents an exported identifier (type, constant, or variable) from the source package. +type Ident struct { + ID string + Name string + SourcePackage string + TargetPackage string + DocString string + IsAlias bool + Function *Function // for function types +} + +// Test captures simple test values to use with generated tests. +type Test struct { + TestedValue string + ExpectedOutcome TestExpectedOutcome + AssertionMessage string +} + +type TestExpectedOutcome uint8 + +const ( + TestSuccess TestExpectedOutcome = iota + TestFailure + TestPanic +) diff --git a/codegen/internal/scanner/doc.go b/codegen/internal/scanner/doc.go new file mode 100644 index 000000000..6148799f4 --- /dev/null +++ b/codegen/internal/scanner/doc.go @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Package scanner exposes a golang source [Scanner]. +// +// The [Scanner] scans the internal/assertions package. +// +// It extracts all testify helpers methods, types, and +// package-level variables and constants. +package scanner diff --git a/codegen/internal/scanner/options.go b/codegen/internal/scanner/options.go new file mode 100644 index 000000000..094ef92ce --- /dev/null +++ b/codegen/internal/scanner/options.go @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package scanner + +type Option func(*options) + +type options struct { + dir string + pkg string +} + +// WithWorkDir gives a workdir to the code scanner. +func WithWorkDir(dir string) Option { + return func(o *options) { + o.dir = dir + } +} + +// WithPackage indicates which package is scanned. +func WithPackage(pkg string) Option { + return func(o *options) { + o.pkg = pkg + } +} + +func optionsWithDefaults(opts []Option) options { + o := options{ + dir: "..", + pkg: "github.com/go-openapi/testify/v2/internal/assertions", + } + + for _, apply := range opts { + apply(&o) + } + + return o +} diff --git a/codegen/internal/scanner/scanner.go b/codegen/internal/scanner/scanner.go new file mode 100644 index 000000000..4f2ff2bb6 --- /dev/null +++ b/codegen/internal/scanner/scanner.go @@ -0,0 +1,646 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package scanner + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "path/filepath" + "regexp" + "runtime/debug" + "strings" + + "github.com/go-openapi/testify/v2/codegen/internal/model" + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/go/packages" +) + +const pkgLoadMode = packages.NeedName | packages.NeedFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo + +const ( + successPrefix = "success:" + failurePrefix = "failure:" + panicPrefix = "panic:" +) + +// Scanner scans the internal/assertions package and extracts all functions, types, and metadata. +type Scanner struct { + options + + scanConfig *packages.Config + syntaxPackage []*ast.File + typedPackage *types.Package + typesInfo *types.Info + filesMap map[*token.File]*ast.File + fileSet *token.FileSet + importAliases map[string]string // import path -> alias name used in source + result *model.AssertionPackage +} + +// New [Scanner] ready to [Scanner.Scan] code. +func New(opts ...Option) *Scanner { + o := optionsWithDefaults(opts) + + cfg := &packages.Config{ + Dir: o.dir, + Mode: pkgLoadMode, + Tests: false, // we infer generated tests from production code and ignore internal tests + } + + return &Scanner{ + options: o, + scanConfig: cfg, + result: model.New(), + } +} + +// Scan a source package an returns a [model.AssertionPackage] data structure suited for code generation. +func (s *Scanner) Scan() (*model.AssertionPackage, error) { + pkgs, err := packages.Load(s.scanConfig, s.pkg) + if err != nil { + return nil, err + } + + if len(pkgs) == 0 { + return nil, fmt.Errorf("could not parse package: %v", s.pkg) + } + + // we consider only one package + pkg := pkgs[0] + s.syntaxPackage = pkg.Syntax + s.typedPackage = pkg.Types + if s.typedPackage == nil { + return nil, fmt.Errorf("something is wrong. Could not parse packages: %v", s.pkg) + } + s.typesInfo = pkg.TypesInfo + s.filesMap = buildFilesMap(pkg) + s.fileSet = pkg.Fset + s.importAliases = buildImportAliases(pkg) + + s.resolveScope() + s.result.Tool = moduleName() + s.result.Copyright = s.extractCopyright().Text() + s.result.DocString = s.extractPackageComments().Text() + s.result.TestDataPath = filepath.Join(pkg.Dir, "testdata") + + return s.result, nil +} + +func (s *Scanner) resolveScope() { + s.result.Package = s.typedPackage.Path() + + for _, pkg := range s.typedPackage.Imports() { + s.addImport(pkg) + } + + scope := s.typedPackage.Scope() + for _, symbol := range scope.Names() { + object := scope.Lookup(symbol) + if object == nil { // something went wrong + continue + } + if !object.Exported() { + continue + } + + switch typedObject := object.(type) { + case *types.Func: + s.addFunction(typedObject) + case *types.Const: + s.addConst(typedObject) + case *types.Var: + s.addVar(typedObject) + case *types.TypeName: + s.addNamedType(typedObject) + // NOTE: known limitation this does not support type or var aliases in the source package + default: + continue + } + } +} + +// buildFilesMap constructs a lookup index to help bridge token position vs ast.File. +func buildFilesMap(pkg *packages.Package) map[*token.File]*ast.File { + filesMap := make(map[*token.File]*ast.File, len(pkg.Syntax)) + + for _, astFile := range pkg.Syntax { + tokenFile := pkg.Fset.File(astFile.Pos()) // o(log n) lookup + filesMap[tokenFile] = astFile + } + + return filesMap +} + +// buildImportAliases scans import declarations to find aliases used in the source. +// +// This bridges the AST view (import aliases) with the types view (package paths). +func buildImportAliases(pkg *packages.Package) map[string]string { + aliases := make(map[string]string) + + for _, astFile := range pkg.Syntax { + for _, importSpec := range astFile.Imports { + // Get the import path (remove quotes) + importPath := strings.Trim(importSpec.Path.Value, `"`) + + var alias string + if importSpec.Name != nil { + // Explicit alias: import foo "bar/baz" + alias = importSpec.Name.Name + + // Skip blank imports and dot imports for type qualification + if alias == "_" || alias == "." { + continue + } + } else { + // No explicit alias - need to determine the package name + // Try to find it in the loaded imports + for _, imported := range pkg.Imports { + if imported.PkgPath == importPath { + alias = imported.Name + break + } + } + + // Fallback: use last segment of import path + if alias == "" { + parts := strings.Split(importPath, "/") + alias = parts[len(parts)-1] + } + } + + // Store the mapping (later imports override earlier ones if there are conflicts) + aliases[importPath] = alias + } + } + + return aliases +} + +func (s *Scanner) addImport(pkg *types.Package) { + if s.result.Imports == nil { + s.result.Imports = make(model.ImportMap) + } + + // use the alias if one exists, otherwise use the package name. + // (this ensures the key matches what elidedQualifier() returns) + key := pkg.Name() // default to package name + if alias, ok := s.importAliases[pkg.Path()]; ok { + key = alias // use the alias from source + } + + s.result.Imports[key] = pkg.Path() +} + +func (s *Scanner) addFunction(object *types.Func) { + docComment := s.extractComments(object) + + // Extract the base function signature + function := s.extractFunctionSignature(object.Signature(), object.Name()) + + // Add function-specific metadata + function.ID = object.Id() + function.SourcePackage = object.Pkg().Path() // full package name + function.TargetPackage = object.Pkg().Name() // short package name + function.DocString = docComment.Text() + function.Tests = parseTestExamples(docComment) // extract test values from Example section + + s.result.Functions = append(s.result.Functions, function) +} + +func (s *Scanner) addConst(object *types.Const) { + constant := model.Ident{ + ID: object.Id(), + Name: object.Name(), + SourcePackage: object.Pkg().Path(), + TargetPackage: object.Pkg().Name(), // short package name + DocString: s.extractComments(object).Text(), + } + s.result.Consts = append(s.result.Consts, constant) +} + +func (s *Scanner) addVar(object *types.Var) { + variable := model.Ident{ + ID: object.Id(), + Name: object.Name(), + SourcePackage: object.Pkg().Path(), + TargetPackage: object.Pkg().Name(), // short package name + DocString: s.extractComments(object).Text(), + } + + // Check if this variable is a function type + if sig, ok := object.Type().(*types.Signature); ok { + fn := s.extractFunctionSignature(sig, object.Name()) + variable.Function = &fn + } + + s.result.Vars = append(s.result.Vars, variable) +} + +func (s *Scanner) addNamedType(object *types.TypeName) { + namedType := model.Ident{ + ID: object.Id(), + Name: object.Name(), + SourcePackage: object.Pkg().Path(), + TargetPackage: object.Pkg().Name(), // short package name + IsAlias: object.IsAlias(), + DocString: s.extractComments(object).Text(), + } + + // Check if this named type is a function type + // For named types, we need to check the underlying type + if named, ok := object.Type().(*types.Named); ok { + if sig, ok := named.Underlying().(*types.Signature); ok { + fn := s.extractFunctionSignature(sig, object.Name()) + namedType.Function = &fn + } + } else if sig, ok := object.Type().(*types.Signature); ok { + // Type alias to a function type + fn := s.extractFunctionSignature(sig, object.Name()) + namedType.Function = &fn + } + + s.result.Types = append(s.result.Types, namedType) +} + +// extractFunctionSignature extracts function signature details from a types.Signature. +// +// This is used for both regular functions and function types (var/type declarations). +func (s *Scanner) extractFunctionSignature(signature *types.Signature, name string) model.Function { + function := model.Function{ + Name: name, + } + + // Check if generic + isGeneric := signature.TypeParams() != nil + function.IsGeneric = isGeneric + + // Extract parameters + params := signature.Params() + function.AllParams = make(model.Parameters, 0, params.Len()) + function.Params = make(model.Parameters, 0, params.Len()) + + for param := range params.Variables() { + p := model.Parameter{ + Name: param.Name(), + GoType: s.elidedType(param.Type()), + Selector: s.elidedQualifier(param.Type()), + } + function.AllParams = append(function.AllParams, p) + + if p.Name != "t" && p.Name != "msgAndArgs" { + // filtered params + function.Params = append(function.Params, p) + } + } + + // Handle variadic parameters + l := params.Len() + if signature.Variadic() && l > 0 { + // introduce ellipsis notation + lastParam := params.At(l - 1) + lastType := lastParam.Type() + if asSlice, ok := lastType.(*types.Slice); ok { // should be always ok + elemGoType := s.elidedType(asSlice.Elem()) + function.AllParams[len(function.AllParams)-1].GoType = "..." + elemGoType + function.AllParams[len(function.AllParams)-1].IsVariadic = true + + // check filtered params + if len(function.Params) > 0 && function.Params[len(function.Params)-1].Name == function.AllParams[len(function.AllParams)-1].Name { + function.Params[len(function.Params)-1].GoType = "..." + elemGoType + function.Params[len(function.Params)-1].IsVariadic = true + } + } + } + + // Extract return values + results := signature.Results() + function.Returns = make(model.Parameters, 0, results.Len()) + for result := range results.Variables() { + function.Returns = append(function.Returns, model.Parameter{ + Name: result.Name(), + GoType: s.elidedType(result.Type()), + Selector: s.elidedQualifier(result.Type()), + }) + } + + // Detect helpers (not assertions) + function.IsHelper = l == 0 || (len(function.AllParams) > 0 && function.AllParams[0].Name != "t") + function.IsConstructor = name == "New" + + return function +} + +// qualifier returns the appropriate package name for type qualification. +// +// It uses import aliases from the source (AST) rather than the package's actual name. +func (s *Scanner) qualifier(pkg *types.Package) string { + if pkg == nil { + return "" + } + + // If it's the current package being scanned, no qualification needed + if pkg == s.typedPackage { + return "" + } + + // Look up the alias used in source imports + if alias, ok := s.importAliases[pkg.Path()]; ok { + return alias + } + + // Fallback to the package's actual name + return pkg.Name() +} + +// elidedType returns a string representation of the type with package names as they appear in source. +// +// Uses import aliases when available (e.g., "httputil.Handler" if imported as "httputil"). +func (s *Scanner) elidedType(t types.Type) string { + return types.TypeString(t, s.qualifier) +} + +// elidedQualifier returns the selector used for a type, as its import package alias used in source, +// or the empty string if this is a local declaration. +func (s *Scanner) elidedQualifier(t types.Type) string { + const maxInterestingParts = 2 + parts := strings.SplitN(types.TypeString(t, s.qualifier), ".", maxInterestingParts) + if len(parts) > 1 { + return parts[0] + } + + return "" +} + +// extractPackageComments finds the package-level comment that +// describes the source package. +func (s *Scanner) extractPackageComments() *ast.CommentGroup { + for _, file := range s.syntaxPackage { + if file.Doc == nil { + continue + } + + return file.Doc + } + + // safeguard: never returns nil + return &ast.CommentGroup{} +} + +var copyrightRex = regexp.MustCompile(`(?i)copyright`) + +// extractCopyright scans source files and expects that at least one of those contains +// a leading comment line with the string "copyright". This comment group is assigned +// to the copyright heading that will be retained. +func (s *Scanner) extractCopyright() *ast.CommentGroup { +FILE: + for _, file := range s.syntaxPackage { + if len(file.Comments) == 0 { + continue + } + + firstGroup := file.Comments[0] + + for _, line := range firstGroup.List { + if line.Slash >= file.Package { + // copyright comment must be before the "package" stanza + continue FILE + } + + if copyrightRex.MatchString(line.Text) { + // first file found with leading comments + return firstGroup + } + } + } + + // safeguard: never returns nil + return &ast.CommentGroup{} +} + +// extractComments retrieves the docstring for an object. +// +// It never returns nil: if no comment is present an empty but valid [ast.CommentGroup] is returned. +// +// NOTE: comment prioritization rule is: +// 1. GenDecl.Doc = leading comment for the entire declaration block +// 2. Spec.Doc = individual doc for that specific spec +func (s *Scanner) extractComments(object types.Object) *ast.CommentGroup { + pos := object.Pos() + if !pos.IsValid() { + return &ast.CommentGroup{} + } + + tokenFile := s.fileSet.File(pos) // o(log n) lookup + if tokenFile == nil { + return &ast.CommentGroup{} + } + + astFile := s.filesMap[tokenFile] // o(1) lookup + if astFile == nil { + return &ast.CommentGroup{} + } + + path, _ := astutil.PathEnclosingInterval(astFile, pos, pos) + for _, node := range path { + declaration, ok := node.(ast.Decl) + if !ok { + continue + } + + return extractCommentFromDecl(declaration, object) + } + + return &ast.CommentGroup{} +} + +func extractCommentFromDecl(declaration ast.Decl, object types.Object) *ast.CommentGroup { + switch typedDeclaration := declaration.(type) { + case *ast.GenDecl: // const, var, type declaration + for _, spec := range typedDeclaration.Specs { + comment := extractCommentFromTypeSpec(typedDeclaration, spec, object) + if comment != nil { + return comment + } + } + case *ast.FuncDecl: // a function + if typedDeclaration.Doc != nil { + return typedDeclaration.Doc + } + } + + return &ast.CommentGroup{} +} + +func extractCommentFromTypeSpec(typedDeclaration *ast.GenDecl, spec ast.Spec, object types.Object) *ast.CommentGroup { + switch typedSpec := spec.(type) { + case *ast.TypeSpec: + // for TypeSpec, check if it matches (though usually only 1 spec per GenDecl for types) + if typedSpec.Name.Name != object.Name() { + return nil + } + + // return Doc, checking both GenDecl.Doc and TypeSpec.Doc + if typedDeclaration.Doc != nil { + return typedDeclaration.Doc + } + + if typedSpec.Doc != nil { + return typedSpec.Doc + } + case *ast.ValueSpec: + for _, ident := range typedSpec.Names { + if ident.Name != object.Name() { + return nil + } + + // return Doc, checking both GenDecl.Doc and ValueSpec.Doc + if typedDeclaration.Doc != nil { + return typedDeclaration.Doc + } + + if typedSpec.Doc != nil { + return typedSpec.Doc + } + } + } + + return nil +} + +// parseTestExamples extracts test examples from doc comments. +// +// It looks for an "Examples:" or "Example:" section and parses lines like: +// - success: +// - failure: +// - panic: +// +// Assumption: we use regular "//" comments, not "/* ... */". +func parseTestExamples(docComment *ast.CommentGroup) []model.Test { + if docComment == nil { + return nil + } + + const usualNumberOfExamples = 2 + tests := make([]model.Test, 0, usualNumberOfExamples) + + inExamplesSection := false // comments are expected to contain an Example[s] or # Example[s] section + inValueSection := false + + for _, comment := range docComment.List { + text := strings.TrimPrefix(comment.Text, "//") + text = strings.TrimSpace(text) + + if inValueSection && len(tests) > 0 && text != "" && !startAnotherSection(text) && !startExampleValue(text) { + // check if a comment line follows an example value: this would the assertion message + tests[len(tests)-1].AssertionMessage = text + inValueSection = false + + continue + } + + inValueSection = false + + // Check if we're entering the Examples section + if startExampleSection(text) { + inExamplesSection = true + continue + } + + // Skip until we find the Examples section + if !inExamplesSection { + continue + } + + // Stop if we hit another section (starts with capital letter and ends with colon) + if startAnotherSection(text) { + break + } + + // parse test lines: "success: { values to put in the test }", "failure: ..." or "panic: ..." + // After each value line, we may found an additional text to be used as an assertion message. + switch { + case strings.HasPrefix(text, successPrefix): + inValueSection = true + if testcase, ok := parseTestValue(successPrefix, model.TestSuccess, text); ok { + tests = append(tests, testcase) + } + case strings.HasPrefix(text, failurePrefix): + inValueSection = true + if testcase, ok := parseTestValue(failurePrefix, model.TestFailure, text); ok { + tests = append(tests, testcase) + } + case strings.HasPrefix(text, panicPrefix): + inValueSection = true + if testcase, ok := parseTestValue(panicPrefix, model.TestPanic, text); ok { + tests = append(tests, testcase) + } + } + } + + return tests +} + +// moduleName returns the main module name of the caller. +// +// This identifies the tool currently running the analysis. +func moduleName() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "" + } + var ( + modVersion string + gitVersion string + ) + + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + gitVersion = setting.Value + } + } + + if info.Main.Version == "(devel)" { + modVersion = "master" + } else { + modVersion = info.Main.Version + } + + final := info.Main.Path + "@" + modVersion + if gitVersion != "" { + final += " [sha: " + gitVersion + "]" + } + + return final +} + +func startExampleSection(text string) bool { + return strings.HasPrefix(text, "Examples:") || + strings.HasPrefix(text, "Example:") || + strings.HasPrefix(text, "# Example") || + strings.HasPrefix(text, "# Examples") +} + +func startAnotherSection(text string) bool { + return len(text) > 0 && (text[0] >= 'A' && text[0] <= 'Z' && strings.HasSuffix(text, ":")) || strings.HasPrefix(text, "# ") +} + +func startExampleValue(text string) bool { + return strings.HasPrefix(text, successPrefix) || strings.HasPrefix(text, failurePrefix) || strings.HasPrefix(text, panicPrefix) +} + +func parseTestValue(placeHolder string, outcome model.TestExpectedOutcome, text string) (model.Test, bool) { + value := strings.TrimSpace(strings.TrimPrefix(text, placeHolder)) + _, isTodo := strings.CutPrefix(value, "// TODO") + + if value != "" && !isTodo { + return model.Test{ + TestedValue: value, + ExpectedOutcome: outcome, + }, true + } + + return model.Test{}, false +} diff --git a/codegen/internal/scanner/scanner_test.go b/codegen/internal/scanner/scanner_test.go new file mode 100644 index 000000000..14c3e5c6f --- /dev/null +++ b/codegen/internal/scanner/scanner_test.go @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package scanner + +import ( + "os" + "testing" + + "github.com/go-openapi/testify/v2/internal/spew" +) + +// TestScanner exercises the [Scanner] without asserting anything else than running without error. +// +// You may use this smoke test to verify the content of the constructed model. +func TestScanner(t *testing.T) { + s := New() + + r, err := s.Scan() + if err != nil { + t.Error(err) + t.FailNow() + } + + if isCI := os.Getenv("CI"); isCI != "" { + // skip output when run on CI + return + } + spew.Config = spew.ConfigState{ + DisableMethods: true, + } + + spew.Dump(r) +} diff --git a/codegen/main.go b/codegen/main.go new file mode 100644 index 000000000..8561508d1 --- /dev/null +++ b/codegen/main.go @@ -0,0 +1,88 @@ +// Package main provides the testify code generator. +// +// This program reads all assertion functions from the internal/assertions package and +// automatically generates the corresponding packages assert and require with all variants. +package main + +import ( + "flag" + "log" + "strings" + + "github.com/go-openapi/testify/v2/codegen/internal/generator" + "github.com/go-openapi/testify/v2/codegen/internal/scanner" +) + +type config struct { + dir string + targetRoot string + inputPkg string + outputPkgs string + + includeFmt bool + includeFwd bool + includeTst bool + includeGen bool + includeHlp bool + includeExa bool + runExa bool +} + +func main() { + cfg := new(config) + registerFlags(cfg) + flag.Parse() // exits if invalid flags + + if err := execute(cfg); err != nil { + log.Fatal(err) + } +} + +func registerFlags(cfg *config) { + flag.StringVar(&cfg.dir, "work-dir", "..", "working directory to scan for package (default is the parent folder)") + flag.StringVar(&cfg.inputPkg, "input-package", "github.com/go-openapi/testify/v2/internal/assertions", "source package to scan to produce generated output") + flag.StringVar(&cfg.outputPkgs, "output-packages", "assert,require", "package(s) to generate") + flag.StringVar(&cfg.targetRoot, "target-root", "..", "where to place the generated packages (default is in the parent folder)") + + flag.BoolVar(&cfg.includeFmt, "include-format-funcs", true, "include format functions such as Errorf and Equalf") + flag.BoolVar(&cfg.includeFwd, "include-forward-funcs", true, "include forward assertions functions as methods of the Assertions object") + flag.BoolVar(&cfg.includeTst, "include-tests", true, "generate the tests in the target package(s)") + flag.BoolVar(&cfg.includeGen, "include-generics", false, "include generic functions") + flag.BoolVar(&cfg.includeHlp, "include-helpers", true, "include helper functions that are not assertions") + flag.BoolVar(&cfg.includeExa, "include-examples", true, "include generated testable examples") + flag.BoolVar(&cfg.runExa, "runnable-examples", true, "include Output to generated testable examples, so they are run as tests") +} + +func execute(cfg *config) error { + scanner := scanner.New( + scanner.WithWorkDir(cfg.dir), + scanner.WithPackage(cfg.inputPkg), + ) + scanned, err := scanner.Scan() + if err != nil { + return err + } + + builder := generator.New(scanned) + + for targetPkg := range strings.SplitSeq(cfg.outputPkgs, ",") { + err = builder.Generate( + // where to generate + generator.WithTargetRoot(cfg.targetRoot), + generator.WithTargetPackage(targetPkg), + // what to generate + generator.WithIncludeFormatFuncs(cfg.includeFmt), + generator.WithIncludeForwardFuncs(cfg.includeFwd), + generator.WithIncludeGenerics(cfg.includeGen), + generator.WithIncludeTests(cfg.includeTst), + generator.WithIncludeHelpers(cfg.includeHlp), + generator.WithIncludeExamples(cfg.includeExa), + generator.WithRunnableExamples(cfg.runExa), + ) + if err != nil { + return err + } + } + + return nil +} diff --git a/codegen/main_test.go b/codegen/main_test.go new file mode 100644 index 000000000..bdfae58ab --- /dev/null +++ b/codegen/main_test.go @@ -0,0 +1,152 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "iter" + "os" + "path/filepath" + "slices" + "testing" +) + +// TestExecute verifies the execute function works with valid configuration. +func TestExecute(t *testing.T) { + // Skip if we're in a short test run + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + + tmpDir := t.TempDir() + targetRoot := filepath.Join(tmpDir, "output") + + cfg := &config{ + dir: "..", + inputPkg: "github.com/go-openapi/testify/v2/internal/assertions", + outputPkgs: "assert", + targetRoot: targetRoot, + includeFmt: true, + includeFwd: true, + includeTst: true, + includeGen: false, + includeHlp: true, + includeExa: true, + runExa: true, + } + + err := execute(cfg) + if err != nil { + t.Fatalf("Execute failed: %v", err) + } + + // Verify that the assert package was generated + assertPkg := filepath.Join(targetRoot, "assert") + if _, err := os.Stat(assertPkg); os.IsNotExist(err) { + t.Error("Assert package directory was not created") + } + + // Verify key generated files exist + expectedFiles := []string{ + "assert_types.go", + "assert_assertions.go", + "assert_format.go", + "assert_forward.go", + "assert_helpers.go", + } + + for _, file := range expectedFiles { + path := filepath.Join(assertPkg, file) + if _, err := os.Stat(path); os.IsNotExist(err) { + t.Errorf("Expected file %s was not generated", file) + } + } +} + +// TestExecuteMultiplePackages verifies that generating multiple packages works. +func TestExecuteMultiplePackages(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + + tmpDir := t.TempDir() + targetRoot := filepath.Join(tmpDir, "output") + + cfg := &config{ + dir: "..", + inputPkg: "github.com/go-openapi/testify/v2/internal/assertions", + outputPkgs: "assert,require", + targetRoot: targetRoot, + includeFmt: false, + includeFwd: false, + includeTst: false, + includeGen: false, + includeHlp: false, + includeExa: false, + runExa: false, + } + + err := execute(cfg) + if err != nil { + t.Fatalf("Execute failed: %v", err) + } + + // Verify both packages were generated + for _, pkg := range []string{"assert", "require"} { + pkgDir := filepath.Join(targetRoot, pkg) + if _, err := os.Stat(pkgDir); os.IsNotExist(err) { + t.Errorf("Package %s was not created", pkg) + } + + // Verify at least the main assertions file exists + assertionsFile := filepath.Join(pkgDir, pkg+"_assertions.go") + if _, err := os.Stat(assertionsFile); os.IsNotExist(err) { + t.Errorf("Assertions file for %s was not generated", pkg) + } + } +} + +// TestExecuteInvalidConfig verifies error handling for invalid configuration. +func TestExecuteInvalidConfig(t *testing.T) { + t.Parallel() + dir := t.TempDir() + + for tt := range invalidConfigCases(dir) { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + err := execute(tt.cfg) + if err == nil { + t.Error("Expected error but got nil") + } + }) + } +} + +type invalidConfigCase struct { + name string + cfg *config +} + +func invalidConfigCases(dir string) iter.Seq[invalidConfigCase] { + return slices.Values([]invalidConfigCase{ + { + name: "invalid input package", + cfg: &config{ + dir: "..", + inputPkg: "invalid/package/path", + outputPkgs: "assert", + targetRoot: dir, + }, + }, + { + name: "nonexistent work dir", + cfg: &config{ + dir: "/nonexistent/directory", + inputPkg: "github.com/go-openapi/testify/v2/internal/assertions", + outputPkgs: "assert", + targetRoot: dir, + }, + }, + }) +} diff --git a/doc.go b/doc.go index e80e38bcc..d2b551055 100644 --- a/doc.go +++ b/doc.go @@ -1,16 +1,47 @@ // SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers // SPDX-License-Identifier: Apache-2.0 -// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend. +// Package testify provides comprehensive assertion packages for Go testing. // -// Testify contains the following packages: +// # Overview // -// 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. +// This is the go-openapi fork of testify, designed with zero external dependencies +// and a focus on maintainability. The codebase uses code generation more extensively +// than the original testify. This helps maintain consistency across all assertion variants. // -// A [golangci-lint] compatible linter for testify is available called [testifylint]. +// # Packages // -// [the Go testing system]: https://go.dev/doc/code#Testing -// [golangci-lint]: https://golangci-lint.run/ +// The [assert] package provides a comprehensive set of assertion functions that +// integrate with Go's testing framework. Assertions return boolean values allowing +// tests to continue after failures. +// +// The [require] package provides the same assertions but with fatal checks that stop +// test execution immediately on failure via [testing.T.FailNow]. +// +// # Key Differences from stretchr/testify +// +// This fork prioritizes: +// - Zero external dependencies (go-spew and difflib are internalized) +// - Removed mock and suite packages (favor the use mockery or similar specialized tools instead) +// - Optional features via enable packages (e.g., enable/yaml for YAML assertions) +// - Code generation ensures consistency across 76 assertion functions × 8 variants +// +// # Optional Features +// +// YAML assertions require importing the enable package: +// +// import _ "github.com/go-openapi/testify/v2/enable/yaml" +// +// Without this import, YAMLEq and YAMLEqf will panic loudly with a helpful error message. +// +// # Note on testifylint +// +// The golangci-lint compatible linter [testifylint] is designed for stretchr/testify +// and will not work with this fork as it checks only for the original dependency. +// +// [assert]: https://pkg.go.dev/github.com/go-openapi/testify/v2/assert +// [require]: https://pkg.go.dev/github.com/go-openapi/testify/v2/require // [testifylint]: https://github.com/Antonboom/testifylint package testify + +//go:generate go run ./codegen/main.go -target-root . -work-dir . diff --git a/docs/EXAMPLES_STATUS.md b/docs/EXAMPLES_STATUS.md new file mode 100644 index 000000000..dc2f6f659 --- /dev/null +++ b/docs/EXAMPLES_STATUS.md @@ -0,0 +1,148 @@ +# Test Examples Status + +This document tracks which assertion functions have test examples added. + +## ✅ Completed (with values) + +### boolean.go +- [x] True - `success: 1 == 1`, `failure: 1 == 0` +- [x] False - `success: 1 == 0`, `failure: 1 == 1` + +### collection.go +- [x] Len - `success: []string{"A","B"}, 2`, `failure: []string{"A","B"}, 1` +- [x] Contains - `success: []string{"A","B"}, "A"`, `failure: []string{"A","B"}, "C"` +- [x] NotContains - `success: []string{"A","B"}, "C"`, `failure: []string{"A","B"}, "B"` + +### equal.go +- [x] Equal - `success: 123, 123`, `failure: 123, 456` +- [x] EqualValues - `success: uint32(123), int32(123)`, `failure: uint32(123), int32(456)` + +### error.go +- [x] NoError - `success: nil`, `failure: ErrTest` +- [x] Error - `success: ErrTest`, `failure: nil` +- [x] EqualError - `success: ErrTest, "assert.ErrTest general error for testing"`, `failure: ErrTest, "wrong error message"` +- [x] ErrorContains - `success: ErrTest, "general error"`, `failure: ErrTest, "not in message"` + +### yaml.go +- [x] YAMLEq - `panic:` (with message about yaml feature) + +## 📝 Completed (with TODO placeholders) + +### equal.go +- [x] Same - TODO: add pointer test values +- [x] NotSame - TODO: add different pointer test values +- [x] EqualExportedValues - TODO: add struct test values + +## ⏳ Remaining Functions (need examples) + +### equal.go +- [ ] NotEqual +- [ ] NotEqualValues +- [ ] Exactly + +### collection.go +- [ ] Empty +- [ ] NotEmpty +- [ ] Subset +- [ ] NotSubset +- [ ] ElementsMatch +- [ ] NotElementsMatch + +### compare.go +- [ ] Greater +- [ ] GreaterOrEqual +- [ ] Less +- [ ] LessOrEqual +- [ ] Positive +- [ ] Negative + +### error.go +- [ ] ErrorIs +- [ ] ErrorAs +- [ ] NotErrorIs + +### object.go +- [ ] Nil +- [ ] NotNil +- [ ] IsType +- [ ] NotNil +- [ ] Zero +- [ ] NotZero + +### panic.go +- [ ] Panics +- [ ] PanicsWithValue +- [ ] PanicsWithError +- [ ] NotPanics + +### string.go +- [ ] Regexp +- [ ] NotRegexp + +### number.go +- [ ] InDelta +- [ ] InDeltaSlice +- [ ] InDeltaMapValues +- [ ] InEpsilon +- [ ] InEpsilonSlice + +### condition.go +- [ ] Condition + +### http.go +- [ ] HTTPSuccess +- [ ] HTTPRedirect +- [ ] HTTPError +- [ ] HTTPStatusCode +- [ ] HTTPBodyContains +- [ ] HTTPBodyNotContains + +### json.go +- [ ] JSONEq + +### file.go +- [ ] FileExists +- [ ] NoFileExists +- [ ] DirExists +- [ ] NoDirExists + +### time.go +- [ ] WithinDuration +- [ ] WithinRange + +### type.go +- [ ] Implements + +### testing.go +- [ ] Never +- [ ] Eventually +- [ ] EventuallyWithT + +### assertion.go +- [ ] Fail +- [ ] FailNow + +## Template for Adding Examples + +```go +// FunctionName does something. +// +// Usage: +// +// assert.FunctionName(t, args...) +// +// Examples: +// +// success: +// failure: +// panic: +// +func FunctionName(...) bool { +``` + +## Notes + +- Use actual Go values that can be directly inserted into test code +- For complex types, use TODO comments +- success/failure are required, panic is optional +- All values will be injected directly into generated test code diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md new file mode 100644 index 000000000..e17b822f1 --- /dev/null +++ b/docs/MAINTAINERS.md @@ -0,0 +1,315 @@ +# Maintainer's guide + +## Repo structure + +Monorepo with multiple go modules. + +## Repo configuration + +* default branch: master +* protected branches: master +* branch protection rules: + * require pull requests and approval + * required status checks: + - DCO (simple email sign-off) + - Lint + - tests completed +* auto-merge enabled (used for dependabot updates) + +## Continuous Integration + +### Code Quality checks + +* meta-linter: golangci-lint +* linter config: [`.golangci.yml`](../.golangci.yml) (see our [posture](./STYLE.md) on linters) + +* Code quality assessment: [CodeFactor](https://www.codefactor.io/dashboard) +* Code quality badges + * go report card: + * CodeFactor: + +> **NOTES** +> +> codefactor inherits roles from github. There is no need to create a dedicated account. +> +> The codefactor app is installed at the organization level (`github.com/go-openapi`). +> +> There is no special token to setup in github for CI usage. + +### Testing + +* Test reports + * Uploaded to codecov: +* Test coverage reports + * Uploaded to codecov: + +* Fuzz testing + * Fuzz tests are handled separately by CI and may reuse a cached version of the fuzzing corpus. + At this moment, cache may not be shared between feature branches or feature branch and master. + The minimized corpus produced on failure is uploaded as an artifact and should be added manually + to `testdata/fuzz/...`. + +Coverage threshold status is informative and not blocking. +This is because the thresholds are difficult to tune and codecov oftentimes reports false negatives +or may fail to upload coverage. + +All tests across `go-openapi` use our fork of `stretchr/testify` (this repo): `github.com/go-openapi/testify`. +This allows for minimal test dependencies. + +> **NOTES** +> +> codecov inherits roles from github. There is no need to create a dedicated account. +> However, there is only 1 maintainer allowed to be the admin of the organization on codecov +> with their free plan. +> +> The codecov app is installed at the organization level (`github.com/go-openapi`). +> +> There is no special token to setup in github for CI usage. +> A organization-level token used to upload coverage and test reports is managed at codecov: +> no setup is required on github. + +### Automated updates + +* dependabot + * configuration: [`dependabot.yaml`](../.github/dependabot.yaml) + + Principle: + + * codecov applies updates and security patches to the github-actions and golang ecosystems. + * all updates from "trusted" dependencies (github actions, golang.org packages, go-openapi packages + are auto-merged if they successfully pass CI. + +* go version udpates + + Principle: + + * we support the 2 latest minor versions of the go compiler (`stable`, `oldstable`) + * `go.mod` should be updated (manually) whenever there is a new go minor release + (e.g. every 6 months). + +* contributors + * a [`CONTRIBUTORS.md`](../CONTRIBUTORS.md) file is updated weekly, with all-time contributors to the repository + * the `github-actions[bot]` posts a pull request to do that automatically + * at this moment, this pull request is not auto-approved/auto-merged (bot cannot approve its own PRs) + +### Vulnerability scanners + +There are 3 complementary scanners - obviously, there is some overlap, but each has a different focus. + +* github `CodeQL` +* `trivy` +* `govulnscan` + +None of these tools require an additional account or token. + +Github CodeQL configuration is set to "Advanced", so we may collect a CI status for this check (e.g. for badges). + +Scanners run on every commit to master and at least once a week. + +Reports are centralized in github security reports for code scanning tools. + +## Releases + +The release process is minimalist: + +* push a semver tag (i.e v{major}.{minor}.{patch}) to the master branch. +* the CI handles this to generate a github release with release notes + +* release notes generator: git-cliff +* configuration: [`cliff.toml`](../.cliff.toml) + +Tags are preferably PGP-signed. + +The tag message introduces the release notes (e.g. a summary of this release). + +The release notes generator does not assume that commits are necessarily "conventional commits". + +## Other files + +Standard documentation: + +* [`CONTRIBUTING.md`](../.github/CONTRIBUTING.md) guidelines +* [`DCO.md`](../.github/DCO.md) terms for first-time contributors to read +* [`CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md) +* [`SECURIY.md`](../SECURITY.md) policy: how to report vulnerabilities privately +* [`LICENSE`](../LICENSE) terms +* [`NOTICE`](../NOTICE) on supplementary license terms (original authors, copied code etc) + +Reference documentation (released): + +* [godoc](https://pkg.go/dev/go-openapi/testify) + +## Maintaining Generated Code + +This repository uses code generation extensively to maintain consistency across assertion packages. + +### Architecture Overview + +**Source of Truth: `internal/assertions/`** + +All assertion implementations live in `internal/assertions/`, organized by domain: +- Functions are implemented once with comprehensive tests +- Doc comments include "Examples:" sections that drive test generation +- Both `assert/` and `require/` packages are 100% generated from this source + +**Code Generator: `codegen/`** + +The generator scans `internal/assertions/` and produces: +- 76 assertion functions × 8 variants = 608 generated functions +- Package-level functions (`assert.Equal`, `require.Equal`) +- Format variants (`assert.Equalf`, `require.Equalf`) +- Forward methods (`a.Equal()`, `r.Equal()`) +- Tests for all variants +- Testable examples for godoc + +**Generated Packages: `assert/` and `require/`** + +Everything in these packages is generated. Never edit generated files directly. + +Exceptions: +* `doc.go` is not generated +* the `assert` package contains a small `enable` package to enable features. This is not generated. + +### Adding a New Assertion + +**Complete workflow:** + +1. **Add function to `internal/assertions/.go`:** + + The following example would like go to `string.go`, next to the `Regexp` assertion. + + ```go + // StartsWith asserts that the string starts with the given prefix. + // + // Examples: + // + // success: "hello world", "hello" + // failure: "hello world", "bye" + func StartsWith(t T, str, prefix string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + if !strings.HasPrefix(str, prefix) { + return Fail(t, fmt.Sprintf("Expected %q to start with %q", str, prefix), msgAndArgs...) + } + return true + } + ``` + +2. **Add tests to `internal/assertions/_test.go`:** + Write comprehensive table-driven tests covering edge cases. + +3. **Run code generation:** + ```bash + go generate ./... + ``` + +4. **Done!** All 8 variants are generated with tests and examples: + - `assert.StartsWith(t, str, prefix)` + - `assert.StartsWithf(t, str, prefix, "msg")` + - `a.StartsWith(str, prefix)` (forward method) + - `a.StartsWithf(str, prefix, "msg")` + - `require.StartsWith(t, str, prefix)` + - `require.StartsWithf(t, str, prefix, "msg")` + - `r.StartsWith(str, prefix)` (forward method) + - `r.StartsWithf(str, prefix, "msg")` + +### Example Annotations Format + +The "Examples:" section in doc comments drives test and example generation: + +```go +// Examples: +// +// success: +// failure: +// panic: +// +``` + +**Rules:** +- Use valid Go expressions that can be directly inserted into test code +- `success:` and `failure:` are required for most assertions +- `panic:` is optional (used for assertions like Panics, YAMLEq) +- Multiple examples of the same type are allowed (e.g., multiple `success:` lines) +- Examples are extracted by the scanner and used to generate: + - Unit tests (success + failure cases) + - Testable examples (success cases only for simplicity) + +**Example with multiple success cases:** +```go +// Examples: +// +// success: []string{"a", "b"}, 2 // slice +// success: map[string]int{"a": 1}, 1 // map +// success: "hello", 5 // string +// failure: []string{"a"}, 5 +``` + +### Special Cases in Generated Tests + +For complex assertions requiring special setup, the test templates support conditional logic. See `codegen/internal/generator/templates/assertion_assertions_test.gotmpl` for examples of: +- Custom mock selection based on function behavior (mockT vs mockFailNowT) +- Package-specific test helpers (testDataPath, httpOK, etc.) +- Handling functions without test examples (generates `t.Skip()`) + +Some go expressions won't fit nicely for examples (examples use an external package, e.g. `assert_test`). +To cover these edge cases, a `relocate` function map currently rewrites the example values to be used +from an external package. Most transforms there are hard-coded specifically for the 3 edges cases identified so far +(see `codegen/internal/generator/funcmap.go`). + +### Generator Flags + +```bash +go run ./codegen/main.go \ + -work-dir=.. \ + -input-package=github.com/go-openapi/testify/v2/internal/assertions \ + -output-packages=assert,require \ + -target-root=.. \ + -include-format-funcs=true \ + -include-forward-funcs=true \ + -include-tests=true \ + -include-examples=true \ + -runnable-examples=true \ + -include-helpers=true \ + -include-generics=false +``` + +Current usage with `go generate` (see `doc.go`): + +```go +//go:generate go run ./codegen/main.go -target-root . -work-dir . +``` + +**Note:** Generic functions are planned but not yet implemented. + +### Verification + +After generation, verify: +```bash +# All tests pass +go test ./... + +# Coverage remains high +go test -cover ./internal/assertions # Should be ~94% +go test -cover ./assert # Should be ~99.5% +go test -cover ./require # Should be ~99.5% + +# Examples are valid +go test -run Example ./assert +go test -run Example ./require +``` + +The 0.5% coverage gap comes from helper functions (non-assertion functions) that don't have "Examples:" annotations. + +## TODOs & other ideas + +A few things remain ahead to ease a bit a maintainer's job: + +* [ ] reuse CI workflows (e.g. in `github.com/go-openapi/workflows`) +* [ ] reusable actions with custom tools pinned (e.g. in `github.com/go-openapi/gh-actions`) +* open-source license checks +* [ ] auto-merge for CONTRIBUTORS.md (requires a github app to produce tokens) +* [x] more automated code renovation / relinting work (possibly built with CLAUDE) +* organization-level documentation web site +* ... diff --git a/original.md b/docs/ORIGINAL.md similarity index 100% rename from original.md rename to docs/ORIGINAL.md diff --git a/docs/STYLE.md b/docs/STYLE.md new file mode 100644 index 000000000..056fdb512 --- /dev/null +++ b/docs/STYLE.md @@ -0,0 +1,83 @@ +# Coding style at `go-openapi` + +> **TL;DR** +> +> Let's be honest: at `go-openapi` and `go-swagger` we've never been super-strict on code style etc. +> +> But perhaps now (2025) is the time to adopt a different stance. + +Even though our repos have been early adopters of `golangci-lint` years ago +(we used some other metalinter before), our decade-old codebase is only realigned to new rules from time to time. + +Now go-openapi and go-swagger make up a really large codebase, which is taxing to maintain and keep afloat. + +Code quality and the harmonization of rules have thus become things that we need now. + +## Meta-linter + +Universally formatted go code promotes ease of writing, reading, and maintenance. + +You should run `golangci-lint run` before committing your changes. + +Many editors have plugins that do that automatically. + +> We use the `golangci-lint` meta-linter. The configuration lies in [`.golangci.yml`](../.golangci.yml). +> You may read for additional reference. + +## Linting rules posture + +Thanks to go's original design, we developers don't have to waste much time arguing about code figures of style. + +However, the number of available linters has been growing to the point that we need to pick a choice. + +We enable all linters published by `golangci-lint` by default, then disable a few ones. + +Here are the reasons why they are disabled (update: Nov. 2025, `golangci-lint v2.6.1`): + +```yaml + disable: + - depguard # we don't want to configure rules to constrain import. That's the reviewer's job + - exhaustruct # we don't want to configure regexp's to check type name. That's the reviewer's job + - funlen # we accept cognitive complexity as a meaningful metric, but function length is relevant + - godox # we don't see any value in forbidding TODO's etc in code + - nlreturn # we usually apply this "blank line" rule to make code less compact. We just don't want to enforce it + - nonamedreturns # we don't see any valid reason why we couldn't used named returns + - noinlineerr # there is no value added forbidding inlined err + - paralleltest # we like parallel tests. We just don't want them to be enforced everywhere + - recvcheck # we like the idea of having pointer and non-pointer receivers + - testpackage # we like test packages. We just don't want them to be enforced everywhere + - tparallel # see paralleltest + - varnamelen # sometimes, we like short variables. The linter doesn't catch cases when a short name is good + - whitespace # no added value + - wrapcheck # although there is some sense with this linter's general idea, it produces too much noise + - wsl # no added value. Noise + - wsl_v5 # no added value. Noise +``` + +As you may see, we agree with the objective of most linters, at least the principle they are supposed to enforce. +But all linters do not support fine-grained tuning to tolerate some cases and not some others. + +When this is possible, we enable linters with relaxed constraints: + +```yaml + settings: + dupl: + threshold: 200 # in a older code base such as ours, we have to be tolerant with a little redundancy + # Hopefully, we'll be able to gradually get rid of those. + goconst: + min-len: 2 + min-occurrences: 3 + cyclop: + max-complexity: 20 # the default is too low for most of our functions. 20 is a nicer trade-off + gocyclo: + min-complexity: 20 + exhaustive: # when using default in switch, this should be good enough + default-signifies-exhaustive: true + default-case-required: true + lll: + line-length: 180 # we just want to avoid extremely long lines. + # It is no big deal if a line or two don't fit on your terminal. +``` + +Final note: since we have switched to a forked version of `stretchr/testify`, +we no longer benefit from the great `testifylint` linter for tests. diff --git a/enable/yaml/enable_yaml.go b/enable/yaml/enable_yaml.go index 31a4e85d1..77e790dc3 100644 --- a/enable/yaml/enable_yaml.go +++ b/enable/yaml/enable_yaml.go @@ -5,11 +5,11 @@ package yaml import ( - yamlstub "github.com/go-openapi/testify/v2/assert/yaml" + yamlstub "github.com/go-openapi/testify/v2/assert/enable/yaml" yaml "go.yaml.in/yaml/v3" ) func init() { //nolint:gochecknoinits // we precisely want this init to run when importing the package - yamlstub.EnableYAMLUnmarshal = yaml.Unmarshal + yamlstub.EnableYAMLWithUnmarshal(yaml.Unmarshal) } diff --git a/enable/yaml/go.mod b/enable/yaml/go.mod index f1e0421aa..45a1256d7 100644 --- a/enable/yaml/go.mod +++ b/enable/yaml/go.mod @@ -1,7 +1,7 @@ module github.com/go-openapi/testify/enable/yaml/v2 require ( - github.com/go-openapi/testify/v2 v2.0.2 + github.com/go-openapi/testify/v2 v2.0.0-00010101000000-000000000000 go.yaml.in/yaml/v3 v3.0.4 ) diff --git a/go.work b/go.work index c89de2fe7..0d65e3bac 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,6 @@ use ( . - ./_codegen + ./codegen ./enable/yaml ) diff --git a/go.work.sum b/go.work.sum index ce365bca7..0a6a65381 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1 +1,5 @@ github.com/go-openapi/testify/v2 v2.0.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= diff --git a/internal/assertions/assertion.go b/internal/assertions/assertion.go new file mode 100644 index 000000000..a3d965013 --- /dev/null +++ b/internal/assertions/assertion.go @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +// Assertions provides assertion methods around the [T] interface. +type Assertions struct { + t T +} + +// New makes a new [Assertions] object for the specified [T]. +func New(t T) *Assertions { + return &Assertions{ + t: t, + } +} diff --git a/internal/assertions/assertion_test.go b/internal/assertions/assertion_test.go new file mode 100644 index 000000000..67ca0e782 --- /dev/null +++ b/internal/assertions/assertion_test.go @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +func TestAssertionNew(t *testing.T) { + t.Parallel() + mock := new(mockT) + + a := New(mock) + if a == nil { + FailNow(t, "New should never return nil") + + return + } + if a.t == nil { + FailNow(t, "assertion should contain a T") + } +} diff --git a/internal/assertions/benchmarks_test.go b/internal/assertions/benchmarks_test.go new file mode 100644 index 000000000..3fc2d2304 --- /dev/null +++ b/internal/assertions/benchmarks_test.go @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +func Benchmark_isEmpty(b *testing.B) { + b.ReportAllocs() + + v := new(int) + + for b.Loop() { + isEmpty("") + isEmpty(42) + isEmpty(v) + } +} + +func BenchmarkNotNil(b *testing.B) { + for b.Loop() { + NotNil(b, b) + } +} + +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 := &mockFailNowT{} + + for b.Loop() { + Equal(mockT, s, s2) + } +} diff --git a/internal/assertions/boolean.go b/internal/assertions/boolean.go new file mode 100644 index 000000000..e990cde61 --- /dev/null +++ b/internal/assertions/boolean.go @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +// True asserts that the specified value is true. +// +// Usage: +// +// assertions.True(t, myBool) +// +// Examples: +// +// success: 1 == 1 +// failure: 1 == 0 +func True(t T, value bool, msgAndArgs ...any) bool { + if !value { + if h, ok := t.(H); ok { + h.Helper() + } + return Fail(t, "Should be true", msgAndArgs...) + } + + return true +} + +// False asserts that the specified value is false. +// +// Usage: +// +// assertions.False(t, myBool) +// +// Examples: +// +// success: 1 == 0 +// failure: 1 == 1 +func False(t T, value bool, msgAndArgs ...any) bool { + if value { + if h, ok := t.(H); ok { + h.Helper() + } + return Fail(t, "Should be false", msgAndArgs...) + } + + return true +} diff --git a/internal/assertions/boolean_test.go b/internal/assertions/boolean_test.go new file mode 100644 index 000000000..feb84d705 --- /dev/null +++ b/internal/assertions/boolean_test.go @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +func TestBooleanTrue(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + + if !True(mock, true) { + t.Error("True should return true") + } + + if True(mock, false) { + t.Error("True should return false") + } + + if !True(mock, true) { + t.Error("check error") + } +} + +func TestBooleanFalse(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + + if !False(mock, false) { + t.Error("False should return true") + } + if False(mock, true) { + t.Error("False should return false") + } +} diff --git a/internal/assertions/collection.go b/internal/assertions/collection.go new file mode 100644 index 000000000..bbbc00446 --- /dev/null +++ b/internal/assertions/collection.go @@ -0,0 +1,442 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bytes" + "fmt" + "reflect" + "strings" +) + +// Len asserts that the specified object has specific length. +// +// Len also fails if the object has a type that len() does not accept. +// +// The asserted object can be a string, a slice, a map, an array or a channel. +// +// See also [reflect.Len]. +// +// Usage: +// +// assertions.Len(t, mySlice, 3) +// assertions.Len(t, myString, 4) +// assertions.Len(t, myMap, 5) +// +// Examples: +// +// success: []string{"A","B"}, 2 +// failure: []string{"A","B"}, 1 +func Len(t T, object any, length int, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// Usage: +// +// assertions.Contains(t, "Hello World", "World") +// assertions.Contains(t, ["Hello", "World"], "World") +// assertions.Contains(t, {"Hello": "World"}, "Hello") +// +// Examples: +// +// success: []string{"A","B"}, "A" +// failure: []string{"A","B"}, "C" +func Contains(t T, s, contains any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + + ok, found := containsElement(s, contains) + if !ok { + return Fail(t, truncatingFormat("%#v", s)+" could not be applied builtin len()", 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. +// +// Usage: +// +// assertions.NotContains(t, "Hello World", "Earth") +// assertions.NotContains(t, ["Hello", "World"], "Earth") +// assertions.NotContains(t, {"Hello": "World"}, "Earth") +// +// Examples: +// +// success: []string{"A","B"}, "C" +// failure: []string{"A","B"}, "B" +func NotContains(t T, s, contains any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + + ok, found := containsElement(s, contains) + if !ok { + return Fail(t, truncatingFormat("%#v", s)+" could not be applied builtin len()", 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2} +// failure: []int{1, 2, 3}, []int{4, 5} +func Subset(t T, list, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); 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([]any, subsetList.Len()) + for idx, key := range subsetList.MapKeys() { + keys[idx] = key.Interface() + } + subsetList = reflect.ValueOf(keys) + } + + for i := range subsetList.Len() { + 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{4, 5} +// failure: []int{1, 2, 3}, []int{1, 2} +func NotSubset(t T, list, subset any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); 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([]any, subsetList.Len()) + for idx, key := range subsetList.MapKeys() { + keys[idx] = key.Interface() + } + subsetList = reflect.ValueOf(keys) + } + for i := range subsetList.Len() { + 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]). +// +// Examples: +// +// success: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +// failure: []int{1, 2, 3}, []int{1, 2, 4} +func ElementsMatch(t T, listA, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); 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...) +} + +// containsElement tries to 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 any, element any) (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 := range mapKeys { + if ObjectsAreEqual(mapKeys[i].Interface(), element) { + return true, true + } + } + return true, false + } + + for i := range listValue.Len() { + if ObjectsAreEqual(listValue.Index(i).Interface(), element) { + return true, true + } + } + return true, false +} + +// isList checks that the provided value is array or slice. +func isList(t T, list any, msgAndArgs ...any) (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 any) (extraA, extraB []any) { + 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 := range aLen { + element := aValue.Index(i).Interface() + found := false + for j := range bLen { + 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 := range bLen { + if visited[j] { + continue + } + extraB = append(extraB, bValue.Index(j).Interface()) + } + + return extraA, extraB +} + +func formatListDiff(listA, listB any, extraA, extraB []any) 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. +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2, 4} +// failure: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +func NotElementsMatch(t T, listA, listB any, msgAndArgs ...any) (ok bool) { + if h, ok := t.(H); 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 +} + +// getLen tries to get the length of an object. +// It returns (0, false) if impossible. +func getLen(x any) (length int, ok bool) { + v := reflect.ValueOf(x) + defer func() { + ok = recover() == nil + }() + return v.Len(), true +} diff --git a/internal/assertions/collection_impl_test.go b/internal/assertions/collection_impl_test.go new file mode 100644 index 000000000..d594d6029 --- /dev/null +++ b/internal/assertions/collection_impl_test.go @@ -0,0 +1,130 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "iter" + "slices" + "testing" +) + +func TestCollectionUnexportedImplementationDetails(t *testing.T) { + t.Parallel() + + t.Run("containsElement", testContainsElement()) + t.Run("getLen", testGetLen()) +} + +func testContainsElement() func(*testing.T) { + return func(t *testing.T) { + t.Parallel() + + list1 := []string{"Foo", "Bar"} + list2 := []int{1, 2} + simpleMap := map[any]any{"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 testGetLen() func(*testing.T) { + return func(t *testing.T) { + t.Parallel() + + for v := range collectionImplGetLenFalseCases() { + 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) + } + + for c := range collectionImplGetLenTrueCases() { + l, ok := getLen(c.v) + True(t, ok, "Expected getLen success to get length of %#v", c.v) + Equal(t, c.l, l) + } + } +} + +type collectionImplGetLenCase = any + +func collectionImplGetLenFalseCases() iter.Seq[collectionImplGetLenCase] { + return slices.Values([]collectionImplGetLenCase{ + nil, + 0, + true, + false, + 'A', + struct{}{}, + }) +} + +type collectionImplGetLenTrueCase struct { + v any + l int +} + +func collectionImplGetLenTrueCases() iter.Seq[collectionImplGetLenTrueCase] { + ch := make(chan int, 5) + ch <- 1 + ch <- 2 + ch <- 3 + + return slices.Values([]collectionImplGetLenTrueCase{ + {[]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}, + }) +} diff --git a/internal/assertions/collection_test.go b/internal/assertions/collection_test.go new file mode 100644 index 000000000..968cd0147 --- /dev/null +++ b/internal/assertions/collection_test.go @@ -0,0 +1,555 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "iter" + "path/filepath" + "reflect" + "runtime" + "slices" + "strings" + "testing" +) + +func TestCollectionLen(t *testing.T) { + t.Parallel() + + t.Run("with invalid types", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + False(t, Len(mock, nil, 0), "nil does not have length") + False(t, Len(mock, 0, 0), "int does not have length") + False(t, Len(mock, true, 0), "true does not have length") + False(t, Len(mock, false, 0), "false does not have length") + False(t, Len(mock, 'A', 0), "Rune does not have length") + False(t, Len(mock, struct{}{}, 0), "Struct does not have length") + }) + + t.Run("with valid types", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for c := range collectionValidLenCases() { + True(t, Len(mock, c.v, c.l), "%#v have %d items", c.v, c.l) + False(t, Len(mock, c.v, c.l+1), "%#v have %d items", c.v, c.l) + + if c.expected1234567 != "" { + msgMock := new(mockT) + Len(msgMock, c.v, 1234567) + Contains(t, msgMock.errorString(), c.expected1234567) + } + } + }) + + t.Run("with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Len(mock, longSlice, 1) + Contains(t, mock.errorString(), ` + Error Trace: + Error: "[0 0 0`) + Contains(t, mock.errorString(), `<... truncated>" should have 1 item(s), but has 1000000`) + }) +} + +func TestCollectionContains(t *testing.T) { + t.Parallel() + + t.Run("nil with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Nil(mock, &longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Expected nil, but got: &[]int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated>`) + }) + + t.Run("empty with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Empty(mock, longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Should be empty, but was [0 0 0`) + Contains(t, mock.errorString(), `<... truncated>`) + }) + + t.Run("with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Contains(mock, longSlice, 1) + Contains(t, mock.errorString(), ` + Error Trace: + Error: []int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated> does not contain 1`) + }) +} + +func TestCollectionNotContains(t *testing.T) { + t.Parallel() + + t.Run("with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotContains(mock, longSlice, 0) + Contains(t, mock.errorString(), ` + Error Trace: + Error: []int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated> should not contain 0`) + }) +} + +func TestCollectionSubset(t *testing.T) { + t.Parallel() + + t.Run("with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Subset(mock, longSlice, []int{1}) + Contains(t, mock.errorString(), ` + Error Trace: + Error: []int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated> does not contain 1`) + }) + + t.Run("with map too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Subset(mock, map[bool][]int{true: longSlice}, map[bool][]int{false: longSlice}) + Contains(t, mock.errorString(), ` + Error Trace: + Error: map[bool][]int{true:[]int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated> does not contain map[bool][]int{false:[]int{0, 0, 0,`) + }) +} + +func TestCollectionNotSubset(t *testing.T) { + t.Parallel() + + t.Run("with slice too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotSubset(mock, longSlice, longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: ['\x00' '\x00' '\x00'`) + Contains(t, mock.errorString(), `<... truncated> is a subset of ['\x00' '\x00' '\x00'`) + }) + + t.Run("with map too long to print", func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotSubset(mock, map[int][]int{1: longSlice}, map[int][]int{1: longSlice}) + Contains(t, mock.errorString(), ` + Error Trace: + Error: map['\x01':['\x00' '\x00' '\x00'`) + Contains(t, mock.errorString(), `<... truncated> is a subset of map['\x01':['\x00' '\x00' '\x00'`) + }) +} + +func TestCollectionContainsNotContains(t *testing.T) { + t.Parallel() + + for c := range collectionContainsCases() { + t.Run(fmt.Sprintf("Contains(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := Contains(mock, 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 collectionContainsCases() { + t.Run(fmt.Sprintf("NotContains(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := NotContains(mock, c.expected, c.actual) + + // NotContains should be inverse of Contains. If it's not, something is wrong + if res == Contains(mock, 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 TestCollectionContainsNotContainsFailMessage(t *testing.T) { + t.Parallel() + + for c := range collectionContainsFailCases() { + 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) { + t.Parallel() + mock := new(mockT) + + c.assertion(mock, c.container, c.instance) + actualFail := mock.errorString() + if !strings.Contains(actualFail, c.expected) { + t.Errorf("Contains failure should include %q but was %q", c.expected, actualFail) + } + }) + } +} + +func TestCollectionContainsNotContainsOnNilValue(t *testing.T) { + t.Parallel() + mock := new(mockT) + + Contains(mock, nil, "key") + expectedFail := " could not be applied builtin len()" + actualFail := mock.errorString() + if !strings.Contains(actualFail, expectedFail) { + t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail) + } + + NotContains(mock, nil, "key") + if !strings.Contains(actualFail, expectedFail) { + t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail) + } +} + +func TestCollectionSubsetNotSubset(t *testing.T) { + t.Parallel() + + for c := range collectionSubsetCases() { + t.Run("SubSet: "+c.message, func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + res := Subset(mock, 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 := mock.errorString() + if !strings.Contains(actualFail, expectedFail) { + t.Log(actualFail) + t.Errorf("Subset failure should contain %q but was %q", expectedFail, actualFail) + } + } + }) + } + + for c := range collectionSubsetCases() { + t.Run("NotSubSet: "+c.message, func(t *testing.T) { + t.Parallel() + mock := new(mockT) + + res := NotSubset(mock, c.list, c.subset) + + // NotSubset should match the inverse of Subset. If it doesn't, something is wrong + if res == Subset(mock, c.list, c.subset) { + t.Errorf("NotSubset should return %t: %s", !c.result, c.message) + } + + if c.result { + expectedFail := c.message + actualFail := mock.errorString() + if !strings.Contains(actualFail, expectedFail) { + t.Log(actualFail) + t.Errorf("NotSubset failure should contain %q but was %q", expectedFail, actualFail) + } + } + }) + } +} + +func TestCollectionNotSubsetNil(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + NotSubset(mock, []string{"foo"}, nil) + if !mock.Failed() { + t.Error("NotSubset on nil set should have failed the test") + } +} + +func TestCollectionElementsMatch(t *testing.T) { + t.Parallel() + + for c := range collectionElementsMatchCases() { + t.Run(fmt.Sprintf("ElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := ElementsMatch(mock, c.actual, c.expected) + + if res != c.result { + t.Errorf("ElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result) + } + }) + } +} + +func TestCollectionNotElementsMatch(t *testing.T) { + t.Parallel() + + for c := range collectionNotElementsMatchCases() { + t.Run(fmt.Sprintf("NotElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := NotElementsMatch(mock, c.actual, c.expected) + + if res != c.result { + t.Errorf("NotElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result) + } + }) + } +} + +/* iterators for test cases */ + +type collectionValidLenCase struct { + v any + l int + expected1234567 string // message when expecting 1234567 items +} + +func collectionValidLenCases() iter.Seq[collectionValidLenCase] { + ch := make(chan int, 5) + ch <- 1 + ch <- 2 + ch <- 3 + + return slices.Values([]collectionValidLenCase{ + {[]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`}, + }) +} + +type collectionContainsCase = testCase + +func collectionContainsCases() iter.Seq[collectionContainsCase] { + type A struct { + Name, Value string + } + + list := []string{"Foo", "Bar"} + complexList := []*A{ + {"b", "c"}, + {"d", "e"}, + {"g", "h"}, + {"j", "k"}, + } + simpleMap := map[any]any{"Foo": "Bar"} + var zeroMap map[any]any + + return slices.Values([]collectionContainsCase{ + {"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}, + }) +} + +type collectionContainsFailCase struct { + assertion func(t T, s, contains any, msgAndArgs ...any) bool + container any + instance any + expected string +} + +func collectionContainsFailCases() iter.Seq[collectionContainsFailCase] { + const pkg = "assertions" + type nonContainer struct { + Value string + } + + return slices.Values([]collectionContainsFailCase{ + { + 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: pkg + ".nonContainer{Value:\"Hello\"} could not be applied builtin len()\n", + }, + { + assertion: NotContains, + container: nonContainer{Value: "Hello"}, + instance: "Hello", + expected: pkg + ".nonContainer{Value:\"Hello\"} could not be applied builtin len()\n", + }, + }) +} + +type collectionSubsetCase struct { + list any + subset any + result bool + message string +} + +func collectionSubsetCases() iter.Seq[collectionSubsetCase] { + return slices.Values([]collectionSubsetCase{ + // 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"`}, + }) +} + +type collectionElementsMatchCase = testCase + +func collectionElementsMatchCases() iter.Seq[collectionElementsMatchCase] { + return slices.Values([]collectionElementsMatchCase{ + // 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}, + }) +} + +type collectionNotElementsMatch = testCase + +func collectionNotElementsMatchCases() iter.Seq[collectionNotElementsMatch] { + return slices.Values([]collectionNotElementsMatch{ + // 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}, + }) +} diff --git a/assert/assertion_compare.go b/internal/assertions/compare.go similarity index 76% rename from assert/assertion_compare.go rename to internal/assertions/compare.go index 7cf84962a..13d324ecb 100644 --- a/assert/assertion_compare.go +++ b/internal/assertions/compare.go @@ -1,4 +1,7 @@ -package assert +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions import ( "bytes" @@ -9,6 +12,25 @@ import ( "time" ) +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(T, any, any, ...any) bool + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(T, any, ...any) bool + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(T, bool, ...any) bool + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(T, error, ...any) bool + +// Comparison is a custom function that returns true on success and false on failure. +type Comparison func() (success bool) + // 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 @@ -165,66 +187,93 @@ func convertReflectValue[T any](obj any, value reflect.Value) T { //nolint:iretu return converted } -// Greater asserts that the first element is greater than the second +// Greater asserts that the first element is strictly greater than the second. +// +// Usage: +// +// assertions.Greater(t, 2, 1) +// assertions.Greater(t, float64(2), float64(1)) +// assertions.Greater(t, "b", "a") // -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") -func Greater(t TestingT, e1 any, e2 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +func Greater(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// 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 any, e2 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +func GreaterOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// Less asserts that the first element is strictly 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 any, e2 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +func Less(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// 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 any, e2 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +func LessOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// Positive asserts that the specified element is strictly positive. // // assert.Positive(t, 1) // assert.Positive(t, 1.23) -func Positive(t TestingT, e any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: 1 +// failure: -1 +func Positive(t T, e any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } zero := reflect.Zero(reflect.TypeOf(e)) @@ -232,12 +281,17 @@ func Positive(t TestingT, e any, msgAndArgs ...any) bool { return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...) } -// Negative asserts that the specified element is negative +// Negative asserts that the specified element is strictly negative. // // assert.Negative(t, -1) // assert.Negative(t, -1.23) -func Negative(t TestingT, e any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: -1 +// failure: 1 +func Negative(t T, e any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } zero := reflect.Zero(reflect.TypeOf(e)) @@ -245,8 +299,8 @@ func Negative(t TestingT, e any, msgAndArgs ...any) bool { return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...) } -func compareTwoValues(t TestingT, e1 any, e2 any, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +func compareTwoValues(t T, e1 any, e2 any, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } diff --git a/internal/assertions/compare_impl_test.go b/internal/assertions/compare_impl_test.go new file mode 100644 index 000000000..453a4bcee --- /dev/null +++ b/internal/assertions/compare_impl_test.go @@ -0,0 +1,229 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "iter" + "reflect" + "slices" + "testing" + "time" +) + +func TestCompareUnexportedImplementationDetails(t *testing.T) { + t.Parallel() + + t.Run("compare", testCompare()) + t.Run("containsValue", testContainsValue()) + t.Run("compareTwoValues - different types", testCompareTwoValuesDifferentTypes()) + t.Run("compareTwoValues - not comparable", testCompareTwoValuesNotComparable()) + t.Run("compareTwoValues - compare result", testCompareTwoValuesCorrectCompareResult()) +} + +func testCompare() func(*testing.T) { + return func(t *testing.T) { + for currCase := range compareImplCompareCases() { + t.Run("compare", func(t *testing.T) { + t.Parallel() + + 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 %s", currCase.cType) + } + + resEqual, isComparable := compare(currCase.less, currCase.less, reflect.ValueOf(currCase.less).Kind()) + if !isComparable { + t.Errorf("object are comparable for type %s", currCase.cType) + } + + if resEqual != 0 { + t.Errorf("objects should be equal for type %s", currCase.cType) + } + }) + } + } +} + +func testContainsValue() func(*testing.T) { + return func(t *testing.T) { + t.Parallel() + + for currCase := range compareContainsValueCases() { + result := containsValue(currCase.values, currCase.value) + Equal(t, currCase.result, result) + } + } +} + +func testCompareTwoValuesDifferentTypes() func(*testing.T) { + return func(t *testing.T) { + for currCase := range compareTwoValuesDifferentTypesCases() { + t.Run("different types should not be comparable", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + result := compareTwoValues(mock, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage") + False(t, result) + }) + } + } +} + +func testCompareTwoValuesNotComparable() func(*testing.T) { + return func(t *testing.T) { + for currCase := range compareTwoValuesNotComparableCases() { + t.Run("should not be comparable", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + result := compareTwoValues(mock, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage") + False(t, result) + }) + } + } +} + +func testCompareTwoValuesCorrectCompareResult() func(*testing.T) { + return func(t *testing.T) { + for currCase := range compareTwoValuesCorrectResultCases() { + t.Run("should be comparable", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + result := compareTwoValues(mock, currCase.v1, currCase.v2, currCase.allowedResults, "testFailMessage") + True(t, result) + }) + } + } +} + +type compareImplCompareCase struct { + less any + greater any + cType string +} + +func compareImplCompareCases() iter.Seq[compareImplCompareCase] { + 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 + + return slices.Values([]compareImplCompareCase{ + {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"}, + { + // using time.Local is ok in this context: this is precisely the goal of this test + less: time.Date(2024, 0, 0, 0, 0, 0, 0, time.Local), //nolint:gosmopolitan // ok. See above + greater: time.Date(2263, 0, 0, 0, 0, 0, 0, time.Local), //nolint:gosmopolitan // ok. See above + 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"}, + }) +} + +type compareTwoValuesCase struct { + v1 any + v2 any + // compareResult bool + allowedResults []compareResult +} + +func compareTwoValuesDifferentTypesCases() iter.Seq[compareTwoValuesCase] { + return slices.Values([]compareTwoValuesCase{ + {v1: 123, v2: "abc"}, + {v1: "abc", v2: 123456}, + {v1: float64(12), v2: "123"}, + {v1: "float(12)", v2: float64(1)}, + }) +} + +func compareTwoValuesNotComparableCases() iter.Seq[compareTwoValuesCase] { + type CompareStruct struct{} + return slices.Values([]compareTwoValuesCase{ + {v1: CompareStruct{}, v2: CompareStruct{}}, + {v1: map[string]int{}, v2: map[string]int{}}, + {v1: make([]int, 5), v2: make([]int, 5)}, + }) +} + +func compareTwoValuesCorrectResultCases() iter.Seq[compareTwoValuesCase] { + return slices.Values([]compareTwoValuesCase{ + {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}}, + }) +} + +type compareContainsValueCase struct { + values []compareResult + value compareResult + result bool +} + +func compareContainsValueCases() iter.Seq[compareContainsValueCase] { + return slices.Values([]compareContainsValueCase{ + {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}, + }) +} diff --git a/internal/assertions/compare_test.go b/internal/assertions/compare_test.go new file mode 100644 index 000000000..f26bac831 --- /dev/null +++ b/internal/assertions/compare_test.go @@ -0,0 +1,312 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bytes" + "fmt" + "iter" + "runtime" + "slices" + "strings" + "testing" + "time" +) + +const pkg = "github.com/go-openapi/testify/v2/internal/assertions" + +func TestCompareGreater(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Greater(mock, 2, 1) { + t.Error("Greater should return true") + } + + if Greater(mock, 1, 1) { + t.Error("Greater should return false") + } + + if Greater(mock, 1, 2) { + t.Error("Greater should return false") + } + + // check error report + for currCase := range compareIncreasingFixtures() { + 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, pkg+".Greater") + } +} + +func TestCompareGreaterOrEqual(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !GreaterOrEqual(mock, 2, 1) { + t.Error("GreaterOrEqual should return true") + } + + if !GreaterOrEqual(mock, 1, 1) { + t.Error("GreaterOrEqual should return true") + } + + if GreaterOrEqual(mock, 1, 2) { + t.Error("GreaterOrEqual should return false") + } + + // check error report + for currCase := range compareIncreasingFixtures() { + out := &outputT{buf: bytes.NewBuffer(nil)} + False(t, GreaterOrEqual(out, currCase.less, currCase.greater)) + Contains(t, out.buf.String(), strings.ReplaceAll(currCase.msg, "than", "than or equal to")) + Contains(t, out.helpers, pkg+".GreaterOrEqual") + } +} + +func TestCompareLess(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Less(mock, 1, 2) { + t.Error("Less should return true") + } + + if Less(mock, 1, 1) { + t.Error("Less should return false") + } + + if Less(mock, 2, 1) { + t.Error("Less should return false") + } + + // check error report + for currCase := range compareIncreasingFixtures3() { + 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, pkg+".Less") + } +} + +func TestCompareLessOrEqual(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !LessOrEqual(mock, 1, 2) { + t.Error("LessOrEqual should return true") + } + + if !LessOrEqual(mock, 1, 1) { + t.Error("LessOrEqual should return true") + } + + if LessOrEqual(mock, 2, 1) { + t.Error("LessOrEqual should return false") + } + + // check error report + for currCase := range compareIncreasingFixtures3() { + out := &outputT{buf: bytes.NewBuffer(nil)} + False(t, LessOrEqual(out, currCase.greater, currCase.less)) + Contains(t, out.buf.String(), strings.ReplaceAll(currCase.msg, "than", "than or equal to")) + Contains(t, out.helpers, pkg+".LessOrEqual") + } +} + +func TestComparePositive(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Positive(mock, 1) { + t.Error("Positive should return true") + } + + if !Positive(mock, 1.23) { + t.Error("Positive should return true") + } + + if Positive(mock, -1) { + t.Error("Positive should return false") + } + + if Positive(mock, -1.23) { + t.Error("Positive should return false") + } + + // Check error report + for currCase := range comparePositiveCases() { + out := &outputT{buf: bytes.NewBuffer(nil)} + False(t, Positive(out, currCase.e)) + Contains(t, out.buf.String(), currCase.msg) + Contains(t, out.helpers, pkg+".Positive") + } +} + +func TestCompareNegative(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Negative(mock, -1) { + t.Error("Negative should return true") + } + + if !Negative(mock, -1.23) { + t.Error("Negative should return true") + } + + if Negative(mock, 1) { + t.Error("Negative should return false") + } + + if Negative(mock, 1.23) { + t.Error("Negative should return false") + } + + // Check error report + for currCase := range compareNegativeCases() { + out := &outputT{buf: bytes.NewBuffer(nil)} + False(t, Negative(out, currCase.e)) + Contains(t, out.buf.String(), currCase.msg) + Contains(t, out.helpers, pkg+".Negative") + } +} + +func TestCompareMsgAndArgsForwarding(t *testing.T) { + msgAndArgs := []any{"format %s %x", "this", 0xc001} + expectedOutput := "format this c001\n" + + funcs := []func(t T){ + func(t T) { Greater(t, 1, 2, msgAndArgs...) }, + func(t T) { GreaterOrEqual(t, 1, 2, msgAndArgs...) }, + func(t T) { Less(t, 2, 1, msgAndArgs...) }, + func(t T) { LessOrEqual(t, 2, 1, msgAndArgs...) }, + func(t T) { Positive(t, 0, msgAndArgs...) }, + func(t T) { Negative(t, 0, msgAndArgs...) }, + } + + for _, f := range funcs { + out := &outputT{buf: bytes.NewBuffer(nil)} + f(out) + Contains(t, out.buf.String(), expectedOutput) + } +} + +type outputT struct { + buf *bytes.Buffer + helpers map[string]struct{} +} + +// Implements T. +func (t *outputT) Errorf(format string, args ...any) { + 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 +} + +type compareFixture struct { + less any + greater any + msg string +} + +//nolint:dupl // factoring further the message to save a little duplication would make the test harder to read +func compareIncreasingFixtures() iter.Seq[compareFixture] { + return slices.Values( + []compareFixture{ + {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]"`}, + }, + ) +} + +//nolint:dupl // factoring further the message to save a little duplication would make the test harder to read +func compareIncreasingFixtures3() iter.Seq[compareFixture] { + return slices.Values( + []compareFixture{ + {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]"`}, + }, + ) +} + +type compareTestCase struct { + e any + msg string +} + +type comparePositiveCase = compareTestCase + +type compareNegativeCase = compareTestCase + +func comparePositiveCases() iter.Seq[comparePositiveCase] { + return slices.Values([]comparePositiveCase{ + {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`}, + }) +} + +func compareNegativeCases() iter.Seq[compareNegativeCase] { + return slices.Values([]compareNegativeCase{ + {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`}, + }) +} diff --git a/internal/assertions/condition.go b/internal/assertions/condition.go new file mode 100644 index 000000000..bce0b47b2 --- /dev/null +++ b/internal/assertions/condition.go @@ -0,0 +1,228 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "runtime" + "time" +) + +// Condition uses a Comparison to assert a complex condition. +// +// Examples: +// +// success: func() bool { return true } +// failure: func() bool { return false } +func Condition(t T, comp Comparison, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + result := comp() + if !result { + Fail(t, "Condition failed!", msgAndArgs...) + } + return result +} + +// 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) +// +// Examples: +// +// success: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +func Eventually(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 T 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 ...any) { + 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(T) { + 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") +// +// Examples: +// +// success: func(c *CollectT) { True(c,true) }, 100*time.Millisecond, 20*time.Millisecond +// failure: func(c *CollectT) { False(c,true) }, 100*time.Millisecond, 20*time.Millisecond +func EventuallyWithT(t T, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); 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) +// +// Examples: +// +// success: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +func Never(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 + } + } +} diff --git a/internal/assertions/condition_test.go b/internal/assertions/condition_test.go new file mode 100644 index 000000000..8c4982925 --- /dev/null +++ b/internal/assertions/condition_test.go @@ -0,0 +1,228 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "testing" + "time" +) + +func TestCondition(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Condition(mock, func() bool { return true }, "Truth") { + t.Error("Condition should return true") + } + + if Condition(mock, func() bool { return false }, "Lie") { + t.Error("Condition should return false") + } +} + +func TestConditionEventually(t *testing.T) { + t.Parallel() + + t.Run("condition should Eventually be false", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + condition := func() bool { + return false + } + + False(t, Eventually(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + }) + + t.Run("condition should Eventually be true", func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + state := 0 + condition := func() bool { + defer func() { + state++ + }() + return state == 2 + } + + True(t, Eventually(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + }) +} + +func TestConditionEventuallyWithTFalse(t *testing.T) { + t.Parallel() + mock := new(errorsCapturingT) + + condition := func(collect *CollectT) { + Fail(collect, "condition fixed failure") + } + + False(t, EventuallyWithT(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + Len(t, mock.errors, 2) +} + +func TestConditionEventuallyWithTTrue(t *testing.T) { + t.Parallel() + mock := new(errorsCapturingT) + + counter := 0 + condition := func(collect *CollectT) { + counter++ + True(collect, counter == 2) + } + + True(t, EventuallyWithT(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + Len(t, mock.errors, 0) + Equal(t, 2, counter, "Condition is expected to be called 2 times") +} + +func TestConditionEventuallyWithT_ConcurrencySafe(t *testing.T) { + t.Parallel() + mock := 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(mock, condition, 100*time.Millisecond, time.Nanosecond)) + Len(t, mock.errors, 2) +} + +func TestConditionEventuallyWithT_ReturnsTheLatestFinishedConditionErrors(t *testing.T) { + t.Parallel() + mock := new(errorsCapturingT) + + // 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") + } + + False(t, EventuallyWithT(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + Len(t, mock.errors, 2) +} + +func TestConditionEventuallyWithTFailNow(t *testing.T) { + t.Parallel() + mock := new(CollectT) + + condition := func(collect *CollectT) { + collect.FailNow() + } + + False(t, EventuallyWithT(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) + Len(t, mock.errors, 1) +} + +// Check that a long running condition doesn't block Eventually. +// See issue 805 (and its long tail of following issues). +func TestConditionEventuallyTimeout(t *testing.T) { + t.Parallel() + mock := 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(mock, condition, time.Millisecond, time.Microsecond)) + + close(done) + <-done2 + }) +} + +func TestConditionEventuallySucceedQuickly(t *testing.T) { + t.Parallel() + mock := 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(mock, condition, 100*time.Millisecond, time.Second)) +} + +func TestConditionEventuallyWithTSucceedQuickly(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + condition := func(*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(mock, condition, 100*time.Millisecond, time.Second)) +} + +func TestConditionNeverFalse(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 TestConditionNeverTrue(t *testing.T) { + t.Parallel() + mock := 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(mock, condition, 100*time.Millisecond, 20*time.Millisecond)) +} + +func TestConditionNeverFailQuickly(t *testing.T) { + t.Parallel() + mock := 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(mock, condition, 100*time.Millisecond, time.Second)) +} + +// 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 ...any) { + t.errors = append(t.errors, fmt.Errorf(format, args...)) +} diff --git a/internal/assertions/doc.go b/internal/assertions/doc.go new file mode 100644 index 000000000..c45a34574 --- /dev/null +++ b/internal/assertions/doc.go @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Package assertions holds the internal implementation +// of all the helper functions exposed by testify. +// +// It serves as a base to develop and test testify, +// whereas the publicly exposed API (in packages assert and require) +// is generated. +package assertions diff --git a/internal/assertions/embed_test.go b/internal/assertions/embed_test.go new file mode 100644 index 000000000..b928cf7de --- /dev/null +++ b/internal/assertions/embed_test.go @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +/* Enhancement proposal: move json literals to file fixtures in the embedded FS +import ( + "embed" +) + +//nolint:gochecknoglobals // it's okay to have embedded test fixtures a globals +var ( + //go:embed testdata/json/*.json + fixtureJSONAssets embed.FS +) +*/ diff --git a/internal/assertions/enable/doc.go b/internal/assertions/enable/doc.go new file mode 100644 index 000000000..30ff081d1 --- /dev/null +++ b/internal/assertions/enable/doc.go @@ -0,0 +1,3 @@ +// Package enable registers extra features +// and possibly additional dependencies. +package enable diff --git a/internal/assertions/enable/yaml/enable_yaml.go b/internal/assertions/enable/yaml/enable_yaml.go new file mode 100644 index 000000000..4b95a335c --- /dev/null +++ b/internal/assertions/enable/yaml/enable_yaml.go @@ -0,0 +1,34 @@ +// Package yaml is an indirection to handle YAML deserialization. +// +// This package allows the builder to override the indirection with an alternative implementation +// of YAML deserialization. +package yaml + +var enableYAMLUnmarshal func([]byte, any) error //nolint:gochecknoglobals // in this particular case, we need a global to enable the feature from another module + +// EnableYAMLWithUnmarshal registers a YAML-capable unmarshaler. +// +// This is not intended for concurrent use. +func EnableYAMLWithUnmarshal(unmarshaler func([]byte, any) error) { + enableYAMLUnmarshal = unmarshaler +} + +// Unmarshal is a wrapper to some exernal library to unmarshal YAML documents. +func Unmarshal(in []byte, out any) error { + if enableYAMLUnmarshal == nil { + // fail early and loud + panic(` +YAML is not enabled yet! + +You should enable a YAML library before running this test, +e.g. by adding the following to your imports: + +import ( + _ "github.com/go-openapi/testify/enable/yaml/v2" +) +`, + ) + + } + return enableYAMLUnmarshal(in, out) +} diff --git a/internal/assertions/equal.go b/internal/assertions/equal.go new file mode 100644 index 000000000..700f1ab4d --- /dev/null +++ b/internal/assertions/equal.go @@ -0,0 +1,500 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "reflect" + "time" +) + +// 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. +// +// Examples: +// +// success: 123, 123 +// failure: 123, 456 +func Equal(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} + +// 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. +// +// Examples: +// +// success: &staticVar, staticVarPtr +// failure: &staticVar, ptr("static string") +func Same(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: &staticVar, ptr("static string") +// failure: &staticVar, staticVarPtr +func NotSame(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} + +// validateEqualArgs checks whether provided arguments can be safely used in the +// Equal/NotEqual functions. +func validateEqualArgs(expected, actual any) error { + if expected == nil && actual == nil { + return nil + } + + if isFunction(expected) || isFunction(actual) { + return errors.New("cannot take func type as argument") + } + return nil +} + +// 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 any) (same bool, ok bool) { + firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) + if firstPtr.Kind() != reflect.Pointer || secondPtr.Kind() != reflect.Pointer { + 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 any) (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) + default: + return truncatingFormat("%#v", expected), truncatingFormat("%#v", actual) + } +} + +// EqualValues asserts that two objects are equal or convertible to the larger +// type and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +// +// Examples: +// +// success: uint32(123), int32(123) +// failure: uint32(123), int32(456) +func EqualValues(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// +// Examples: +// +// success: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2} +// failure: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1} +func EqualExportedValues(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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)) +// +// Examples: +// +// success: int32(123), int32(123) +// failure: int32(123), int64(123) +func Exactly(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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) +// +// Examples: +// +// success: "not nil" +// failure: nil +func NotNil(t T, object any, msgAndArgs ...any) bool { + if !isNil(object) { + return true + } + if h, ok := t.(H); 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 any) 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() + default: + return false + } +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +// +// Examples: +// +// success: nil +// failure: "not nil" +func Nil(t T, object any, msgAndArgs ...any) bool { + if isNil(object) { + return true + } + if h, ok := t.(H); ok { + h.Helper() + } + return Fail(t, "Expected nil, but got: "+truncatingFormat("%#v", object), msgAndArgs...) +} + +// 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) +// +// Examples: +// +// success: "" +// failure: "not empty" +// +// [Zero values]: https://go.dev/ref/spec#The_zero_value +func Empty(t T, object any, msgAndArgs ...any) bool { + pass := isEmpty(object) + if !pass { + if h, ok := t.(H); ok { + h.Helper() + } + Fail(t, "Should be empty, but was "+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]) +// } +// +// Examples: +// +// success: "not empty" +// failure: "" +func NotEmpty(t T, object any, msgAndArgs ...any) bool { + pass := !isEmpty(object) + if !pass { + if h, ok := t.(H); ok { + h.Helper() + } + Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) + } + + return pass +} + +// 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). +// +// Examples: +// +// success: 123, 456 +// failure: 123, 123 +func NotEqual(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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) +// +// Examples: +// +// success: uint32(123), int32(456) +// failure: uint32(123), int32(123) +func NotEqualValues(t T, expected, actual any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + + if ObjectsAreEqualValues(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) + } + + return true +} + +// isEmpty gets whether the specified object is considered empty or not. +func isEmpty(object any) 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()) + default: + return false + } +} + +// copyExportedFields iterates downward through nested data structures and creates a copy +// that only contains the exported struct fields. +func copyExportedFields(expected any) any { + 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 := range expectedType.NumField() { + 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.Pointer: + 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 := range expectedValue.Len() { + 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 + } +} + +func isFunction(arg any) bool { + if arg == nil { + return false + } + return reflect.TypeOf(arg).Kind() == reflect.Func +} diff --git a/internal/assertions/equal_impl_test.go b/internal/assertions/equal_impl_test.go new file mode 100644 index 000000000..f4c24cd3c --- /dev/null +++ b/internal/assertions/equal_impl_test.go @@ -0,0 +1,209 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "testing" + "time" +) + +func TestEqualUnexportedImplementationDetails(t *testing.T) { + t.Parallel() + + t.Run("samePointers", testSamePointers()) + t.Run("formatUnequalValue", testFormatUnequalValues()) + t.Run("isEmpty", testIsEmpty()) + t.Run("validateEqualArgs", testValidateEqualArgs()) +} + +func testSamePointers() func(*testing.T) { + return func(t *testing.T) { + t.Parallel() + + for tt := range equalSamePointersCases() { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + same, ok := samePointers(tt.args.first, tt.args.second) + tt.same(t, same) + tt.ok(t, ok) + }) + } + } +} + +func testFormatUnequalValues() func(*testing.T) { + return func(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, fmt.Sprintf(`&%s.testStructType{Val:"test"}`, shortpkg), expected, "value should not include type annotation") + Equal(t, fmt.Sprintf(`&%s.testStructType{Val:"test"}`, shortpkg), actual, "value should not include type annotation") + } +} + +func testIsEmpty() func(*testing.T) { + return func(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([]any(nil))) + True(t, isEmpty([]any{})) + 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 testValidateEqualArgs() func(*testing.T) { + return func(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") + } + } +} diff --git a/internal/assertions/equal_test.go b/internal/assertions/equal_test.go new file mode 100644 index 000000000..bc40958fe --- /dev/null +++ b/internal/assertions/equal_test.go @@ -0,0 +1,745 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "iter" + "os" + "reflect" + "regexp" + "slices" + "testing" + "time" +) + +const shortpkg = "assertions" + +func TestEqualNotNil(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !NotNil(mock, new(AssertionTesterConformingObject)) { + t.Error("NotNil should return true: object is not nil") + } + + if NotNil(mock, nil) { + t.Error("NotNil should return false: object is nil") + } + + if NotNil(mock, (*struct{})(nil)) { + t.Error("NotNil should return false: object is (*struct{})(nil)") + } +} + +func TestEqualNil(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Nil(mock, nil) { + t.Error("Nil should return true: object is nil") + } + + if !Nil(mock, (*struct{})(nil)) { + t.Error("Nil should return true: object is (*struct{})(nil)") + } + + if Nil(mock, new(AssertionTesterConformingObject)) { + t.Error("Nil should return false: object is not nil") + } +} + +func TestEqualSameWithSliceTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Same(mock, &[]int{}, &longSlice) + Contains(t, mock.errorString(), `&[]int{0, 0, 0,`) +} + +func TestEqualNotSameWithSliceTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotSame(mock, &longSlice, &longSlice) + Contains(t, mock.errorString(), `&[]int{0, 0, 0,`) +} + +func TestEqualNotEqualWithSliceTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotEqual(mock, longSlice, longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Should not be: []int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated>`) +} + +func TestEqualNotEqualValuesWithSliceTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NotEqualValues(mock, longSlice, longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Should not be: []int{0, 0, 0,`) + Contains(t, mock.errorString(), `<... truncated>`) +} + +func TestEqual(t *testing.T) { + t.Parallel() + + for c := range equalCases() { + t.Run(fmt.Sprintf("Equal(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := Equal(mock, 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 TestEqualSame(t *testing.T) { + t.Parallel() + mock := new(mockT) + + if Same(mock, ptr(1), ptr(1)) { + t.Error("Same should return false") + } + + if Same(mock, 1, 1) { + t.Error("Same should return false") + } + + p := ptr(2) + if Same(mock, p, *p) { + t.Error("Same should return false") + } + + if !Same(mock, 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(mock, dps, ps) { + t.Error("Same should return false") + } + expPat := + fmt.Sprintf(`expected: &%[1]s.s\{i:1\} \(%[1]s.sPtr\)\((0x[a-f0-9]+)\)\s*\n`, shortpkg) + + fmt.Sprintf(`\s+actual : &%[1]s.s\{i:1\} \(\*%[1]s.s\)\((0x[a-f0-9]+)\)`, shortpkg) + Regexp(t, regexp.MustCompile(expPat), mock.errorString()) + }) +} + +func TestEqualNotSame(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !NotSame(mock, ptr(1), ptr(1)) { + t.Error("NotSame should return true; different pointers") + } + + if !NotSame(mock, 1, 1) { + t.Error("NotSame should return true; constant inputs") + } + + p := ptr(2) + if !NotSame(mock, p, *p) { + t.Error("NotSame should return true; mixed-type inputs") + } + + if NotSame(mock, p, p) { + t.Error("NotSame should return false") + } +} + +func TestEqualNotEqual(t *testing.T) { + t.Parallel() + + for c := range equalNotEqualCases() { + t.Run(fmt.Sprintf("NotEqual(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := NotEqual(mock, 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() + + for c := range equalValuesCases() { + mock := new(testing.T) + + // Test NotEqualValues + t.Run(fmt.Sprintf("NotEqualValues(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + res := NotEqualValues(mock, 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(mock, c.expected, c.actual) + + if res != expectedEqualResult { + t.Errorf("EqualValues(%#v, %#v) should return %#v", c.expected, c.actual, expectedEqualResult) + } + }) + } +} + +func TestEqualEmpty(t *testing.T) { + t.Parallel() + + // TODO(fredbi): redundant test context declaration + 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 + } + + t.Run("should be empty", func(t *testing.T) { + mock := new(testing.T) + + True(t, Empty(mock, ""), "Empty string is empty") + True(t, Empty(mock, nil), "Nil is empty") + True(t, Empty(mock, []string{}), "Empty string array is empty") + True(t, Empty(mock, 0), "Zero int value is empty") + True(t, Empty(mock, false), "False value is empty") + True(t, Empty(mock, make(chan struct{})), "Channel without values is empty") + True(t, Empty(mock, s), "Nil string pointer is empty") + True(t, Empty(mock, f), "Nil os.File pointer is empty") + True(t, Empty(mock, tiP), "Nil time.Time pointer is empty") + True(t, Empty(mock, tiNP), "time.Time is empty") + True(t, Empty(mock, TStruct{}), "struct with zero values is empty") + True(t, Empty(mock, TString("")), "empty aliased string is empty") + True(t, Empty(mock, sP), "ptr to nil value is empty") + True(t, Empty(mock, [1]int{}), "array is state") + }) + + t.Run("should not be empty", func(t *testing.T) { + mock := new(testing.T) + + False(t, Empty(mock, "something"), "Non Empty string is not empty") + False(t, Empty(mock, errors.New("something")), "Non nil object is not empty") + False(t, Empty(mock, []string{"something"}), "Non empty string array is not empty") + False(t, Empty(mock, 1), "Non-zero int value is not empty") + False(t, Empty(mock, true), "True value is not empty") + False(t, Empty(mock, chWithValue), "Channel with values is not empty") + False(t, Empty(mock, TStruct{x: 1}), "struct with initialized values is empty") + False(t, Empty(mock, TString("abc")), "non-empty aliased string is empty") + False(t, Empty(mock, xP), "ptr to non-nil value is not empty") + False(t, Empty(mock, [1]int{42}), "array is not state") + }) + + // error messages validation + for tt := range equalEmptyCases() { + t.Run(tt.name, func(t *testing.T) { + mock := new(captureT) + + res := Empty(mock, tt.value) + mock.checkResultAndErrMsg(t, res, tt.expectedResult, tt.expectedErrMsg) + }) + } +} + +func TestEqualNotEmpty(t *testing.T) { + t.Parallel() + + t.Run("should not be empty", func(t *testing.T) { + mock := new(testing.T) + + False(t, NotEmpty(mock, ""), "Empty string is empty") + False(t, NotEmpty(mock, nil), "Nil is empty") + False(t, NotEmpty(mock, []string{}), "Empty string array is empty") + False(t, NotEmpty(mock, 0), "Zero int value is empty") + False(t, NotEmpty(mock, false), "False value is empty") + False(t, NotEmpty(mock, make(chan struct{})), "Channel without values is empty") + False(t, NotEmpty(mock, [1]int{}), "array is state") + }) + + t.Run("should be empty", func(t *testing.T) { + mock := new(testing.T) + + chWithValue := make(chan struct{}, 1) + chWithValue <- struct{}{} + + False(t, NotEmpty(mock, ""), "Empty string is empty") + True(t, NotEmpty(mock, "something"), "Non Empty string is not empty") + True(t, NotEmpty(mock, errors.New("something")), "Non nil object is not empty") + True(t, NotEmpty(mock, []string{"something"}), "Non empty string array is not empty") + True(t, NotEmpty(mock, 1), "Non-zero int value is not empty") + True(t, NotEmpty(mock, true), "True value is not empty") + True(t, NotEmpty(mock, chWithValue), "Channel with values is not empty") + True(t, NotEmpty(mock, [1]int{42}), "array is not state") + }) + + // error messages validation + for tt := range equalNotEmptyCases() { + t.Run(tt.name, func(t *testing.T) { + mock := new(captureT) + + res := NotEmpty(mock, tt.value) + mock.checkResultAndErrMsg(t, tt.expectedResult, res, tt.expectedErrMsg) + }) + } +} + +func TestEqualExactly(t *testing.T) { + t.Parallel() + + for c := range equalExactlyCases() { + t.Run(fmt.Sprintf("Exactly(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + res := Exactly(mock, c.expected, c.actual) + if res != c.result { + t.Errorf("Exactly(%#v, %#v) should return %#v", c.expected, c.actual, c.result) + } + }) + } +} + +func TestEqualBytes(t *testing.T) { + t.Parallel() + + i := 0 + for c := range equalBytesCases() { + Equal(t, reflect.DeepEqual(c.a, c.b), ObjectsAreEqual(c.a, c.b), "case %d failed", i) + i++ + } +} + +type equalCase struct { + expected any + actual any + result bool + remark string +} + +func equalCases() iter.Seq[equalCase] { + type myType string + var m map[string]any + return slices.Values([]equalCase{ + {"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, ""}, + }) +} + +type samePointersCase struct { + name string + args args + same BoolAssertionFunc + ok BoolAssertionFunc +} + +type args struct { + first any + second any +} + +func ptr(i int) *int { + return &i +} + +func equalSamePointersCases() iter.Seq[samePointersCase] { + p := ptr(2) + return slices.Values([]samePointersCase{ + { + 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, + }, + }) +} + +type equalNotEqualCase struct { + expected any + actual any + result bool +} + +func equalNotEqualCases() iter.Seq[equalNotEqualCase] { + return slices.Values([]equalNotEqualCase{ + // 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}, + }) +} + +type equalValuesCase struct { + expected any + actual any + notEqualResult bool // result for NotEqualValues +} + +func equalValuesCases() iter.Seq[equalValuesCase] { + return slices.Values([]equalValuesCase{ + // 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}, + }) +} + +type equalEmptyCase struct { + name string + value any + expectedResult bool + expectedErrMsg string +} + +func equalEmptyCases() iter.Seq[equalEmptyCase] { + 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 + } + + return slices.Values([]equalEmptyCase{ + { + 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: "", + }, + }) +} + +type equalNotEmptyCase struct { + name string + value any + expectedResult bool + expectedErrMsg string +} + +func equalNotEmptyCases() iter.Seq[equalNotEmptyCase] { + return slices.Values([]equalNotEmptyCase{ + { + 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: "", + }, + }) +} + +type diffTestingStruct struct { + A string + B int +} + +func (d *diffTestingStruct) String() string { + return d.A +} + +type equalExactlyCase struct { + expected any + actual any + result bool +} + +func equalExactlyCases() iter.Seq[equalExactlyCase] { + a := float32(1) + b := float64(1) + c := float32(1) + d := float32(2) + + return slices.Values([]equalExactlyCase{ + {a, b, false}, + {a, d, false}, + {a, c, true}, + {nil, a, false}, + {a, nil, false}, + }) +} + +type equalBytesCase struct { + a, b []byte +} + +func equalBytesCases() iter.Seq[equalBytesCase] { + return slices.Values([]equalBytesCase{ + {make([]byte, 2), make([]byte, 2)}, + {make([]byte, 2), make([]byte, 2, 3)}, + {nil, make([]byte, 0)}, + }) +} diff --git a/internal/assertions/error.go b/internal/assertions/error.go new file mode 100644 index 000000000..d95043e0b --- /dev/null +++ b/internal/assertions/error.go @@ -0,0 +1,261 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "reflect" + "strings" +) + +// ErrTest 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 ErrTest = errors.New("assert.ErrTest general error for testing") // TODO: make a type and a const. + +// 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) +// } +// +// Examples: +// +// success: nil +// failure: ErrTest +func NoError(t T, err error, msgAndArgs ...any) bool { + if err != nil { + if h, ok := t.(H); ok { + h.Helper() + } + return Fail(t, "Received unexpected error:\n"+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) +// +// Examples: +// +// success: ErrTest +// failure: nil +func Error(t T, err error, msgAndArgs ...any) bool { + if err == nil { + if h, ok := t.(H); 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) +// +// Examples: +// +// success: ErrTest, "assert.ErrTest general error for testing" +// failure: ErrTest, "wrong error message" +func EqualError(t T, theError error, errString string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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) +// +// Examples: +// +// success: ErrTest, "general error" +// failure: ErrTest, "not in message" +func ErrorContains(t T, theError error, contains string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", io.EOF), io.EOF +// failure: ErrTest, io.EOF +func ErrorIs(t T, err, target error, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: ErrTest, io.EOF +// failure: fmt.Errorf("wrap: %w", io.EOF), io.EOF +func NotErrorIs(t T, err, target error, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +// failure: ErrTest, new(*dummyError) +func ErrorAs(t T, err error, target any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: ErrTest, new(*dummyError) +// failure: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +func NotErrorAs(t T, err error, target any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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) { //nolint:errorlint // false positive: this type switch is checking for interfaces + 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 strings.Builder + errs := unwrapAll(err) + for i := range errs { + if i != 0 { + chain.WriteString("\n\t") + } + chain.WriteString(fmt.Sprintf("%q", errs[i].Error())) + if withType { + chain.WriteString(fmt.Sprintf(" (%T)", errs[i])) + } + } + return chain.String() +} diff --git a/internal/assertions/error_test.go b/internal/assertions/error_test.go new file mode 100644 index 000000000..ba02ecadb --- /dev/null +++ b/internal/assertions/error_test.go @@ -0,0 +1,460 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "io" + "iter" + "slices" + "testing" +) + +func TestErrorNoErrorWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + NoError(mock, fmt.Errorf("long: %v", longSlice)) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Received unexpected error: + long: [0 0 0`) + Contains(t, mock.errorString(), `<... truncated>`) +} + +func TestErrorEqualErrorWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + EqualError(mock, fmt.Errorf("long: %v", longSlice), "EOF") + Contains(t, mock.errorString(), ` + Error Trace: + Error: Error message not equal: + expected: "EOF" + actual : "long: [0 0 0`) + Contains(t, mock.errorString(), `<... truncated>`) +} + +func TestErrorContainsWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + ErrorContains(mock, fmt.Errorf("long: %v", longSlice), "EOF") + Contains(t, mock.errorString(), ` + Error Trace: + Error: Error "long: [0 0 0`) + Contains(t, mock.errorString(), `<... truncated> does not contain "EOF"`) +} + +func TestErrorIsWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + ErrorIs(mock, fmt.Errorf("long: %v", longSlice), fmt.Errorf("also: %v", longSlice)) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Target error should be in err chain: + expected: "also: [0 0 0`) + Contains(t, mock.errorString(), `<... truncated> + in chain: "long: [0 0 0`) +} + +func TestErrorNotErrorIsWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + err := fmt.Errorf("long: %v", longSlice) + NotErrorIs(mock, err, err) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Target error should not be in err chain: + found: "long: [0 0 0`) + Contains(t, mock.errorString(), `<... truncated> + in chain: "long: [0 0 0`) +} + +func TestErrorAsWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + var target *customError + ErrorAs(mock, fmt.Errorf("long: %v", longSlice), &target) + Contains(t, mock.errorString(), fmt.Sprintf(` + Error Trace: + Error: Should be in error chain: + expected: *%s.customError`, + shortpkg)) + Contains(t, mock.errorString(), ` + in chain: "long: [0 0 0`) + Contains(t, mock.errorString(), "<... truncated>") +} + +func TestErrorNotErrorAsWithErrorTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + var target *customError + NotErrorAs(mock, fmt.Errorf("long: %v %w", longSlice, &customError{}), &target) + Contains(t, mock.errorString(), fmt.Sprintf(` + Error Trace: + Error: Target error should not be in err chain: + found: *%s.customError`, + shortpkg)) + Contains(t, mock.errorString(), ` + in chain: "long: [0 0 0`) + Contains(t, mock.errorString(), "<... truncated>") +} + +func TestErrorNotErrorAs(t *testing.T) { + t.Parallel() + + for tt := range errorNotErrorAsCases() { + t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, &customError{}), func(t *testing.T) { + t.Parallel() + mock := new(captureT) + var target *customError + + res := NotErrorAs(mock, tt.err, &target) + mock.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) + }) + } +} + +func TestErrorIs(t *testing.T) { + t.Parallel() + + for tt := range errorIsCases() { + t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { + t.Parallel() + mock := new(captureT) + + res := ErrorIs(mock, tt.err, tt.target) + mock.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) + }) + } +} + +func TestErrorNotErrorIs(t *testing.T) { + t.Parallel() + + for tt := range errorNotErrorIsCases() { + t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) { + t.Parallel() + mock := new(captureT) + + res := NotErrorIs(mock, tt.err, tt.target) + mock.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) + }) + } +} + +func TestErrorAs(t *testing.T) { + t.Parallel() + + for tt := range errorAsCases() { + t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, &customError{}), func(t *testing.T) { + t.Parallel() + mock := new(captureT) + var target *customError + + res := ErrorAs(mock, tt.err, &target) + mock.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg) + }) + } +} + +func TestErrorNoError(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + // start with a nil error + var err error + + True(t, NoError(mock, err), "NoError should return True for nil arg") + + // now set an error + err = errors.New("some error") + + False(t, NoError(mock, 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(mock, err), "NoError should fail with empty error interface") +} + +func TestError(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + // start with a nil error + var err error + + False(t, Error(mock, err), "Error should return False for nil arg") + + // now set an error + err = errors.New("some error") + + True(t, Error(mock, err), "Error with error should return True") + + /* TODO(fred): testing formatted versions of method should be generated + // 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(mock, err), "Error should pass with empty error interface") +} + +func TestErrorEqualError(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + // start with a nil error + var err error + False(t, EqualError(mock, err, ""), + "EqualError should return false for nil arg") + + // now set an error + err = errors.New("some error") + False(t, EqualError(mock, err, "Not some error"), + "EqualError should return false for different error string") + True(t, EqualError(mock, err, "some error"), + "EqualError should return true") +} + +func TestErrorContains(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + // start with a nil error + var err error + False(t, ErrorContains(mock, err, ""), + "ErrorContains should return false for nil arg") + + // now set an error + err = errors.New("some error: another error") + False(t, ErrorContains(mock, err, "bad error"), + "ErrorContains should return false for different error string") + True(t, ErrorContains(mock, err, "some error"), + "ErrorContains should return true") + True(t, ErrorContains(mock, err, "another error"), + "ErrorContains should return true") +} + +type errorNotErrorAsCase struct { + err error + result bool + resultErrMsg string +} + +func errorNotErrorAsCases() iter.Seq[errorNotErrorAsCase] { + return slices.Values([]errorNotErrorAsCase{ + { + err: fmt.Errorf("wrap: %w", &customError{}), + result: false, + resultErrMsg: "" + + "Target error should not be in err chain:\n" + + fmt.Sprintf("found: *%[1]s.customError\n", shortpkg) + + "in chain: \"wrap: fail\" (*fmt.wrapError)\n" + + fmt.Sprintf("\t\"fail\" (*%[1]s.customError)\n", shortpkg), + }, + { + err: io.EOF, + result: true, + }, + { + err: nil, + result: true, + }, + }) +} + +type errorIsCase struct { + err error + target error + result bool + resultErrMsg string +} + +func errorIsCases() iter.Seq[errorIsCase] { + return slices.Values([]errorIsCase{ + { + 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", + }, + }) +} + +type errorNotErrorIsCase struct { + err error + target error + result bool + resultErrMsg string +} + +func errorNotErrorIsCases() iter.Seq[errorNotErrorIsCase] { + return slices.Values([]errorNotErrorIsCase{ + { + 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, + }, + }) +} + +type errorAsCase struct { + err error + result bool + resultErrMsg string +} + +func errorAsCases() iter.Seq[errorAsCase] { + return slices.Values([]errorAsCase{ + { + err: fmt.Errorf("wrap: %w", &customError{}), + result: true, + }, + { + err: io.EOF, + result: false, + resultErrMsg: "" + + "Should be in error chain:\n" + + fmt.Sprintf("expected: *%[1]s.customError\n", shortpkg) + + "in chain: \"EOF\" (*errors.errorString)\n", + }, + { + err: nil, + result: false, + resultErrMsg: "" + + "An error is expected but got nil.\n" + + fmt.Sprintf(`expected: *%s.customError`, shortpkg) + "\n", + }, + { + err: fmt.Errorf("abc: %w", errors.New("def")), + result: false, + resultErrMsg: "" + + "Should be in error chain:\n" + + fmt.Sprintf("expected: *%[1]s.customError\n", shortpkg) + + "in chain: \"abc: def\" (*fmt.wrapError)\n" + + "\t\"def\" (*errors.errorString)\n", + }, + }) +} + +type customError struct{} + +func (*customError) Error() string { return "fail" } diff --git a/internal/assertions/file.go b/internal/assertions/file.go new file mode 100644 index 000000000..c4a6bab30 --- /dev/null +++ b/internal/assertions/file.go @@ -0,0 +1,174 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "io/fs" + "os" +) + +// 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"non_existing_file") +func FileExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_file") +// failure: filepath.Join(testDataPath(),"existing_file") +func NoFileExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_dir") +// failure: filepath.Join(testDataPath(),"non_existing_dir") +func DirExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_dir") +// failure: filepath.Join(testDataPath(),"existing_dir") +func NoDirExists(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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...) +} + +// FileEmpty checks whether a file exists in the given path and is empty. +// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"empty_file") +// failure: filepath.Join(testDataPath(),"existing_file") +func FileEmpty(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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...) + } + if info.Mode()&fs.ModeSymlink > 0 { + target, err := os.Readlink(path) + if err != nil { + return Fail(t, fmt.Sprintf("could not resolve symlink %q", path), msgAndArgs...) + } + return FileEmpty(t, target, msgAndArgs...) + } + + if info.Size() > 0 { + return Fail(t, fmt.Sprintf("%q is not empty", path), msgAndArgs...) + } + + return true +} + +// FileNotEmpty checks whether a file exists in the given path and is not empty. +// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"empty_file") +func FileNotEmpty(t T, path string, msgAndArgs ...any) bool { + if h, ok := t.(H); 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...) + } + if info.Mode()&fs.ModeSymlink > 0 { + target, err := os.Readlink(path) + if err != nil { + return Fail(t, fmt.Sprintf("could not resolve symlink %q", path), msgAndArgs...) + } + return FileNotEmpty(t, target, msgAndArgs...) + } + + if info.Size() == 0 { + return Fail(t, fmt.Sprintf("%q is empty", path), msgAndArgs...) + } + + return true +} diff --git a/internal/assertions/file_test.go b/internal/assertions/file_test.go new file mode 100644 index 000000000..cf94abd26 --- /dev/null +++ b/internal/assertions/file_test.go @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "os" + "path/filepath" + "testing" +) + +func TestFileExists(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + True(t, FileExists(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + False(t, FileExists(mock, "random_file")) + + mock = new(testing.T) + False(t, FileExists(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + True(t, FileExists(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_file") + mock = new(testing.T) + True(t, FileExists(mock, link)) +} + +func TestFileNoFileExists(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, NoFileExists(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + True(t, NoFileExists(mock, "non_existent_file")) + + mock = new(testing.T) + True(t, NoFileExists(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + False(t, NoFileExists(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_file") + mock = new(testing.T) + False(t, NoFileExists(mock, link)) +} + +func TestFileDirExists(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, DirExists(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + False(t, DirExists(mock, "non_existent_dir")) + + mock = new(testing.T) + True(t, DirExists(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + False(t, DirExists(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_dir") + mock = new(testing.T) + False(t, DirExists(mock, link)) +} + +func TestFileNoDirExists(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + True(t, NoDirExists(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + True(t, NoDirExists(mock, "non_existent_dir")) + + mock = new(testing.T) + False(t, NoDirExists(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + True(t, NoDirExists(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_dir") + mock = new(testing.T) + True(t, NoDirExists(mock, link)) +} + +func TestFileEmpty(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + True(t, FileEmpty(mock, filepath.Join("testdata", "empty_file"))) + + mock = new(testing.T) + False(t, FileEmpty(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + False(t, FileEmpty(mock, "random_file")) + + mock = new(testing.T) + False(t, FileEmpty(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "empty_file")) + mock = new(testing.T) + True(t, FileEmpty(mock, link)) + + link = getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + False(t, FileEmpty(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_file") + mock = new(testing.T) + False(t, FileEmpty(mock, link)) +} + +func TestFileNotEmpty(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + True(t, FileNotEmpty(mock, filepath.Join("testdata", "existing_file"))) + + mock = new(testing.T) + False(t, FileNotEmpty(mock, filepath.Join("testdata", "empty_file"))) + + mock = new(testing.T) + False(t, FileNotEmpty(mock, "non_existent_file")) + + mock = new(testing.T) + False(t, FileNotEmpty(mock, filepath.Join("testdata", "existing_dir"))) + + link := getTempSymlinkPath(t, filepath.Join("testdata", "empty_file")) + mock = new(testing.T) + False(t, FileNotEmpty(mock, link)) + + link = getTempSymlinkPath(t, filepath.Join("testdata", "existing_file")) + mock = new(testing.T) + True(t, FileNotEmpty(mock, link)) + + link = getTempSymlinkPath(t, "non_existent_file") + mock = new(testing.T) + False(t, NoFileExists(mock, link)) +} + +func getTempSymlinkPath(t *testing.T, file string) string { + t.Helper() + + tempDir := t.TempDir() + link := filepath.Join(tempDir, filepath.Base(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 +} diff --git a/internal/assertions/helpers.go b/internal/assertions/helpers.go new file mode 100644 index 000000000..6ebce19d7 --- /dev/null +++ b/internal/assertions/helpers.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bufio" + "fmt" + "reflect" + "time" + + "github.com/go-openapi/testify/v2/internal/difflib" +) + +/* + Helper functions +*/ + +// 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 any, actual any) 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.TypeFor[string](): + e = reflect.ValueOf(expected).String() + a = reflect.ValueOf(actual).String() + case reflect.TypeFor[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 typeAndKind(v any) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + +// 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 any) string { + const maxMessageSize = bufio.MaxScanTokenSize/2 - 100 + + value := fmt.Sprintf(format, data) + // Give us space for two truncated objects and the surrounding sentence. + if len(value) > maxMessageSize { + value = value[0:maxMessageSize] + "<... truncated>" + } + return value +} diff --git a/internal/assertions/helpers_impl_test.go b/internal/assertions/helpers_impl_test.go new file mode 100644 index 000000000..f0edc1802 --- /dev/null +++ b/internal/assertions/helpers_impl_test.go @@ -0,0 +1,273 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bufio" + "errors" + "fmt" + "iter" + "slices" + "strings" + "testing" + "time" +) + +func TestHelpersUnexportedImplementationDetails(t *testing.T) { + t.Parallel() + + t.Run("truncatingFormat", testTruncatingFormat()) + t.Run("diff", testDiff()) + t.Run("diffList", testDiffList()) +} + +func testTruncatingFormat() func(*testing.T) { + return func(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 += "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") + } + } +} + +func testDiff() func(*testing.T) { + return func(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 testDiffList() func(*testing.T) { + return func(t *testing.T) { + t.Parallel() + + for test := range compareDiffListCases() { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + 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) + }) + } + } +} + +type compareDiffListCase struct { + name string + listA any + listB any + extraA []any + extraB []any +} + +func compareDiffListCases() iter.Seq[compareDiffListCase] { + return slices.Values([]compareDiffListCase{ + { + 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: []any{"hello"}, + extraB: nil, + }, + { + name: "extra A twice", + listA: []string{"hello", "hello", "hello", "world"}, + listB: []string{"hello", "world"}, + extraA: []any{"hello", "hello"}, + extraB: nil, + }, + { + name: "extra B", + listA: []string{"hello", "world"}, + listB: []string{"hello", "hello", "world"}, + extraA: nil, + extraB: []any{"hello"}, + }, + { + name: "extra B twice", + listA: []string{"hello", "world"}, + listB: []string{"hello", "hello", "world", "hello"}, + extraA: nil, + extraB: []any{"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: []any{1}, + extraB: []any{2}, + }, + }) +} diff --git a/internal/assertions/helpers_test.go b/internal/assertions/helpers_test.go new file mode 100644 index 000000000..8ac150e06 --- /dev/null +++ b/internal/assertions/helpers_test.go @@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions diff --git a/assert/http_assertions.go b/internal/assertions/http.go similarity index 69% rename from assert/http_assertions.go rename to internal/assertions/http.go index 18e52e506..7350765c5 100644 --- a/assert/http_assertions.go +++ b/internal/assertions/http.go @@ -1,4 +1,7 @@ -package assert +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions import ( "context" @@ -27,8 +30,13 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) ( // 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 ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpOK, "GET", "/", nil +// failure: httpError, "GET", "/", nil +func HTTPSuccess(t T, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } code, err := httpCode(handler, method, url, values) @@ -49,8 +57,13 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value // 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 ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpRedirect, "GET", "/", nil +// failure: httpError, "GET", "/", nil +func HTTPRedirect(t T, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } code, err := httpCode(handler, method, url, values) @@ -71,8 +84,13 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu // 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 ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpError, "GET", "/", nil +// failure: httpOK, "GET", "/", nil +func HTTPError(t T, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } code, err := httpCode(handler, method, url, values) @@ -93,8 +111,13 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values // 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 ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpOK, "GET", "/", nil, http.StatusOK +// failure: httpError, "GET", "/", nil, http.StatusOK +func HTTPStatusCode(t T, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } code, err := httpCode(handler, method, url, values) @@ -110,8 +133,8 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va return successful } -// HTTPBody is a helper that returns HTTP body of the response. It returns -// empty string if building a new request fails. +// HTTPBody is a helper that returns the HTTP body of the response. +// It returns the 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 { @@ -125,14 +148,18 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s return w.Body.String() } -// HTTPBodyContains asserts that a specified handler returns a -// body that contains a 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!" +func HTTPBodyContains(t T, handler http.HandlerFunc, method, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } body := HTTPBody(handler, method, url, values) @@ -151,8 +178,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!" +func HTTPBodyNotContains(t T, handler http.HandlerFunc, method, url string, values url.Values, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } body := HTTPBody(handler, method, url, values) diff --git a/internal/assertions/http_test.go b/internal/assertions/http_test.go new file mode 100644 index 000000000..592742ac1 --- /dev/null +++ b/internal/assertions/http_test.go @@ -0,0 +1,221 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "io" + "net/http" + "net/url" + "testing" +) + +func TestHTTPSuccess(t *testing.T) { + t.Parallel() + + mock1 := new(testing.T) + Equal(t, HTTPSuccess(mock1, httpOK, "GET", "/", nil), true) + False(t, mock1.Failed()) + + mock2 := new(testing.T) + Equal(t, HTTPSuccess(mock2, httpRedirect, "GET", "/", nil), false) + True(t, mock2.Failed()) + + mock3 := new(mockT) + Equal(t, HTTPSuccess( + mock3, httpError, "GET", "/", nil, + "was not expecting a failure here", + ), false) + True(t, mock3.Failed()) + Contains(t, mock3.errorString(), "was not expecting a failure here") + + mock4 := new(testing.T) + Equal(t, HTTPSuccess(mock4, httpStatusCode, "GET", "/", nil), false) + True(t, mock4.Failed()) + + mock5 := new(testing.T) + Equal(t, HTTPSuccess(mock5, httpReadBody, "POST", "/", nil), true) + False(t, mock5.Failed()) +} + +func TestHTTPRedirect(t *testing.T) { + t.Parallel() + mock1 := new(mockT) + + Equal(t, HTTPRedirect( + mock1, httpOK, "GET", "/", nil, + "was expecting a 3xx status code. Got 200.", + ), false) + True(t, mock1.Failed()) + Contains(t, mock1.errorString(), "was expecting a 3xx status code. Got 200.") + + mock2 := new(testing.T) + Equal(t, HTTPRedirect(mock2, httpRedirect, "GET", "/", nil), true) + False(t, mock2.Failed()) + + mock3 := new(testing.T) + Equal(t, HTTPRedirect(mock3, httpError, "GET", "/", nil), false) + True(t, mock3.Failed()) + + mock4 := new(testing.T) + Equal(t, HTTPRedirect(mock4, httpStatusCode, "GET", "/", nil), false) + True(t, mock4.Failed()) +} + +func TestHTTPError(t *testing.T) { + t.Parallel() + + mock1 := new(testing.T) + Equal(t, HTTPError(mock1, httpOK, "GET", "/", nil), false) + True(t, mock1.Failed()) + + mock2 := new(mockT) + Equal(t, HTTPError( + mock2, httpRedirect, "GET", "/", nil, + "Expected this request to error out. But it didn't", + ), false) + True(t, mock2.Failed()) + Contains(t, mock2.errorString(), "Expected this request to error out. But it didn't") + + mock3 := new(testing.T) + Equal(t, HTTPError(mock3, httpError, "GET", "/", nil), true) + False(t, mock3.Failed()) + + mock4 := new(testing.T) + Equal(t, HTTPError(mock4, httpStatusCode, "GET", "/", nil), false) + True(t, mock4.Failed()) +} + +func TestHTTPStatusCode(t *testing.T) { + t.Parallel() + + mock1 := new(testing.T) + Equal(t, HTTPStatusCode(mock1, httpOK, "GET", "/", nil, http.StatusSwitchingProtocols), false) + True(t, mock1.Failed()) + + mock2 := new(testing.T) + Equal(t, HTTPStatusCode(mock2, httpRedirect, "GET", "/", nil, http.StatusSwitchingProtocols), false) + True(t, mock2.Failed()) + + mock3 := new(mockT) + Equal(t, HTTPStatusCode( + mock3, httpError, "GET", "/", nil, http.StatusSwitchingProtocols, + "Expected the status code to be %d", http.StatusSwitchingProtocols, + ), false) + True(t, mock3.Failed()) + Contains(t, mock3.errorString(), "Expected the status code to be 101") + + mock4 := new(testing.T) + Equal(t, HTTPStatusCode(mock4, httpStatusCode, "GET", "/", nil, http.StatusSwitchingProtocols), true) + False(t, mock4.Failed()) +} + +func TestHTTPStatusWrapper(t *testing.T) { // TODO(fredbi): check if redundant (wrappers tests are generated) + t.Parallel() + mock := new(mockT) + + Equal(t, HTTPSuccess(mock, httpOK, "GET", "/", nil), true) + Equal(t, HTTPSuccess(mock, httpRedirect, "GET", "/", nil), false) + Equal(t, HTTPSuccess(mock, httpError, "GET", "/", nil), false) + + Equal(t, HTTPRedirect(mock, httpOK, "GET", "/", nil), false) + Equal(t, HTTPRedirect(mock, httpRedirect, "GET", "/", nil), true) + Equal(t, HTTPRedirect(mock, httpError, "GET", "/", nil), false) + + Equal(t, HTTPError(mock, httpOK, "GET", "/", nil), false) + Equal(t, HTTPError(mock, httpRedirect, "GET", "/", nil), false) + Equal(t, HTTPError(mock, httpError, "GET", "/", nil), true) +} + +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() + mock := new(mockT) + + True(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) + True(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) + False(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) + + False(t, HTTPBodyNotContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) + False(t, HTTPBodyNotContains( + mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World", + "Expected the request body to not contain 'World'. But it did.", + )) + True(t, HTTPBodyNotContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) + Contains(t, mock.errorString(), "Expected the request body to not contain 'World'. But it did.") + + True(t, HTTPBodyContains(mock, httpReadBody, "GET", "/", nil, "hello")) +} + +func TestHTTPBodyWrappers(t *testing.T) { + t.Parallel() + mock := new(mockT) + + True(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) + True(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) + False(t, HTTPBodyContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) + + False(t, HTTPBodyNotContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) + False(t, HTTPBodyNotContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) + True(t, HTTPBodyNotContains(mock, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) +} + +func httpHelloName(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +func httpOK(w http.ResponseWriter, _ *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, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpStatusCode(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusSwitchingProtocols) +} diff --git a/internal/assertions/ifaces.go b/internal/assertions/ifaces.go new file mode 100644 index 000000000..22d4847b3 --- /dev/null +++ b/internal/assertions/ifaces.go @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +// T is an interface wrapper around [testing.T]. +type T interface { + Errorf(format string, args ...any) +} + +// H is an interface for types that implement the Helper method. +// This allows marking functions as test helpers. +type H interface { + Helper() +} + +type failNower interface { + FailNow() +} + +type namer interface { + Name() string +} diff --git a/internal/assertions/ifaces_test.go b/internal/assertions/ifaces_test.go new file mode 100644 index 000000000..b995d0ba8 --- /dev/null +++ b/internal/assertions/ifaces_test.go @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +// 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{} diff --git a/internal/assertions/json.go b/internal/assertions/json.go new file mode 100644 index 000000000..c7a3e5924 --- /dev/null +++ b/internal/assertions/json.go @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// JSONEqBytes asserts that two JSON byte slices are equivalent. +// +// assert.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) +// +// Examples: +// +// success: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`) +// failure: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`) +func JSONEqBytes(t T, expected, actual []byte, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + var expectedJSONAsInterface, actualJSONAsInterface any + + if err := json.Unmarshal(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 bytes.Equal(actual, expected) { + return true + } + + if err := json.Unmarshal(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...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// +// Examples: +// +// success: `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}` +// failure: `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]` +func JSONEq(t T, expected, actual string, msgAndArgs ...any) bool { + return JSONEqBytes(t, []byte(expected), []byte(actual), msgAndArgs) +} diff --git a/internal/assertions/json_test.go b/internal/assertions/json_test.go new file mode 100644 index 000000000..49ff2fff4 --- /dev/null +++ b/internal/assertions/json_test.go @@ -0,0 +1,138 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +// TODO(fred): load fixtures and assertions from embedded testdata + +func TestJSONEq_EqualSONString(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + True(t, JSONEq(mock, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) +} + +func TestJSONEq_EquivalentButNotEqual(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + True(t, JSONEq(mock, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) +} + +func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + True(t, JSONEq(mock, + "{\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() + + mock := new(testing.T) + True(t, JSONEq(mock, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) +} + +func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) +} + +func TestJSONEq_HashesNotEquivalent(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) +} + +func TestJSONEq_ActualIsNotJSON(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, `{"foo": "bar"}`, "Not JSON")) +} + +func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, "Not JSON", `{"foo": "bar", "hello": "world"}`)) +} + +func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, "Not JSON", "Not JSON")) +} + +func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + False(t, JSONEq(mock, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)) +} + +func TestJSONEqBytes_EqualSONString(t *testing.T) { + mock := new(testing.T) + True(t, JSONEqBytes(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"hello": "world", "foo": "bar"}`))) +} + +func TestJSONEqBytes_EquivalentButNotEqual(t *testing.T) { + mock := new(testing.T) + True(t, JSONEqBytes(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`))) +} + +func TestJSONEqBytes_HashOfArraysAndHashes(t *testing.T) { + mock := new(testing.T) + True(t, JSONEqBytes(mock, + []byte("{\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}"), + []byte("{\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 TestJSONEqBytes_Array(t *testing.T) { + mock := new(testing.T) + True(t, JSONEqBytes(mock, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`["foo", {"nested": "hash", "hello": "world"}]`))) +} + +func TestJSONEqBytes_HashAndArrayNotEquivalent(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`{"foo": "bar", {"nested": "hash", "hello": "world"}}`))) +} + +func TestJSONEqBytes_HashesNotEquivalent(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte(`{"foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`))) +} + +func TestJSONEqBytes_ActualIsNotJSON(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte(`{"foo": "bar"}`), []byte("Not JSON"))) +} + +func TestJSONEqBytes_ExpectedIsNotJSON(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte("Not JSON"), []byte(`{"foo": "bar", "hello": "world"}`))) +} + +func TestJSONEqBytes_ExpectedAndActualNotJSON(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte("Not JSON"), []byte("Not JSON"))) +} + +func TestJSONEqBytes_ArraysOfDifferentOrder(t *testing.T) { + mock := new(testing.T) + False(t, JSONEqBytes(mock, []byte(`["foo", {"hello": "world", "nested": "hash"}]`), []byte(`[{ "hello": "world", "nested": "hash"}, "foo"]`))) +} diff --git a/internal/assertions/mock_test.go b/internal/assertions/mock_test.go new file mode 100644 index 000000000..efbb3e91c --- /dev/null +++ b/internal/assertions/mock_test.go @@ -0,0 +1,183 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bytes" + "fmt" + "regexp" + "runtime" + "strings" + "testing" +) + +type mockT struct { + errorFmt string + args []any +} + +// Helper is like [testing.T.Helper] but does nothing. +func (mockT) Helper() {} + +func (m *mockT) Errorf(format string, args ...any) { + m.errorFmt = format + m.args = args +} + +func (m *mockT) Failed() bool { + return m.errorFmt != "" +} + +func (m *mockT) errorString() string { + return fmt.Sprintf(m.errorFmt, m.args...) +} + +type mockFailNowT struct { + failed bool +} + +// Helper is like [testing.T.Helper] but does nothing. +func (mockFailNowT) Helper() {} + +func (m *mockFailNowT) Errorf(format string, args ...any) { + _ = format + _ = args +} + +func (m *mockFailNowT) FailNow() { + m.failed = true +} + +type captureT struct { + failed bool + msg string +} + +// Helper is like [testing.T.Helper] but does nothing. +func (captureT) Helper() {} + +func (ctt *captureT) Errorf(format string, args ...any) { + ctt.msg = fmt.Sprintf(format, args...) + ctt.failed = true +} + +func (ctt *captureT) 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) +} + +// 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 ...any) { + // 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...))) +} + +// 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 testCase struct { + expected any + actual any + result bool +} diff --git a/internal/assertions/number.go b/internal/assertions/number.go new file mode 100644 index 000000000..fdf60f963 --- /dev/null +++ b/internal/assertions/number.go @@ -0,0 +1,254 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "fmt" + "math" + "reflect" + "time" +) + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// +// Examples: +// +// success: 1.0, 1.01, 0.02 +// failure: 1.0, 1.1, 0.05 +func InDelta(t T, expected, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02 +// failure: []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05 +func InDeltaSlice(t T, expected, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 := range actualSlice.Len() { + 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. +// +// Examples: +// +// success: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02 +// failure: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05 +func InDeltaMapValues(t T, expected, actual any, delta float64, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 any) (float64, error) { + af, aok := toFloat(expected) + bf, bok := toFloat(actual) + if !aok || !bok { + return 0, errors.New("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, errors.New("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. +// +// Examples: +// +// success: 100.0, 101.0, 0.02 +// failure: 100.0, 110.0, 0.05 +func InEpsilon(t T, expected, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := t.(H); 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. +// +// Examples: +// +// success: []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02 +// failure: []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05 +func InEpsilonSlice(t T, expected, actual any, epsilon float64, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 := range expectedLen { + if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) { + return false + } + } + + return true +} + +func toFloat(x any) (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 +} diff --git a/internal/assertions/number_test.go b/internal/assertions/number_test.go new file mode 100644 index 000000000..b6eef3404 --- /dev/null +++ b/internal/assertions/number_test.go @@ -0,0 +1,235 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "iter" + "math" + "slices" + "testing" + "time" +) + +func TestNumberInDelta(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + True(t, InDelta(mock, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01") + True(t, InDelta(mock, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01") + True(t, InDelta(mock, 1, 2, 1), "|1 - 2| <= 1") + False(t, InDelta(mock, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") + False(t, InDelta(mock, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") + False(t, InDelta(mock, "", nil, 1), "Expected non numerals to fail") + False(t, InDelta(mock, 42, math.NaN(), 0.01), "Expected NaN for actual to fail") + False(t, InDelta(mock, math.NaN(), 42, 0.01), "Expected NaN for expected to fail") + True(t, InDelta(mock, math.NaN(), math.NaN(), 0.01), "Expected NaN for both to pass") + + for tc := range numberInDeltaCases() { + True(t, InDelta(mock, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta) + } +} + +func TestNumberInDeltaSlice(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + True(t, InDeltaSlice(mock, + []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(mock, + []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(mock, + []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(mock, "", nil, 1), "Expected non numeral slices to fail") +} + +func TestNumberInDeltaMapValues(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for tc := range numberInDeltaMapCases() { + tc.f(t, InDeltaMapValues(mock, tc.expect, tc.actual, tc.delta), tc.title+"\n"+diff(tc.expect, tc.actual)) + } +} + +func TestNumberInEpsilon(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for tc := range numberInEpsilonTrueCases() { + 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) + } + + for tc := range numberInEpsilonFalseCases() { + False(t, InEpsilon(mock, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) + } +} + +func TestNumberInEpsilonSlice(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + True(t, InEpsilonSlice(mock, + []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(mock, + []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(mock, "", nil, 1), "Expected non numeral slices to fail") +} + +type numberInDeltaCase struct { + a, b any + delta float64 +} + +func numberInDeltaCases() iter.Seq[numberInDeltaCase] { + return slices.Values([]numberInDeltaCase{ + {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}, + }) +} + +type numberInDeltaMapCase struct { + title string + expect any + actual any + f func(T, bool, ...any) bool + delta float64 +} + +func numberInDeltaMapCases() iter.Seq[numberInDeltaMapCase] { + return slices.Values([]numberInDeltaMapCase{ + { + 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, + }, + }) +} + +type numberInEpsilonCase struct { + a, b any + epsilon float64 +} + +func numberInEpsilonTrueCases() iter.Seq[numberInEpsilonCase] { + return slices.Values([]numberInEpsilonCase{ + {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}, + }) +} + +func numberInEpsilonFalseCases() iter.Seq[numberInEpsilonCase] { + return slices.Values([]numberInEpsilonCase{ + {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}, + }) +} diff --git a/internal/assertions/object.go b/internal/assertions/object.go new file mode 100644 index 000000000..11c4cbd67 --- /dev/null +++ b/internal/assertions/object.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bytes" + "reflect" +) + +// ObjectsAreEqual determines if two objects are considered equal. +// +// This function does no assertion of any kind. +func ObjectsAreEqual(expected, actual any) 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) +} + +// 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 any) 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 any) 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 +} diff --git a/internal/assertions/object_test.go b/internal/assertions/object_test.go new file mode 100644 index 000000000..6de607dbc --- /dev/null +++ b/internal/assertions/object_test.go @@ -0,0 +1,456 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "iter" + "math" + "slices" + "strings" + "testing" + "time" +) + +func TestObjectsAreEqual(t *testing.T) { + t.Parallel() + + for c := range objectEqualCases() { + 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() + + for c := range objectEqualValuesCases() { + 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) + } + }) + } +} + +func TestObjectsExportedFieldsAreEqual(t *testing.T) { + t.Parallel() + + for c := range objectExportedFieldsCases() { + 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 TestObjectsCopyExportedFields(t *testing.T) { + t.Parallel() + + for c := range objectCopyExportedFieldsCases() { + 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 TestObjectsEqualExportedValues(t *testing.T) { + t.Parallel() + + for c := range objectEqualExportedValuesCases() { + t.Run("", func(t *testing.T) { + mockT := new(mockT) + + 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) + } + }) + } +} + +type Nested struct { + Exported any + notExported any +} + +type S struct { + Exported1 any + Exported2 Nested + notExported1 any + notExported2 Nested +} + +type S2 struct { + foo any +} + +type S3 struct { + Exported1 *Nested + Exported2 *Nested +} + +type S4 struct { + Exported1 []*Nested +} + +type S5 struct { + Exported Nested +} + +type S6 struct { + Exported string + unexported string +} + +type objectEqualCase struct { + expected any + actual any + result bool +} + +func objectEqualCases() iter.Seq[objectEqualCase] { + return slices.Values([]objectEqualCase{ + // 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}, + }) +} + +func objectEqualValuesCases() iter.Seq[objectEqualCase] { + now := time.Now() + + return slices.Values([]objectEqualCase{ + {uint32(10), int32(10), true}, + {0, nil, false}, + {nil, 0, false}, + // should not be time zone independent + {now, now.In(time.Local), false}, //nolint:gosmopolitan // ok in this context: this is precisely the goal of this test + {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}, + }) +} + +func objectExportedFieldsCases() iter.Seq[objectEqualCase] { + intValue := 1 + + return slices.Values([]objectEqualCase{ + {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[any]*Nested{nil: nil}, 2}, + Nested{map[any]*Nested{nil: nil}, 2}, + true, + }, + { + Nested{map[any]*Nested{"a": nil}, 2}, + Nested{map[any]*Nested{"a": nil}, 2}, + true, + }, + { + Nested{map[any]*Nested{"a": nil}, 2}, + Nested{map[any]*Nested{"a": {1, 2}}, 2}, + false, + }, + { + Nested{map[any]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, + Nested{map[any]Nested{"a": {1, 5}, "b": {3, 7}}, 2}, + true, + }, + { + Nested{map[any]Nested{"a": {1, 2}, "b": {3, 4}}, 2}, + Nested{map[any]Nested{"a": {2, 2}, "b": {3, 4}}, 2}, + false, + }, + }) +} + +type objectCopyFieldsCase struct { + input any + expected any +} + +func objectCopyExportedFieldsCases() iter.Seq[objectCopyFieldsCase] { + intValue := 1 + + return slices.Values([]objectCopyFieldsCase{ + { + 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", ""}, + }, + }) +} + +type objectEqualExportedValuesCase struct { + value1 any + value2 any + expectedEqual bool + expectedFail string +} + +func objectEqualExportedValuesCases() iter.Seq[objectEqualExportedValuesCase] { + return slices.Values([]objectEqualExportedValuesCase{ + { + 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: fmt.Sprintf(` + Diff: + --- Expected + +++ Actual + @@ -3,3 +3,3 @@ + Exported2: (%s.Nested) { + - Exported: (int) 2, + + Exported: (int) 1, + notExported: (interface {}) `, + shortpkg), + }, + { + value1: S3{&Nested{1, 2}, &Nested{3, 4}}, + value2: S3{&Nested{"a", 2}, &Nested{3, 4}}, + expectedEqual: false, + expectedFail: fmt.Sprintf(` + Diff: + --- Expected + +++ Actual + @@ -2,3 +2,3 @@ + Exported1: (*%s.Nested)({ + - Exported: (int) 1, + + Exported: (string) (len=1) "a", + notExported: (interface {}) `, + shortpkg), + }, + { + value1: S4{[]*Nested{ + {1, 2}, + {3, 4}, + }}, + value2: S4{[]*Nested{ + {1, "a"}, + {2, "b"}, + }}, + expectedEqual: false, + expectedFail: fmt.Sprintf(` + Diff: + --- Expected + +++ Actual + @@ -7,3 +7,3 @@ + (*%s.Nested)({ + - Exported: (int) 3, + + Exported: (int) 2, + notExported: (interface {}) `, + shortpkg), + }, + { + 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: fmt.Sprintf(` + Diff: + --- Expected + +++ Actual + @@ -3,3 +3,3 @@ + Exported2: (%s.Nested) { + - Exported: (int) 2, + + Exported: (int) 1, + notExported: (interface {}) `, + shortpkg), + }, + { + 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: fmt.Sprintf(` + Diff: + --- Expected + +++ Actual + @@ -6,3 +6,3 @@ + (*%s.Nested)({ + - Exported: (int) 3, + + Exported: (int) 2, + notExported: (interface {}) `, + shortpkg), + }, + }) +} diff --git a/assert/assertion_order.go b/internal/assertions/order.go similarity index 69% rename from assert/assertion_order.go rename to internal/assertions/order.go index 4247c9557..f01c94a57 100644 --- a/assert/assertion_order.go +++ b/internal/assertions/order.go @@ -1,4 +1,7 @@ -package assert +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions import ( "fmt" @@ -6,7 +9,7 @@ import ( ) // isOrdered checks that collection contains orderable elements. -func isOrdered(t TestingT, object any, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...any) bool { +func isOrdered(t T, object any, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...any) 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...) @@ -44,49 +47,69 @@ func isOrdered(t TestingT, object any, allowedComparesResults []compareResult, f return true } -// IsIncreasing asserts that the collection is increasing +// 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: []int{1, 2, 3} +// failure: []int{1, 1, 2} +func IsIncreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } -// IsNonIncreasing asserts that the collection is not increasing +// 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: []int{2, 1, 1} +// failure: []int{1, 2, 3} +func IsNonIncreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +// 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: []int{3, 2, 1} +// failure: []int{1, 2, 3} +func IsDecreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } -// IsNonDecreasing asserts that the collection is not decreasing +// 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 any, msgAndArgs ...any) bool { - if h, ok := t.(tHelper); ok { +// +// Examples: +// +// success: []int{1, 1, 2} +// failure: []int{2, 1, 1} +func IsNonDecreasing(t T, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { h.Helper() } return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) diff --git a/assert/assertion_order_test.go b/internal/assertions/order_test.go similarity index 84% rename from assert/assertion_order_test.go rename to internal/assertions/order_test.go index deea57c60..25e370e88 100644 --- a/assert/assertion_order_test.go +++ b/internal/assertions/order_test.go @@ -1,4 +1,7 @@ -package assert +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions import ( "bytes" @@ -13,24 +16,23 @@ type orderedFixture struct { msg string } -func TestIsIncreasing(t *testing.T) { +func TestOrderIsIncreasing(t *testing.T) { t.Parallel() + mock := new(testing.T) - mockT := new(testing.T) - - if !IsIncreasing(mockT, []int{1, 2}) { + if !IsIncreasing(mock, []int{1, 2}) { t.Error("IsIncreasing should return true") } - if !IsIncreasing(mockT, []int{1, 2, 3, 4, 5}) { + if !IsIncreasing(mock, []int{1, 2, 3, 4, 5}) { t.Error("IsIncreasing should return true") } - if IsIncreasing(mockT, []int{1, 1}) { + if IsIncreasing(mock, []int{1, 1}) { t.Error("IsIncreasing should return false") } - if IsIncreasing(mockT, []int{2, 1}) { + if IsIncreasing(mock, []int{2, 1}) { t.Error("IsIncreasing should return false") } @@ -44,24 +46,23 @@ func TestIsIncreasing(t *testing.T) { } } -func TestIsNonIncreasing(t *testing.T) { +func TestOrderIsNonIncreasing(t *testing.T) { t.Parallel() + mock := new(testing.T) - mockT := new(testing.T) - - if !IsNonIncreasing(mockT, []int{2, 1}) { + if !IsNonIncreasing(mock, []int{2, 1}) { t.Error("IsNonIncreasing should return true") } - if !IsNonIncreasing(mockT, []int{5, 4, 4, 3, 2, 1}) { + if !IsNonIncreasing(mock, []int{5, 4, 4, 3, 2, 1}) { t.Error("IsNonIncreasing should return true") } - if !IsNonIncreasing(mockT, []int{1, 1}) { + if !IsNonIncreasing(mock, []int{1, 1}) { t.Error("IsNonIncreasing should return true") } - if IsNonIncreasing(mockT, []int{1, 2}) { + if IsNonIncreasing(mock, []int{1, 2}) { t.Error("IsNonIncreasing should return false") } @@ -75,24 +76,23 @@ func TestIsNonIncreasing(t *testing.T) { } } -func TestIsDecreasing(t *testing.T) { +func TestOrderIsDecreasing(t *testing.T) { t.Parallel() + mock := new(testing.T) - mockT := new(testing.T) - - if !IsDecreasing(mockT, []int{2, 1}) { + if !IsDecreasing(mock, []int{2, 1}) { t.Error("IsDecreasing should return true") } - if !IsDecreasing(mockT, []int{5, 4, 3, 2, 1}) { + if !IsDecreasing(mock, []int{5, 4, 3, 2, 1}) { t.Error("IsDecreasing should return true") } - if IsDecreasing(mockT, []int{1, 1}) { + if IsDecreasing(mock, []int{1, 1}) { t.Error("IsDecreasing should return false") } - if IsDecreasing(mockT, []int{1, 2}) { + if IsDecreasing(mock, []int{1, 2}) { t.Error("IsDecreasing should return false") } @@ -106,24 +106,23 @@ func TestIsDecreasing(t *testing.T) { } } -func TestIsNonDecreasing(t *testing.T) { +func TestOrderIsNonDecreasing(t *testing.T) { t.Parallel() + mock := new(testing.T) - mockT := new(testing.T) - - if !IsNonDecreasing(mockT, []int{1, 2}) { + if !IsNonDecreasing(mock, []int{1, 2}) { t.Error("IsNonDecreasing should return true") } - if !IsNonDecreasing(mockT, []int{1, 1, 2, 3, 4, 5}) { + if !IsNonDecreasing(mock, []int{1, 1, 2, 3, 4, 5}) { t.Error("IsNonDecreasing should return true") } - if !IsNonDecreasing(mockT, []int{1, 1}) { + if !IsNonDecreasing(mock, []int{1, 1}) { t.Error("IsNonDecreasing should return false") } - if IsNonDecreasing(mockT, []int{2, 1}) { + if IsNonDecreasing(mock, []int{2, 1}) { t.Error("IsNonDecreasing should return false") } @@ -137,17 +136,17 @@ func TestIsNonDecreasing(t *testing.T) { } } -func TestOrderingMsgAndArgsForwarding(t *testing.T) { +func TestOrderMsgAndArgsForwarding(t *testing.T) { t.Parallel() msgAndArgs := []any{"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...) }, + funcs := []func(t T){ + func(t T) { IsIncreasing(t, collection, msgAndArgs...) }, + func(t T) { IsNonIncreasing(t, collection, msgAndArgs...) }, + func(t T) { IsDecreasing(t, collection, msgAndArgs...) }, + func(t T) { IsNonDecreasing(t, collection, msgAndArgs...) }, } for _, f := range funcs { out := &outputT{buf: bytes.NewBuffer(nil)} diff --git a/internal/assertions/panic.go b/internal/assertions/panic.go new file mode 100644 index 000000000..f0b13a1ab --- /dev/null +++ b/internal/assertions/panic.go @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "runtime/debug" +) + +// 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() + +// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful +// for table driven tests. +type PanicAssertionFunc func(t T, f PanicTestFunc, msgAndArgs ...any) bool + +// didPanic returns true if the function passed to it panics. Otherwise, it returns false. +func didPanic(f PanicTestFunc) (didPanic bool, message any, stack string) { + didPanic = true + + defer func() { + message = recover() + if didPanic { + stack = string(debug.Stack()) + } + // Go 1.21 introduces runtime.PanicNilError on panic(nil), + // so maintain the same logic going forward (https://github.com/golang/go/issues/25448). + if err, ok := message.(error); ok { + if err.Error() == "panic called with nil argument" { + message = nil + } + } + }() + + // call the target function + f() + didPanic = false + + return +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +// +// Examples: +// +// success: func() { panic("panicking") } +// failure: func() { } +func Panics(t T, f PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); 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() }) +// +// Examples: +// +// success: "panicking", func() { panic("panicking") } +// failure: "panicking", func() { } +func PanicsWithValue(t T, expected any, f PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); 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() }) +// +// Examples: +// +// success: ErrTest.Error(), func() { panic(ErrTest) } +// failure: ErrTest.Error(), func() { } +func PanicsWithError(t T, errString string, f PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); 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() }) +// +// Examples: +// +// success: func() { } +// failure: func() { panic("panicking") } +func NotPanics(t T, f PanicTestFunc, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} diff --git a/internal/assertions/panic_test.go b/internal/assertions/panic_test.go new file mode 100644 index 000000000..07218314f --- /dev/null +++ b/internal/assertions/panic_test.go @@ -0,0 +1,167 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "errors" + "io" + "testing" +) + +func TestPanicDidPanic(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") + } + + { + funcDidPanic, msg, _ := didPanic(func() { + err := errors.New("test") + panic(err) // nil is no longer supported as a panic value and returns a runtime.PanicNil error + }) + if !funcDidPanic { + t.Error("didPanic should have panicked") + } + if msg == nil { + t.Errorf("didPanic should have returned something, but got nil") + } + } + + if funcDidPanic, _, _ := didPanic(func() { + }); funcDidPanic { + t.Error("didPanic should return false") + } +} + +func TestPanics(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Panics(mock, func() { + panic("Panic!") + }) { + t.Error("Panics should return true") + } + + if Panics(mock, func() { + }) { + t.Error("Panics should return false") + } +} + +func TestPanicsWithValue(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !PanicsWithValue(mock, "Panic!", func() { + panic("Panic!") + }) { + t.Error("PanicsWithValue should return true") + } + + { + err := errors.New("test") + if !PanicsWithValue(mock, err, func() { + panic(err) // panic no longer supports a nil argument + }) { + t.Error("PanicsWithValue should return true") + } + } + + if PanicsWithValue(mock, "Panic!", func() { + }) { + t.Error("PanicsWithValue should return false") + } + + if PanicsWithValue(mock, "at the disco", func() { + panic("Panic!") + }) { + t.Error("PanicsWithValue should return false") + } +} + +func TestPanicsWithError(t *testing.T) { + t.Parallel() + + mock := new(captureT) + succeeded := PanicsWithError(mock, "panic", func() { + panic(errors.New("panic")) + }) + mock.checkResultAndErrMsg(t, true, succeeded, "") + + succeeded = PanicsWithError(mock, "Panic!", func() {}) + Equal(t, false, succeeded, "PanicsWithError should return false") + Contains(t, mock.msg, "Panic value:\t") + + succeeded = PanicsWithError(mock, "expected panic err msg", func() { + panic(errors.New("actual panic err msg")) + }) + Equal(t, false, succeeded, "PanicsWithError should return false") + Contains(t, mock.msg, `Error message: "actual panic err msg"`) + + succeeded = PanicsWithError(mock, "expected panic err msg", func() { + panic(&PanicsWrapperError{"wrapped", errors.New("actual panic err msg")}) + }) + Equal(t, false, succeeded, "PanicsWithError should return false") + Contains(t, mock.msg, `Error message: "wrapped: actual panic err msg"`) + + succeeded = PanicsWithError(mock, "expected panic msg", func() { + panic("actual panic msg") + }) + Equal(t, false, succeeded, "PanicsWithError should return false") + Contains(t, mock.msg, `Panic value: "actual panic msg"`) + NotContains(t, mock.msg, "Error message:", "PanicsWithError should not report error message if not due an error") +} + +func TestPanicNotPanics(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !NotPanics(mock, func() { + }) { + t.Error("NotPanics should return true") + } + + if NotPanics(mock, func() { + panic("Panic!") + }) { + t.Error("NotPanics should return false") + } +} + +func TestPanicCallerInfoWithAutogeneratedFunctions(t *testing.T) { + t.Parallel() + + NotPanics(t, func() { + testAutogeneratedFunction() + }) +} + +type PanicsWrapperError struct { + Prefix string + Err error +} + +func (e PanicsWrapperError) Error() string { + return e.Prefix + ": " + e.Err.Error() +} + +func testAutogeneratedFunction() { + defer func() { + if err := recover(); err == nil { + panic("did not panic") + } + CallerInfo() + }() + t := struct { + io.Closer + }{} + c := t + c.Close() +} diff --git a/internal/assertions/spew.go b/internal/assertions/spew.go new file mode 100644 index 000000000..14ec97113 --- /dev/null +++ b/internal/assertions/spew.go @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "github.com/go-openapi/testify/v2/internal/spew" + +const spewMaxDepth = 10 + +//nolint:gochecknoglobals // spew is more easily configured using a global default config. This is okay in this context. +var ( + spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + DisableMethods: true, + MaxDepth: spewMaxDepth, + } + + spewConfigStringerEnabled = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + MaxDepth: spewMaxDepth, + } +) diff --git a/internal/assertions/string.go b/internal/assertions/string.go new file mode 100644 index 000000000..3cb824771 --- /dev/null +++ b/internal/assertions/string.go @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "regexp" +) + +// 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") +// +// Examples: +// +// success: "^start", "starting" +// failure: "^start", "not starting" +func Regexp(t T, rx any, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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") +// +// Examples: +// +// success: "^start", "not starting" +// failure: "^start", "starting" +func NotRegexp(t T, rx any, str any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + match := matchRegexp(rx, str) + + if match { + Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) + } + + return !match +} + +// matchRegexp return true if a specified regexp matches a string. +func matchRegexp(rx any, str any) 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)) + } +} diff --git a/internal/assertions/string_test.go b/internal/assertions/string_test.go new file mode 100644 index 000000000..bc805816f --- /dev/null +++ b/internal/assertions/string_test.go @@ -0,0 +1,180 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "iter" + "regexp" + "slices" + "testing" +) + +func TestStringEqual(t *testing.T) { + t.Parallel() + + i := 0 + for currCase := range stringEqualCases() { + mock := &bufferT{} + + Equal(mock, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...) + Regexp(t, regexp.MustCompile(currCase.want), mock.buf.String(), "Case %d", i) + i++ + } +} + +func TestSringEqualFormatting(t *testing.T) { + t.Parallel() + + i := 0 + for currCase := range stringEqualFormattingCases() { + mock := &bufferT{} + + Equal(mock, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...) + Regexp(t, regexp.MustCompile(currCase.want), mock.buf.String(), "Case %d", i) + i++ + } +} + +func TestStringRegexp(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for tc := range stringRegexpCases() { + True(t, Regexp(mock, tc.rx, tc.str)) + True(t, Regexp(mock, regexp.MustCompile(tc.rx), tc.str)) + True(t, Regexp(mock, regexp.MustCompile(tc.rx), []byte(tc.str))) + + False(t, NotRegexp(mock, tc.rx, tc.str)) + False(t, NotRegexp(mock, tc.rx, []byte(tc.str))) + False(t, NotRegexp(mock, regexp.MustCompile(tc.rx), tc.str)) + } + + for tc := range stringNotRegexpCases() { + False(t, Regexp(mock, tc.rx, tc.str), "Expected %q to not match %q", tc.rx, tc.str) + False(t, Regexp(mock, regexp.MustCompile(tc.rx), tc.str)) + False(t, Regexp(mock, regexp.MustCompile(tc.rx), []byte(tc.str))) + + True(t, NotRegexp(mock, tc.rx, tc.str)) + True(t, NotRegexp(mock, tc.rx, []byte(tc.str))) + True(t, NotRegexp(mock, regexp.MustCompile(tc.rx), tc.str)) + } +} + +type stringEqualCase struct { + equalWant string + equalGot string + msgAndArgs []any + want string +} + +func stringEqualCases() iter.Seq[stringEqualCase] { + return slices.Values([]stringEqualCase{ + { + equalWant: "hi, \nmy name is", + equalGot: "what,\nmy name is", + want: "\t[a-z]+.go:\\d+: \n" + // NOTE: the exact file name reported should be asserted in integration tests + "\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", + }, + }) +} + +func stringEqualFormattingCases() iter.Seq[stringEqualCase] { + return slices.Values([]stringEqualCase{ + { + equalWant: "want", + equalGot: "got", + want: "\t[a-z]+.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: []any{"hello, %v!", "world"}, + want: "\t[a-z]+.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: []any{123}, + want: "\t[a-z]+.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: []any{struct{ a string }{"hello"}}, + want: "\t[a-z]+.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", + }, + }) +} + +type stringRegexpCase struct { + rx, str string +} + +func stringRegexpCases() iter.Seq[stringRegexpCase] { + return slices.Values([]stringRegexpCase{ + {"^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"}, + }) +} + +func stringNotRegexpCases() iter.Seq[stringRegexpCase] { + return slices.Values([]stringRegexpCase{ + {"^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"}, + }) +} diff --git a/assert/testdata/empty_file b/internal/assertions/testdata/empty_file similarity index 100% rename from assert/testdata/empty_file rename to internal/assertions/testdata/empty_file diff --git a/_codegen/go.sum b/internal/assertions/testdata/existing_dir/.gitkeep similarity index 100% rename from _codegen/go.sum rename to internal/assertions/testdata/existing_dir/.gitkeep diff --git a/internal/assertions/testdata/existing_file b/internal/assertions/testdata/existing_file new file mode 100644 index 000000000..233dda281 --- /dev/null +++ b/internal/assertions/testdata/existing_file @@ -0,0 +1 @@ +NOT EMPTY diff --git a/internal/assertions/testdata/json/fixtures.json b/internal/assertions/testdata/json/fixtures.json new file mode 100644 index 000000000..63d7dd74f --- /dev/null +++ b/internal/assertions/testdata/json/fixtures.json @@ -0,0 +1,19 @@ +{ + "contents": "JSON fixtures to test JSON-related assertions", + "testcases": { + "helloworld": { + "data": { + "hello": "world", + "foo": "bar", + }, + "string": "\{\"hello\":\"world\",\"foo\":\"bar\"}" + }, + "reverse-helloworld": { + "data": { + "foo": "bar", + "hello": "world", + }, + "string": "\{\"bar\":\"bar\",\"hello\":\"world\"}" + } + } +} diff --git a/internal/assertions/testing.go b/internal/assertions/testing.go new file mode 100644 index 000000000..d1b0a72e2 --- /dev/null +++ b/internal/assertions/testing.go @@ -0,0 +1,248 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "bufio" + "bytes" + "fmt" + "runtime" + "strings" + "unicode" + "unicode/utf8" +) + +/* 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 { + return callerInfo(1) +} + +// FailNow fails test. +// +// Example: +// +// failure: "failed" +func FailNow(t T, failureMessage string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + + Fail(t, failureMessage, msgAndArgs...) + + // We cannot extend T with FailNow() and + // maintain backwards compatibility, so we fallback + // to panicking when FailNow is not available in T. + // 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. +// +// Example: +// +// failure: "failed" +func Fail(t T, failureMessage string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + + if failureMessage != "" || len(msgAndArgs) > 0 { + errorWithCallerInfo(t, 1, failureMessage, msgAndArgs...) + } + + return false +} + +// 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() +} + +func messageFromMsgAndArgs(msgAndArgs ...any) 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 { + format, ok := msgAndArgs[0].(string) + if ok { + return fmt.Sprintf(format, msgAndArgs[1:]...) + } + } + return "" +} + +// 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 callerInfo(offset int) []string { + var pc uintptr + var file string + var line int + var name string + + const stackFrameBufferSize = 10 + pcs := make([]uintptr, stackFrameBufferSize) + + callers := []string{} + + 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" && dir != "assertions") || 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 +} + +func errorWithCallerInfo(t T, offset int, failureMessage string, msgAndArgs ...any) { + content := []labeledContent{ + {"Error Trace", strings.Join(callerInfo(offset), "\n\t\t\t")}, + {"Error", failureMessage}, + } + + // Add test name if the Go version supports it + if n, ok := t.(namer); 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...)) +} + +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 strings.Builder + for _, v := range content { + output.WriteString("\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n") + } + + return output.String() +} diff --git a/internal/assertions/testing_test.go b/internal/assertions/testing_test.go new file mode 100644 index 000000000..a27e686a0 --- /dev/null +++ b/internal/assertions/testing_test.go @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +func TestTestingFailNowWithPlainT(t *testing.T) { + t.Parallel() + mock := &mockT{} + + Panics(t, func() { + FailNow(mock, "failed") + }, "should panic since mockT is missing FailNow()") +} + +func TestTestingFailNowWithFullT(t *testing.T) { + t.Parallel() + mock := &mockFailNowT{} + + NotPanics(t, func() { + FailNow(mock, "failed") + }, "should call mockT.FailNow() rather than panicking") +} diff --git a/internal/assertions/time.go b/internal/assertions/time.go new file mode 100644 index 000000000..f82d44861 --- /dev/null +++ b/internal/assertions/time.go @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "time" +) + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), 10*time.Second) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second +// failure: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second +func WithinDuration(t T, expected, actual time.Time, delta time.Duration, msgAndArgs ...any) bool { + if h, ok := t.(H); 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)) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +// failure: time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +func WithinRange(t T, actual, start, end time.Time, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} diff --git a/internal/assertions/time_test.go b/internal/assertions/time_test.go new file mode 100644 index 000000000..4531afd2e --- /dev/null +++ b/internal/assertions/time_test.go @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "regexp" + "testing" + "time" +) + +func TestTimeWithinDuration(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + a := time.Now() + b := a.Add(10 * time.Second) + + True(t, WithinDuration(mock, a, b, 10*time.Second), "A 10s difference is within a 10s time difference") + True(t, WithinDuration(mock, b, a, 10*time.Second), "A 10s difference is within a 10s time difference") + + False(t, WithinDuration(mock, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference") + False(t, WithinDuration(mock, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference") + + False(t, WithinDuration(mock, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference") + False(t, WithinDuration(mock, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference") + + False(t, WithinDuration(mock, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference") + False(t, WithinDuration(mock, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference") +} + +func TestTimeWithinRange(t *testing.T) { + t.Parallel() + + mock := new(testing.T) + n := time.Now() + s := n.Add(-time.Second) + e := n.Add(time.Second) + + True(t, WithinRange(mock, n, n, n), "Exact same actual, start, and end values return true") + + True(t, WithinRange(mock, n, s, e), "Time in range is within the time range") + True(t, WithinRange(mock, s, s, e), "The start time is within the time range") + True(t, WithinRange(mock, e, s, e), "The end time is within the time range") + + False(t, WithinRange(mock, s.Add(-time.Nanosecond), s, e, "Just before the start time is not within the time range")) + False(t, WithinRange(mock, e.Add(time.Nanosecond), s, e, "Just after the end time is not within the time range")) + + False(t, WithinRange(mock, n, e, s, "Just after the end time is not within the time range")) +} + +func TestTimeEqualityErrorFormatting(t *testing.T) { + t.Parallel() + mock := new(mockT) + + Equal(mock, 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), mock.errorString()) +} diff --git a/internal/assertions/type.go b/internal/assertions/type.go new file mode 100644 index 000000000..663160d51 --- /dev/null +++ b/internal/assertions/type.go @@ -0,0 +1,129 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + "reflect" +) + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// +// Examples: +// +// success: ptr(dummyInterface), new(testing.T) +// failure: (*error)(nil), new(testing.T) +func Implements(t T, interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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)) +// +// Examples: +// +// success: (*error)(nil), new(testing.T) +// failure: ptr(dummyInterface), new(testing.T) +func NotImplements(t T, interfaceObject any, object any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 any) 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{}) +// +// Examples: +// +// success: 123, 456 +// failure: int32(123), int64(456) +func IsType(t T, expectedType, object any, msgAndArgs ...any) bool { + if isType(expectedType, object) { + return true + } + if h, ok := t.(H); 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{}) +// +// Examples: +// +// success: int32(123), int64(456) +// failure: 123, 456 +func IsNotType(t T, theType, object any, msgAndArgs ...any) bool { + if !isType(theType, object) { + return true + } + if h, ok := t.(H); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...) +} + +// Zero asserts that i is the zero value for its type. +// +// Examples: +// +// success: 0 +// failure: 1 +func Zero(t T, i any, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, "Should be zero, but was "+truncatingFormat("%v", i), msgAndArgs...) + } + return true +} + +// NotZero asserts that i is not the zero value for its type. +// +// Examples: +// +// success: 1 +// failure: 0 +func NotZero(t T, i any, msgAndArgs ...any) bool { + if h, ok := t.(H); 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 +} diff --git a/internal/assertions/type_test.go b/internal/assertions/type_test.go new file mode 100644 index 000000000..4da9d1471 --- /dev/null +++ b/internal/assertions/type_test.go @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "iter" + "slices" + "testing" +) + +func TestTypeImplements(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !Implements(mock, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { + t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface") + } + if Implements(mock, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { + t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") + } + if Implements(mock, (*AssertionTesterInterface)(nil), nil) { + t.Error("Implements method should return false: nil does not implement AssertionTesterInterface") + } +} + +func TestTypeNotImplements(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !NotImplements(mock, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { + t.Error("NotImplements method should return true: AssertionTesterNonConformingObject does not implement AssertionTesterInterface") + } + if NotImplements(mock, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { + t.Error("NotImplements method should return false: AssertionTesterConformingObject implements AssertionTesterInterface") + } + if NotImplements(mock, (*AssertionTesterInterface)(nil), nil) { + t.Error("NotImplements method should return false: nil can't be checked to be implementing AssertionTesterInterface or not") + } +} + +func TestTypeIsType(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !IsType(mock, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { + t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") + } + if IsType(mock, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { + t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") + } +} + +func TestTypeNotIsType(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + if !IsNotType(mock, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { + t.Error("NotIsType should return true: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") + } + if IsNotType(mock, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { + t.Error("NotIsType should return false: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") + } +} + +func TestTypeZeroWithSliceTooLongToPrint(t *testing.T) { + t.Parallel() + mock := new(mockT) + + longSlice := make([]int, 1_000_000) + Zero(mock, longSlice) + Contains(t, mock.errorString(), ` + Error Trace: + Error: Should be zero, but was [0 0 0`) + Contains(t, mock.errorString(), `<... truncated>`) +} + +func TestTypeZero(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for test := range typeZeros() { + True(t, Zero(mock, test, "%#v is not the %T zero value", test, test)) + } + + for test := range typeNonZeros() { + False(t, Zero(mock, test, "%#v is not the %T zero value", test, test)) + } +} + +func TestTypeNotZero(t *testing.T) { + t.Parallel() + mock := new(testing.T) + + for test := range typeZeros() { + False(t, NotZero(mock, test, "%#v is not the %T zero value", test, test)) + } + + for test := range typeNonZeros() { + True(t, NotZero(mock, test, "%#v is not the %T zero value", test, test)) + } +} + +func TestTypeDiffEmptyCases(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 TestTypeDiffRace(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 + } + } +} + +func typeZeros() iter.Seq[any] { + return slices.Values([]any{ + 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]any{}, + []any(nil), + struct{ x int }{}, + (*any)(nil), + (func())(nil), + nil, + any(nil), + map[any]any(nil), + (chan any)(nil), + (<-chan any)(nil), + (chan<- any)(nil), + }) +} + +func typeNonZeros() iter.Seq[any] { + var i int + + return slices.Values([]any{ + 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]any{1}, + []any{}, + struct{ x int }{1}, + (&i), + (func() {}), + any(1), + map[any]any{}, + (make(chan any)), + (<-chan any)(make(chan any)), + (chan<- any)(make(chan any)), + }) +} diff --git a/assert/internal/unsafetests/doc.go b/internal/assertions/unsafetests/doc.go similarity index 100% rename from assert/internal/unsafetests/doc.go rename to internal/assertions/unsafetests/doc.go diff --git a/assert/internal/unsafetests/unsafetests_test.go b/internal/assertions/unsafetests/unsafetests_test.go similarity index 71% rename from assert/internal/unsafetests/unsafetests_test.go rename to internal/assertions/unsafetests/unsafetests_test.go index 9f2060e1f..bc4bd9b68 100644 --- a/assert/internal/unsafetests/unsafetests_test.go +++ b/internal/assertions/unsafetests/unsafetests_test.go @@ -5,23 +5,14 @@ import ( "testing" "unsafe" - "github.com/go-openapi/testify/v2/assert" + assert "github.com/go-openapi/testify/v2/internal/assertions" ) -type ignoreTestingT struct{} +// safeguard: ignoreT implements [assert.T] +var _ assert.T = ignoreT{} -var _ assert.TestingT = ignoreTestingT{} - -func (ignoreTestingT) Helper() {} - -func (ignoreTestingT) Errorf(format string, args ...any) { - // Run the formatting, but ignore the result - msg := fmt.Sprintf(format, args...) - _ = msg -} - -func TestUnsafePointers(t *testing.T) { - var ignore ignoreTestingT +func TestEqualUnsafePointers(t *testing.T) { + var ignore ignoreT 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")) @@ -32,3 +23,13 @@ func TestUnsafePointers(t *testing.T) { 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")) } + +type ignoreT struct{} + +func (ignoreT) Helper() {} + +func (ignoreT) Errorf(format string, args ...any) { + // Run the formatting, but ignore the result + msg := fmt.Sprintf(format, args...) + _ = msg +} diff --git a/internal/assertions/yaml.go b/internal/assertions/yaml.go new file mode 100644 index 000000000..79bae424e --- /dev/null +++ b/internal/assertions/yaml.go @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import ( + "fmt" + + "github.com/go-openapi/testify/v2/internal/assertions/enable/yaml" +) + +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// Usage: +// +// 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 +// ` +// assertions.YAMLEq(t, expected, actual) +// +// Example: +// +// panic: "key: value", "key: value" +// should panic without the yaml feature enabled. +func YAMLEq(t T, expected string, actual string, msgAndArgs ...any) bool { + if h, ok := t.(H); ok { + h.Helper() + } + var expectedYAMLAsInterface, actualYAMLAsInterface any + + 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...) +} diff --git a/internal/assertions/yaml_test.go b/internal/assertions/yaml_test.go new file mode 100644 index 000000000..0e4c8544f --- /dev/null +++ b/internal/assertions/yaml_test.go @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package assertions + +import "testing" + +func TestYAMLEq(t *testing.T) { + mock := new(mockT) + const yamlDoc = ` +--- +a: 1 +` + + if !Panics(t, func() { + _ = YAMLEq(mock, "", yamlDoc) + }) { + Fail(t, "expected YAMLEq to panic with default settings") + } +} diff --git a/require/assert_adhoc_example_1_test.go b/require/assert_adhoc_example_1_test.go new file mode 100644 index 000000000..0e0dfed1a --- /dev/null +++ b/require/assert_adhoc_example_1_test.go @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/require" +) + +func ExampleComparisonAssertionFunc() { + t := new(testing.T) // normally provided by test + + adder := func(x, y int) int { + return x + y + } + + for tt := range comparisonFuncCases() { + tt.requirement(t, tt.expect, adder(tt.args.x, tt.args.y)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type args struct { + x int + y int +} + +type comparisonFuncCase struct { + name string + args args + expect int + requirement require.ComparisonAssertionFunc +} + +func comparisonFuncCases() iter.Seq[comparisonFuncCase] { + return slices.Values([]comparisonFuncCase{ + {"2+2=4", args{2, 2}, 4, require.Equal}, + {"2+2!=5", args{2, 2}, 5, require.NotEqual}, + {"2+3==5", args{2, 3}, 5, require.Exactly}, + }) +} diff --git a/require/assert_adhoc_example_2_test.go b/require/assert_adhoc_example_2_test.go new file mode 100644 index 000000000..a739f6eb5 --- /dev/null +++ b/require/assert_adhoc_example_2_test.go @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "encoding/json" + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/require" +) + +func ExampleValueAssertionFunc() { + t := new(testing.T) // normally provided by test + + dumbParse := func(input string) any { + var x any + _ = json.Unmarshal([]byte(input), &x) + return x + } + + for tt := range valueAssertionCases() { + tt.requirement(t, dumbParse(tt.arg)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type valueAssertionCase struct { + name string + arg string + requirement require.ValueAssertionFunc +} + +func valueAssertionCases() iter.Seq[valueAssertionCase] { + return slices.Values([]valueAssertionCase{ + {"true is not nil", "true", require.NotNil}, + {"empty string is nil", "", require.Nil}, + {"zero is not nil", "0", require.NotNil}, + {"zero is zero", "0", require.Zero}, + {"false is zero", "false", require.Zero}, + }) +} diff --git a/require/assert_adhoc_example_3_test.go b/require/assert_adhoc_example_3_test.go new file mode 100644 index 000000000..92a4061cd --- /dev/null +++ b/require/assert_adhoc_example_3_test.go @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/require" +) + +func ExampleBoolAssertionFunc() { + t := new(testing.T) // normally provided by test + + isOkay := func(x int) bool { + return x >= 42 + } + + for tt := range boolAssertionCases() { + tt.requirement(t, isOkay(tt.arg)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type boolAssertionCase struct { + name string + arg int + requirement require.BoolAssertionFunc +} + +func boolAssertionCases() iter.Seq[boolAssertionCase] { + return slices.Values([]boolAssertionCase{ + {"-1 is bad", -1, require.False}, + {"42 is good", 42, require.True}, + {"41 is bad", 41, require.False}, + {"45 is cool", 45, require.True}, + }) +} diff --git a/require/assert_adhoc_example_4_test.go b/require/assert_adhoc_example_4_test.go new file mode 100644 index 000000000..980a080e1 --- /dev/null +++ b/require/assert_adhoc_example_4_test.go @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "encoding/json" + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/require" +) + +func ExampleErrorAssertionFunc() { + t := new(testing.T) // normally provided by test + + dumbParseNum := func(input string, v any) error { + return json.Unmarshal([]byte(input), v) + } + + for tt := range errorAssertionCases() { + var x float64 + tt.requirement(t, dumbParseNum(tt.arg, &x)) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type errorAssertionCase struct { + name string + arg string + requirement require.ErrorAssertionFunc +} + +func errorAssertionCases() iter.Seq[errorAssertionCase] { + return slices.Values([]errorAssertionCase{ + {"1.2 is number", "1.2", require.NoError}, + {"1.2.3 not number", "1.2.3", require.Error}, + {"true is not number", "true", require.Error}, + {"3 is number", "3", require.NoError}, + }) +} diff --git a/require/assert_adhoc_example_5_test.go b/require/assert_adhoc_example_5_test.go new file mode 100644 index 000000000..1b7e70fe4 --- /dev/null +++ b/require/assert_adhoc_example_5_test.go @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package require_test + +import ( + "fmt" + "iter" + "slices" + "testing" + + "github.com/go-openapi/testify/v2/require" +) + +func ExamplePanicAssertionFunc() { + t := new(testing.T) // normally provided by test + + for tt := range panicAssertionCases() { + tt.requirement(t, tt.panicFn) + } + + fmt.Printf("passed: %t", !t.Failed()) + + // Output: passed: true +} + +type panicAssertionCase struct { + name string + panicFn require.PanicTestFunc + requirement require.PanicAssertionFunc +} + +func panicAssertionCases() iter.Seq[panicAssertionCase] { + return slices.Values([]panicAssertionCase{ + {"with panic", func() { panic(nil) }, require.Panics}, + {"without panic", func() {}, require.NotPanics}, + }) +} diff --git a/require/examples_test.go b/require/examples_test.go deleted file mode 100644 index b7a30e7b0..000000000 --- a/require/examples_test.go +++ /dev/null @@ -1,126 +0,0 @@ -//nolint:testableexamples // not possible at this moment to build a testable example that involves testing.T -package require_test - -import ( - "encoding/json" - "testing" - - "github.com/go-openapi/testify/v2/require" -) - -func ExampleComparisonAssertionFunc() { - t := &testing.T{} // provided by test - - t.Run("example", func(t *testing.T) { - 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 require.ComparisonAssertionFunc - }{ - {"2+2=4", args{2, 2}, 4, require.Equal}, - {"2+2!=5", args{2, 2}, 5, require.NotEqual}, - {"2+3==5", args{2, 3}, 5, require.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 ExampleValueAssertionFunc() { - t := &testing.T{} // provided by test - - t.Run("example", func(t *testing.T) { - dumbParse := func(input string) any { - var x any - _ = json.Unmarshal([]byte(input), &x) - return x - } - - tests := []struct { - name string - arg string - assertion require.ValueAssertionFunc - }{ - {"true is not nil", "true", require.NotNil}, - {"empty string is nil", "", require.Nil}, - {"zero is not nil", "0", require.NotNil}, - {"zero is zero", "0", require.Zero}, - {"false is zero", "false", require.Zero}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.assertion(t, dumbParse(tt.arg)) - }) - } - }) -} - -func ExampleBoolAssertionFunc() { - t := &testing.T{} // provided by test - - t.Run("example", func(t *testing.T) { - isOkay := func(x int) bool { - return x >= 42 - } - - tests := []struct { - name string - arg int - assertion require.BoolAssertionFunc - }{ - {"-1 is bad", -1, require.False}, - {"42 is good", 42, require.True}, - {"41 is bad", 41, require.False}, - {"45 is cool", 45, require.True}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.assertion(t, isOkay(tt.arg)) - }) - } - }) -} - -func ExampleErrorAssertionFunc() { - t := &testing.T{} // provided by test - - dumbParseNum := func(input string, v any) error { - return json.Unmarshal([]byte(input), v) - } - - t.Run("example", func(t *testing.T) { - tests := []struct { - name string - arg string - assertion require.ErrorAssertionFunc - }{ - {"1.2 is number", "1.2", require.NoError}, - {"1.2.3 not number", "1.2.3", require.Error}, - {"true is not number", "true", require.Error}, - {"3 is number", "3", require.NoError}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var x float64 - tt.assertion(t, dumbParseNum(tt.arg, &x)) - }) - } - }) -} diff --git a/require/fixtures_test.go b/require/fixtures_test.go deleted file mode 100644 index fcfbbed47..000000000 --- a/require/fixtures_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package require - -const ( - // strings for JSON tests. - - notJSONString = "Not JSON" - fooBarObject = `{"foo": "bar"}` - simpleJSONObject = `{"hello": "world", "foo": "bar"}` - simpleJSONObjectReversed = `{"foo": "bar", "hello": "world"}` - simpleJSONNested = `["foo", {"hello": "world", "nested": "hash"}]` - simpleJSONNestedReversed = `["foo", {"nested": "hash", "hello": "world"}]` - simpleJSONNestedNotEq = `{"foo": "bar", {"nested": "hash", "hello": "world"}}` - simpleJSONArray = `["foo", {"hello": "world", "nested": "hash"}]` - simpleJSONArrayReversed = `[{ "hello": "world", "nested": "hash"}, "foo"]` - - nestedJSONObject = "{" + - "\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}" - nestedJSONObjectShuffled = "{" + - "\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}" -) diff --git a/require/forward_requirements.go b/require/forward_requirements.go deleted file mode 100644 index 1dcb2338c..000000000 --- a/require/forward_requirements.go +++ /dev/null @@ -1,16 +0,0 @@ -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" diff --git a/require/forward_requirements_test.go b/require/forward_requirements_test.go deleted file mode 100644 index 10f2b2b8b..000000000 --- a/require/forward_requirements_test.go +++ /dev/null @@ -1,476 +0,0 @@ -package require - -import ( - "fmt" - "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(someError()) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestErrorWrapper(t *testing.T) { - t.Parallel() - - require := New(t) - require.Error(someError()) - - 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(fmt.Errorf("some error: another error: %w", errSentinel), "some error") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.ErrorContains(fmt.Errorf("some error: another error: %w", errSentinel), "different error") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqualErrorWrapper(t *testing.T) { - t.Parallel() - - require := New(t) - require.EqualError(someError(), "some error: test error") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.EqualError(someError(), "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(simpleJSONObject, simpleJSONObject) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(simpleJSONObject, simpleJSONObjectReversed) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(nestedJSONObject, nestedJSONObjectShuffled) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_Array(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(simpleJSONNested, simpleJSONNestedReversed) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(simpleJSONNested, simpleJSONNestedNotEq) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(fooBarObject, simpleJSONObjectReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(fooBarObject, notJSONString) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(notJSONString, simpleJSONObjectReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(notJSONString, notJSONString) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(simpleJSONArray, simpleJSONArrayReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} diff --git a/require/require.go b/require/require.go deleted file mode 100644 index 6a54e1261..000000000 --- a/require/require.go +++ /dev/null @@ -1,2278 +0,0 @@ -// Code generated with github.com/go-openapi/testify/v2/_codegen; DO NOT EDIT. - -package require - -import ( - assert "github.com/go-openapi/testify/v2/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 ...any) { - 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 ...any) { - 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 any, contains any, msgAndArgs ...any) { - 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 any, contains any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 any, listB any, msgAndArgs ...any) { - 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 any, listB any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 ...any) { - 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 ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, actual any, msg string, args ...any) { - 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 ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 *require.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 ...any) { - 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 *require.CollectT, "error message %s", "formatted") { -// // 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 EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) { - 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 ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.Falsef(t, value, msg, args...) { - return - } - t.FailNow() -} - -// FileEmpty checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func FileEmpty(t TestingT, path string, msgAndArgs ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.FileEmpty(t, path, msgAndArgs...) { - return - } - t.FailNow() -} - -// FileEmptyf checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. -func FileEmptyf(t TestingT, path string, msg string, args ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.FileEmptyf(t, path, 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 ...any) { - 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 ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.FileExistsf(t, path, msg, args...) { - return - } - t.FailNow() -} - -// FileNotEmpty checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func FileNotEmpty(t TestingT, path string, msgAndArgs ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.FileNotEmpty(t, path, msgAndArgs...) { - return - } - t.FailNow() -} - -// FileNotEmptyf checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. -func FileNotEmptyf(t TestingT, path string, msg string, args ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.FileNotEmptyf(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 any, e2 any, msgAndArgs ...any) { - 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 any, e2 any, msgAndArgs ...any) { - 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 any, e2 any, msg string, args ...any) { - 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 any, e2 any, msg string, args ...any) { - 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") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { - 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") -// -// 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 any, msg string, args ...any) { - 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") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { - 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") -// -// 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 any, msg string, args ...any) { - 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"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - 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"}} -// -// 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 ...any) { - 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"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - 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"}} -// -// 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 ...any) { - 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) -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...any) { - 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") -// -// 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 ...any) { - 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) -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - 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") -// -// 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 ...any) { - 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 any, object any, msgAndArgs ...any) { - 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 any, object any, msg string, args ...any) { - 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 any, actual any, delta float64, msgAndArgs ...any) { - 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 any, actual any, delta float64, msgAndArgs ...any) { - 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 any, actual any, delta float64, msg string, args ...any) { - 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 any, actual any, delta float64, msgAndArgs ...any) { - 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 any, actual any, delta float64, msg string, args ...any) { - 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 any, actual any, delta float64, msg string, args ...any) { - 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 any, actual any, epsilon float64, msgAndArgs ...any) { - 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 any, actual any, epsilon float64, msgAndArgs ...any) { - 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 any, actual any, epsilon float64, msg string, args ...any) { - 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 any, actual any, epsilon float64, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, object any, msgAndArgs ...any) { - 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 any, object any, msg string, args ...any) { - 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 any, object any, msgAndArgs ...any) { - 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 any, object any, msg string, args ...any) { - 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 ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.JSONEq(t, expected, actual, msgAndArgs...) { - return - } - t.FailNow() -} - -// JSONEqBytes asserts that two JSON byte slices are equivalent. -// -// require.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) -func JSONEqBytes(t TestingT, expected []byte, actual []byte, msgAndArgs ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.JSONEqBytes(t, expected, actual, msgAndArgs...) { - return - } - t.FailNow() -} - -// JSONEqBytesf asserts that two JSON byte slices are equivalent. -// -// require.JSONEqBytesf(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "error message %s", "formatted") -func JSONEqBytesf(t TestingT, expected []byte, actual []byte, msg string, args ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.JSONEqBytesf(t, expected, actual, msg, args...) { - 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 ...any) { - 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 any, length int, msgAndArgs ...any) { - 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 any, length int, msg string, args ...any) { - 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 any, e2 any, msgAndArgs ...any) { - 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 any, e2 any, msgAndArgs ...any) { - 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 any, e2 any, msg string, args ...any) { - 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 any, e2 any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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() -// if require.NoError(t, err) { -// require.Equal(t, expectedObj, actualObj) -// } -func NoError(t TestingT, err error, msgAndArgs ...any) { - 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() -// if require.NoErrorf(t, err, "error message %s", "formatted") { -// require.Equal(t, expectedObj, actualObj) -// } -func NoErrorf(t TestingT, err error, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 any, contains any, msgAndArgs ...any) { - 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 any, contains any, msg string, args ...any) { - 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 any, listB any, msgAndArgs ...any) { - 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 any, listB any, msg string, args ...any) { - 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]. -// -// if require.NotEmpty(t, obj) { -// require.Equal(t, "two", obj[1]) -// } -func NotEmpty(t TestingT, object any, msgAndArgs ...any) { - 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]. -// -// if require.NotEmptyf(t, obj, "error message %s", "formatted") { -// require.Equal(t, "two", obj[1]) -// } -func NotEmptyf(t TestingT, object any, msg string, args ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 any, object any, msgAndArgs ...any) { - 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 any, object any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 any, str any, msgAndArgs ...any) { - 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 any, str any, msg string, args ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, subset any, msgAndArgs ...any) { - 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 any, subset any, msg string, args ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 any, f assert.PanicTestFunc, msgAndArgs ...any) { - 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 any, f assert.PanicTestFunc, msg string, args ...any) { - 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 ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - 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 any, str any, msgAndArgs ...any) { - 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 any, str any, msg string, args ...any) { - 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 any, actual any, msgAndArgs ...any) { - 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 any, actual any, msg string, args ...any) { - 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 any, subset any, msgAndArgs ...any) { - 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 any, subset any, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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(), 10*time.Second) -func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) { - 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(), 10*time.Second, "error message %s", "formatted") -func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 ...any) { - 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 any, msgAndArgs ...any) { - 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 any, msg string, args ...any) { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if assert.Zerof(t, i, msg, args...) { - return - } - t.FailNow() -} diff --git a/require/require.go.tmpl b/require/require.go.tmpl deleted file mode 100644 index 8b3283685..000000000 --- a/require/require.go.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -{{ replace .Comment "assert." "require."}} -func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { - if h, ok := t.(tHelper); ok { h.Helper() } - if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } - t.FailNow() -} diff --git a/require/require_assertions.go b/require/require_assertions.go new file mode 100644 index 000000000..4d0a027a0 --- /dev/null +++ b/require/require_assertions.go @@ -0,0 +1,1794 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// Condition uses a Comparison to assert a complex condition. +// +// Examples: +// +// success: func() bool { return true } +// failure: func() bool { return false } +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Condition(t T, comp Comparison, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Condition(t, comp, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// Usage: +// +// assertions.Contains(t, "Hello World", "World") +// assertions.Contains(t, ["Hello", "World"], "World") +// assertions.Contains(t, {"Hello": "World"}, "Hello") +// +// Examples: +// +// success: []string{"A","B"}, "A" +// failure: []string{"A","B"}, "C" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Contains(t T, s any, contains any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Contains(t, s, contains, msgAndArgs...) { + 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_dir") +// failure: filepath.Join(testDataPath(),"non_existing_dir") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func DirExists(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.DirExists(t, path, msgAndArgs...) { + 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. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]). +// +// Examples: +// +// success: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +// failure: []int{1, 2, 3}, []int{1, 2, 4} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ElementsMatch(t T, listA any, listB any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ElementsMatch(t, listA, listB, msgAndArgs...) { + 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". +// +// assert.Empty(t, obj) +// +// Examples: +// +// success: "" +// failure: "not empty" +// +// Upon failure, the test [T] is marked as failed and stops execution. +// +// [Zero values]: https://go.dev/ref/spec#The_zero_value +func Empty(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Empty(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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. +// +// Examples: +// +// success: 123, 123 +// failure: 123, 456 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Equal(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.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() +// assert.EqualError(t, err, expectedErrorString) +// +// Examples: +// +// success: ErrTest, "assert.ErrTest general error for testing" +// failure: ErrTest, "wrong error message" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualError(t T, theError error, errString string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualError(t, theError, errString, msgAndArgs...) { + 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 +// } +// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true +// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false +// +// Examples: +// +// success: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2} +// failure: &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualExportedValues(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualExportedValues(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertible to the larger +// type and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +// +// Examples: +// +// success: uint32(123), int32(123) +// failure: uint32(123), int32(456) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualValues(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualValues(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Error asserts that a function returned a non-nil error (ie. an error). +// +// actualObj, err := SomeFunction() +// assert.Error(t, err) +// +// Examples: +// +// success: ErrTest +// failure: nil +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Error(t T, err error, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.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. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +// failure: ErrTest, new(*dummyError) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorAs(t T, err error, target any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorAs(t, err, target, msgAndArgs...) { + 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() +// assert.ErrorContains(t, err, expectedErrorSubString) +// +// Examples: +// +// success: ErrTest, "general error" +// failure: ErrTest, "not in message" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorContains(t T, theError error, contains string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorContains(t, theError, contains, msgAndArgs...) { + 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. +// +// Examples: +// +// success: fmt.Errorf("wrap: %w", io.EOF), io.EOF +// failure: ErrTest, io.EOF +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorIs(t T, err error, target error, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorIs(t, err, target, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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) +// +// Examples: +// +// success: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Eventually(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.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 +// }() +// 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") +// +// Examples: +// +// success: func(c *CollectT) { True(c,true) }, 100*time.Millisecond, 20*time.Millisecond +// failure: func(c *CollectT) { False(c,true) }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EventuallyWithT(t T, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +// +// Examples: +// +// success: int32(123), int32(123) +// failure: int32(123), int64(123) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Exactly(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Exactly(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Fail reports a failure through. +// +// Example: +// +// failure: "failed" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Fail(t T, failureMessage string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + _ = assertions.Fail(t, failureMessage, msgAndArgs...) + + t.FailNow() +} + +// FailNow fails test. +// +// Example: +// +// failure: "failed" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FailNow(t T, failureMessage string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + _ = assertions.FailNow(t, failureMessage, msgAndArgs...) + + t.FailNow() +} + +// False asserts that the specified value is false. +// +// Usage: +// +// assertions.False(t, myBool) +// +// Examples: +// +// success: 1 == 0 +// failure: 1 == 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func False(t T, value bool, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.False(t, value, msgAndArgs...) { + return + } + + t.FailNow() +} + +// FileEmpty checks whether a file exists in the given path and is empty. +// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"empty_file") +// failure: filepath.Join(testDataPath(),"existing_file") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileEmpty(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileEmpty(t, path, msgAndArgs...) { + 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"non_existing_file") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileExists(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileExists(t, path, msgAndArgs...) { + return + } + + t.FailNow() +} + +// FileNotEmpty checks whether a file exists in the given path and is not empty. +// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"existing_file") +// failure: filepath.Join(testDataPath(),"empty_file") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileNotEmpty(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileNotEmpty(t, path, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Greater asserts that the first element is strictly greater than the second. +// +// Usage: +// +// assertions.Greater(t, 2, 1) +// assertions.Greater(t, float64(2), float64(1)) +// assertions.Greater(t, "b", "a") +// +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Greater(t T, e1 any, e2 any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Greater(t, e1, e2, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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") +// +// Examples: +// +// success: 2, 1 +// failure: 1, 2 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func GreaterOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.GreaterOrEqual(t, e1, e2, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPBodyContains(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!" +// failure: httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPBodyNotContains(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpError, "GET", "/", nil +// failure: httpOK, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPError(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPError(t, handler, method, url, values, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpRedirect, "GET", "/", nil +// failure: httpError, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPRedirect(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpOK, "GET", "/", nil, http.StatusOK +// failure: httpError, "GET", "/", nil, http.StatusOK +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPStatusCode(t T, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: httpOK, "GET", "/", nil +// failure: httpError, "GET", "/", nil +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPSuccess(t T, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// +// Examples: +// +// success: ptr(dummyInterface), new(testing.T) +// failure: (*error)(nil), new(testing.T) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Implements(t T, interfaceObject any, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Implements(t, interfaceObject, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// +// Examples: +// +// success: 1.0, 1.01, 0.02 +// failure: 1.0, 1.1, 0.05 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDelta(t T, expected any, actual any, delta float64, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.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. +// +// Examples: +// +// success: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02 +// failure: map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDeltaMapValues(t T, expected any, actual any, delta float64, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { + return + } + + t.FailNow() +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +// +// Examples: +// +// success: []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02 +// failure: []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDeltaSlice(t T, expected any, actual any, delta float64, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { + return + } + + t.FailNow() +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon. +// +// Examples: +// +// success: 100.0, 101.0, 0.02 +// failure: 100.0, 110.0, 0.05 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InEpsilon(t T, expected any, actual any, epsilon float64, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + return + } + + t.FailNow() +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +// +// Examples: +// +// success: []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02 +// failure: []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InEpsilonSlice(t T, expected any, actual any, epsilon float64, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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"}) +// +// Examples: +// +// success: []int{3, 2, 1} +// failure: []int{1, 2, 3} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsDecreasing(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsDecreasing(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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"}) +// +// Examples: +// +// success: []int{1, 2, 3} +// failure: []int{1, 1, 2} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsIncreasing(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsIncreasing(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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"}) +// +// Examples: +// +// success: []int{1, 1, 2} +// failure: []int{2, 1, 1} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNonDecreasing(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNonDecreasing(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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"}) +// +// Examples: +// +// success: []int{2, 1, 1} +// failure: []int{1, 2, 3} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNonIncreasing(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// IsNotType asserts that the specified objects are not of the same type. +// +// assert.IsNotType(t, &NotMyStruct{}, &MyStruct{}) +// +// Examples: +// +// success: int32(123), int64(456) +// failure: 123, 456 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNotType(t T, theType any, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNotType(t, theType, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +// +// assert.IsType(t, &MyStruct{}, &MyStruct{}) +// +// Examples: +// +// success: 123, 456 +// failure: int32(123), int64(456) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsType(t T, expectedType any, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsType(t, expectedType, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// +// Examples: +// +// success: `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}` +// failure: `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]` +// +// Upon failure, the test [T] is marked as failed and stops execution. +func JSONEq(t T, expected string, actual string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// JSONEqBytes asserts that two JSON byte slices are equivalent. +// +// assert.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) +// +// Examples: +// +// success: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`) +// failure: []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func JSONEqBytes(t T, expected []byte, actual []byte, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.JSONEqBytes(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Len asserts that the specified object has specific length. +// +// Len also fails if the object has a type that len() does not accept. +// +// The asserted object can be a string, a slice, a map, an array or a channel. +// +// See also [reflect.Len]. +// +// Usage: +// +// assertions.Len(t, mySlice, 3) +// assertions.Len(t, myString, 4) +// assertions.Len(t, myMap, 5) +// +// Examples: +// +// success: []string{"A","B"}, 2 +// failure: []string{"A","B"}, 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Len(t T, object any, length int, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Len(t, object, length, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Less asserts that the first element is strictly less than the second. +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Less(t T, e1 any, e2 any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Less(t, e1, e2, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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") +// +// Examples: +// +// success: 1, 2 +// failure: 2, 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func LessOrEqual(t T, e1 any, e2 any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.LessOrEqual(t, e1, e2, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Negative asserts that the specified element is strictly negative. +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +// +// Examples: +// +// success: -1 +// failure: 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Negative(t T, e any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Negative(t, e, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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) +// +// Examples: +// +// success: func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond +// failure: func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Never(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Never(t, condition, waitFor, tick, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +// +// Examples: +// +// success: nil +// failure: "not nil" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Nil(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Nil(t, object, msgAndArgs...) { + 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. +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_dir") +// failure: filepath.Join(testDataPath(),"existing_dir") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoDirExists(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoDirExists(t, path, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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) +// } +// +// Examples: +// +// success: nil +// failure: ErrTest +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoError(t T, err error, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoError(t, err, msgAndArgs...) { + 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. +// +// Examples: +// +// success: filepath.Join(testDataPath(),"non_existing_file") +// failure: filepath.Join(testDataPath(),"existing_file") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoFileExists(t T, path string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoFileExists(t, path, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// Usage: +// +// assertions.NotContains(t, "Hello World", "Earth") +// assertions.NotContains(t, ["Hello", "World"], "Earth") +// assertions.NotContains(t, {"Hello": "World"}, "Earth") +// +// Examples: +// +// success: []string{"A","B"}, "C" +// failure: []string{"A","B"}, "B" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotContains(t T, s any, contains any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotContains(t, s, contains, msgAndArgs...) { + 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. +// +// 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. +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2, 4} +// failure: []int{1, 3, 2, 3}, []int{1, 3, 3, 2} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotElementsMatch(t T, listA any, listB any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotElementsMatch(t, listA, listB, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotEmpty asserts that the specified object is NOT [Empty]. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +// +// Examples: +// +// success: "not empty" +// failure: "" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEmpty(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEmpty(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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). +// +// Examples: +// +// success: 123, 456 +// failure: 123, 123 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEqual(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEqual(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type. +// +// assert.NotEqualValues(t, obj1, obj2) +// +// Examples: +// +// success: uint32(123), int32(456) +// failure: uint32(123), int32(123) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEqualValues(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEqualValues(t, expected, actual, msgAndArgs...) { + 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. +// +// Examples: +// +// success: ErrTest, new(*dummyError) +// failure: fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotErrorAs(t T, err error, target any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotErrorAs(t, err, target, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotErrorIs asserts that none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +// +// Examples: +// +// success: ErrTest, io.EOF +// failure: fmt.Errorf("wrap: %w", io.EOF), io.EOF +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotErrorIs(t T, err error, target error, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotImplements asserts that an object does not implement the specified interface. +// +// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) +// +// Examples: +// +// success: (*error)(nil), new(testing.T) +// failure: ptr(dummyInterface), new(testing.T) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotImplements(t T, interfaceObject any, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotImplements(t, interfaceObject, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +// +// Examples: +// +// success: "not nil" +// failure: nil +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotNil(t T, object any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotNil(t, object, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +// +// Examples: +// +// success: func() { } +// failure: func() { panic("panicking") } +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotPanics(t T, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotPanics(t, f, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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") +// +// Examples: +// +// success: "^start", "not starting" +// failure: "^start", "starting" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotRegexp(t T, rx any, str any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotRegexp(t, rx, str, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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. +// +// Examples: +// +// success: &staticVar, ptr("static string") +// failure: &staticVar, staticVarPtr +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotSame(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotSame(t, expected, actual, msgAndArgs...) { + 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. +// +// 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{4, 5} +// failure: []int{1, 2, 3}, []int{1, 2} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotSubset(t T, list any, subset any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotSubset(t, list, subset, msgAndArgs...) { + return + } + + t.FailNow() +} + +// NotZero asserts that i is not the zero value for its type. +// +// Examples: +// +// success: 1 +// failure: 0 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotZero(t T, i any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotZero(t, i, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +// +// Examples: +// +// success: func() { panic("panicking") } +// failure: func() { } +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Panics(t T, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.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. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// +// Examples: +// +// success: ErrTest.Error(), func() { panic(ErrTest) } +// failure: ErrTest.Error(), func() { } +// +// Upon failure, the test [T] is marked as failed and stops execution. +func PanicsWithError(t T, errString string, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.PanicsWithError(t, errString, f, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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() }) +// +// Examples: +// +// success: "panicking", func() { panic("panicking") } +// failure: "panicking", func() { } +// +// Upon failure, the test [T] is marked as failed and stops execution. +func PanicsWithValue(t T, expected any, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.PanicsWithValue(t, expected, f, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Positive asserts that the specified element is strictly positive. +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +// +// Examples: +// +// success: 1 +// failure: -1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Positive(t T, e any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Positive(t, e, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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") +// +// Examples: +// +// success: "^start", "starting" +// failure: "^start", "not starting" +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Regexp(t T, rx any, str any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Regexp(t, rx, str, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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. +// +// Examples: +// +// success: &staticVar, staticVarPtr +// failure: &staticVar, ptr("static string") +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Same(t T, expected any, actual any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Same(t, expected, actual, msgAndArgs...) { + 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. +// +// 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"]) +// +// Examples: +// +// success: []int{1, 2, 3}, []int{1, 2} +// failure: []int{1, 2, 3}, []int{4, 5} +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Subset(t T, list any, subset any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Subset(t, list, subset, msgAndArgs...) { + return + } + + t.FailNow() +} + +// True asserts that the specified value is true. +// +// Usage: +// +// assertions.True(t, myBool) +// +// Examples: +// +// success: 1 == 1 +// failure: 1 == 0 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func True(t T, value bool, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.True(t, value, msgAndArgs...) { + return + } + + t.FailNow() +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), 10*time.Second) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second +// failure: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second +// +// Upon failure, the test [T] is marked as failed and stops execution. +func WithinDuration(t T, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + return + } + + t.FailNow() +} + +// 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)) +// +// Examples: +// +// success: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +// failure: time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC) +// +// Upon failure, the test [T] is marked as failed and stops execution. +func WithinRange(t T, actual time.Time, start time.Time, end time.Time, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.WithinRange(t, actual, start, end, msgAndArgs...) { + return + } + + t.FailNow() +} + +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// Usage: +// +// 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 +// ` +// assertions.YAMLEq(t, expected, actual) +// +// Example: +// +// panic: "key: value", "key: value" +// should panic without the yaml feature enabled +// +// Upon failure, the test [T] is marked as failed and stops execution. +func YAMLEq(t T, expected string, actual string, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.YAMLEq(t, expected, actual, msgAndArgs...) { + return + } + + t.FailNow() +} + +// Zero asserts that i is the zero value for its type. +// +// Examples: +// +// success: 0 +// failure: 1 +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Zero(t T, i any, msgAndArgs ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Zero(t, i, msgAndArgs...) { + return + } + + t.FailNow() +} diff --git a/require/require_assertions_test.go b/require/require_assertions_test.go new file mode 100644 index 000000000..97b7eb52c --- /dev/null +++ b/require/require_assertions_test.go @@ -0,0 +1,1648 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestCondition(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Condition(t, func() bool { return true }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Condition(mock, func() bool { return false }) + // require functions don't return a value + if !mock.failed { + t.Error("Condition should call FailNow()") + } + }) +} + +func TestContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Contains(t, []string{"A", "B"}, "A") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Contains(mock, []string{"A", "B"}, "C") + // require functions don't return a value + if !mock.failed { + t.Error("Contains should call FailNow()") + } + }) +} + +func TestDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + DirExists(t, filepath.Join(testDataPath(), "existing_dir")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + DirExists(mock, filepath.Join(testDataPath(), "non_existing_dir")) + // require functions don't return a value + if !mock.failed { + t.Error("DirExists should call FailNow()") + } + }) +} + +func TestElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ElementsMatch(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ElementsMatch(mock, []int{1, 2, 3}, []int{1, 2, 4}) + // require functions don't return a value + if !mock.failed { + t.Error("ElementsMatch should call FailNow()") + } + }) +} + +func TestEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Empty(t, "") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Empty(mock, "not empty") + // require functions don't return a value + if !mock.failed { + t.Error("Empty should call FailNow()") + } + }) +} + +func TestEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Equal(t, 123, 123) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Equal(mock, 123, 456) + // require functions don't return a value + if !mock.failed { + t.Error("Equal should call FailNow()") + } + }) +} + +func TestEqualError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualError(t, ErrTest, "assert.ErrTest general error for testing") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualError(mock, ErrTest, "wrong error message") + // require functions don't return a value + if !mock.failed { + t.Error("EqualError should call FailNow()") + } + }) +} + +func TestEqualExportedValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualExportedValues(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualExportedValues(mock, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}) + // require functions don't return a value + if !mock.failed { + t.Error("EqualExportedValues should call FailNow()") + } + }) +} + +func TestEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualValues(t, uint32(123), int32(123)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualValues(mock, uint32(123), int32(456)) + // require functions don't return a value + if !mock.failed { + t.Error("EqualValues should call FailNow()") + } + }) +} + +func TestError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Error(t, ErrTest) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Error(mock, nil) + // require functions don't return a value + if !mock.failed { + t.Error("Error should call FailNow()") + } + }) +} + +func TestErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorAs(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorAs(mock, ErrTest, new(*dummyError)) + // require functions don't return a value + if !mock.failed { + t.Error("ErrorAs should call FailNow()") + } + }) +} + +func TestErrorContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorContains(t, ErrTest, "general error") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorContains(mock, ErrTest, "not in message") + // require functions don't return a value + if !mock.failed { + t.Error("ErrorContains should call FailNow()") + } + }) +} + +func TestErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorIs(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorIs(mock, ErrTest, io.EOF) + // require functions don't return a value + if !mock.failed { + t.Error("ErrorIs should call FailNow()") + } + }) +} + +func TestEventually(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Eventually(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Eventually(mock, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("Eventually should call FailNow()") + } + }) +} + +func TestEventuallyWithT(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EventuallyWithT(t, func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EventuallyWithT(mock, func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("EventuallyWithT should call FailNow()") + } + }) +} + +func TestExactly(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Exactly(t, int32(123), int32(123)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Exactly(mock, int32(123), int64(123)) + // require functions don't return a value + if !mock.failed { + t.Error("Exactly should call FailNow()") + } + }) +} + +func TestFail(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Fail(mock, "failed") + // require functions don't return a value + if !mock.failed { + t.Error("Fail should call FailNow()") + } + }) +} + +func TestFailNow(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FailNow(mock, "failed") + // require functions don't return a value + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestFalse(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + False(t, 1 == 0) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + False(mock, 1 == 1) + // require functions don't return a value + if !mock.failed { + t.Error("False should call FailNow()") + } + }) +} + +func TestFileEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileEmpty(t, filepath.Join(testDataPath(), "empty_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileEmpty(mock, filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileEmpty should call FailNow()") + } + }) +} + +func TestFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileExists(t, filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileExists(mock, filepath.Join(testDataPath(), "non_existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileExists should call FailNow()") + } + }) +} + +func TestFileNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileNotEmpty(t, filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileNotEmpty(mock, filepath.Join(testDataPath(), "empty_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileNotEmpty should call FailNow()") + } + }) +} + +func TestGreater(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Greater(t, 2, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Greater(mock, 1, 2) + // require functions don't return a value + if !mock.failed { + t.Error("Greater should call FailNow()") + } + }) +} + +func TestGreaterOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + GreaterOrEqual(t, 2, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + GreaterOrEqual(mock, 1, 2) + // require functions don't return a value + if !mock.failed { + t.Error("GreaterOrEqual should call FailNow()") + } + }) +} + +func TestHTTPBodyContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPBodyContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPBodyContains(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyContains should call FailNow()") + } + }) +} + +func TestHTTPBodyNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPBodyNotContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPBodyNotContains(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyNotContains should call FailNow()") + } + }) +} + +func TestHTTPError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPError(t, httpError, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPError(mock, httpOK, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPError should call FailNow()") + } + }) +} + +func TestHTTPRedirect(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPRedirect(t, httpRedirect, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPRedirect(mock, httpError, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPRedirect should call FailNow()") + } + }) +} + +func TestHTTPStatusCode(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPStatusCode(t, httpOK, "GET", "/", nil, http.StatusOK) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPStatusCode(mock, httpError, "GET", "/", nil, http.StatusOK) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPStatusCode should call FailNow()") + } + }) +} + +func TestHTTPSuccess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPSuccess(t, httpOK, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPSuccess(mock, httpError, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPSuccess should call FailNow()") + } + }) +} + +func TestImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Implements(t, ptr(dummyInterface), new(testing.T)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Implements(mock, (*error)(nil), new(testing.T)) + // require functions don't return a value + if !mock.failed { + t.Error("Implements should call FailNow()") + } + }) +} + +func TestInDelta(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDelta(t, 1.0, 1.01, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDelta(mock, 1.0, 1.1, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDelta should call FailNow()") + } + }) +} + +func TestInDeltaMapValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDeltaMapValues(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDeltaMapValues(mock, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaMapValues should call FailNow()") + } + }) +} + +func TestInDeltaSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDeltaSlice(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDeltaSlice(mock, []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaSlice should call FailNow()") + } + }) +} + +func TestInEpsilon(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InEpsilon(t, 100.0, 101.0, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InEpsilon(mock, 100.0, 110.0, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilon should call FailNow()") + } + }) +} + +func TestInEpsilonSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InEpsilonSlice(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InEpsilonSlice(mock, []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilonSlice should call FailNow()") + } + }) +} + +func TestIsDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsDecreasing(t, []int{3, 2, 1}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsDecreasing(mock, []int{1, 2, 3}) + // require functions don't return a value + if !mock.failed { + t.Error("IsDecreasing should call FailNow()") + } + }) +} + +func TestIsIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsIncreasing(t, []int{1, 2, 3}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsIncreasing(mock, []int{1, 1, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("IsIncreasing should call FailNow()") + } + }) +} + +func TestIsNonDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNonDecreasing(t, []int{1, 1, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNonDecreasing(mock, []int{2, 1, 1}) + // require functions don't return a value + if !mock.failed { + t.Error("IsNonDecreasing should call FailNow()") + } + }) +} + +func TestIsNonIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNonIncreasing(t, []int{2, 1, 1}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNonIncreasing(mock, []int{1, 2, 3}) + // require functions don't return a value + if !mock.failed { + t.Error("IsNonIncreasing should call FailNow()") + } + }) +} + +func TestIsNotType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNotType(t, int32(123), int64(456)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNotType(mock, 123, 456) + // require functions don't return a value + if !mock.failed { + t.Error("IsNotType should call FailNow()") + } + }) +} + +func TestIsType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsType(t, 123, 456) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsType(mock, int32(123), int64(456)) + // require functions don't return a value + if !mock.failed { + t.Error("IsType should call FailNow()") + } + }) +} + +func TestJSONEq(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + JSONEq(mock, `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`) + // require functions don't return a value + if !mock.failed { + t.Error("JSONEq should call FailNow()") + } + }) +} + +func TestJSONEqBytes(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + JSONEqBytes(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`)) + // require functions don't return a value + if !mock.failed { + t.Error("JSONEqBytes should call FailNow()") + } + }) +} + +func TestLen(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Len(t, []string{"A", "B"}, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Len(mock, []string{"A", "B"}, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Len should call FailNow()") + } + }) +} + +func TestLess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Less(t, 1, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Less(mock, 2, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Less should call FailNow()") + } + }) +} + +func TestLessOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + LessOrEqual(t, 1, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + LessOrEqual(mock, 2, 1) + // require functions don't return a value + if !mock.failed { + t.Error("LessOrEqual should call FailNow()") + } + }) +} + +func TestNegative(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Negative(t, -1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Negative(mock, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Negative should call FailNow()") + } + }) +} + +func TestNever(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Never(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Never(mock, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("Never should call FailNow()") + } + }) +} + +func TestNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Nil(t, nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Nil(mock, "not nil") + // require functions don't return a value + if !mock.failed { + t.Error("Nil should call FailNow()") + } + }) +} + +func TestNoDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoDirExists(t, filepath.Join(testDataPath(), "non_existing_dir")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoDirExists(mock, filepath.Join(testDataPath(), "existing_dir")) + // require functions don't return a value + if !mock.failed { + t.Error("NoDirExists should call FailNow()") + } + }) +} + +func TestNoError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoError(t, nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoError(mock, ErrTest) + // require functions don't return a value + if !mock.failed { + t.Error("NoError should call FailNow()") + } + }) +} + +func TestNoFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoFileExists(t, filepath.Join(testDataPath(), "non_existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoFileExists(mock, filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("NoFileExists should call FailNow()") + } + }) +} + +func TestNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotContains(t, []string{"A", "B"}, "C") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotContains(mock, []string{"A", "B"}, "B") + // require functions don't return a value + if !mock.failed { + t.Error("NotContains should call FailNow()") + } + }) +} + +func TestNotElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotElementsMatch(t, []int{1, 2, 3}, []int{1, 2, 4}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotElementsMatch(mock, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("NotElementsMatch should call FailNow()") + } + }) +} + +func TestNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEmpty(t, "not empty") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEmpty(mock, "") + // require functions don't return a value + if !mock.failed { + t.Error("NotEmpty should call FailNow()") + } + }) +} + +func TestNotEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEqual(t, 123, 456) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEqual(mock, 123, 123) + // require functions don't return a value + if !mock.failed { + t.Error("NotEqual should call FailNow()") + } + }) +} + +func TestNotEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEqualValues(t, uint32(123), int32(456)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEqualValues(mock, uint32(123), int32(123)) + // require functions don't return a value + if !mock.failed { + t.Error("NotEqualValues should call FailNow()") + } + }) +} + +func TestNotErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotErrorAs(t, ErrTest, new(*dummyError)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotErrorAs(mock, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorAs should call FailNow()") + } + }) +} + +func TestNotErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotErrorIs(t, ErrTest, io.EOF) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotErrorIs(mock, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorIs should call FailNow()") + } + }) +} + +func TestNotImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotImplements(t, (*error)(nil), new(testing.T)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotImplements(mock, ptr(dummyInterface), new(testing.T)) + // require functions don't return a value + if !mock.failed { + t.Error("NotImplements should call FailNow()") + } + }) +} + +func TestNotNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotNil(t, "not nil") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotNil(mock, nil) + // require functions don't return a value + if !mock.failed { + t.Error("NotNil should call FailNow()") + } + }) +} + +func TestNotPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotPanics(t, func() {}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotPanics(mock, func() { panic("panicking") }) + // require functions don't return a value + if !mock.failed { + t.Error("NotPanics should call FailNow()") + } + }) +} + +func TestNotRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotRegexp(t, "^start", "not starting") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotRegexp(mock, "^start", "starting") + // require functions don't return a value + if !mock.failed { + t.Error("NotRegexp should call FailNow()") + } + }) +} + +func TestNotSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotSame(t, &staticVar, ptr("static string")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotSame(mock, &staticVar, staticVarPtr) + // require functions don't return a value + if !mock.failed { + t.Error("NotSame should call FailNow()") + } + }) +} + +func TestNotSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotSubset(t, []int{1, 2, 3}, []int{4, 5}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotSubset(mock, []int{1, 2, 3}, []int{1, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("NotSubset should call FailNow()") + } + }) +} + +func TestNotZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotZero(t, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotZero(mock, 0) + // require functions don't return a value + if !mock.failed { + t.Error("NotZero should call FailNow()") + } + }) +} + +func TestPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Panics(t, func() { panic("panicking") }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Panics(mock, func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("Panics should call FailNow()") + } + }) +} + +func TestPanicsWithError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + PanicsWithError(t, ErrTest.Error(), func() { panic(ErrTest) }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + PanicsWithError(mock, ErrTest.Error(), func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithError should call FailNow()") + } + }) +} + +func TestPanicsWithValue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + PanicsWithValue(t, "panicking", func() { panic("panicking") }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + PanicsWithValue(mock, "panicking", func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithValue should call FailNow()") + } + }) +} + +func TestPositive(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Positive(t, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Positive(mock, -1) + // require functions don't return a value + if !mock.failed { + t.Error("Positive should call FailNow()") + } + }) +} + +func TestRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Regexp(t, "^start", "starting") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Regexp(mock, "^start", "not starting") + // require functions don't return a value + if !mock.failed { + t.Error("Regexp should call FailNow()") + } + }) +} + +func TestSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Same(t, &staticVar, staticVarPtr) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Same(mock, &staticVar, ptr("static string")) + // require functions don't return a value + if !mock.failed { + t.Error("Same should call FailNow()") + } + }) +} + +func TestSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Subset(t, []int{1, 2, 3}, []int{1, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Subset(mock, []int{1, 2, 3}, []int{4, 5}) + // require functions don't return a value + if !mock.failed { + t.Error("Subset should call FailNow()") + } + }) +} + +func TestTrue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + True(t, 1 == 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + True(mock, 1 == 0) + // require functions don't return a value + if !mock.failed { + t.Error("True should call FailNow()") + } + }) +} + +func TestWithinDuration(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + WithinDuration(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + WithinDuration(mock, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second) + // require functions don't return a value + if !mock.failed { + t.Error("WithinDuration should call FailNow()") + } + }) +} + +func TestWithinRange(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + WithinRange(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + WithinRange(mock, time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + // require functions don't return a value + if !mock.failed { + t.Error("WithinRange should call FailNow()") + } + }) +} + +func TestYAMLEq(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panics(t, func() { + YAMLEq(t, "key: value", "key: value") + }, "should panic without the yaml feature enabled") + }) +} + +func TestZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Zero(t, 0) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Zero(mock, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Zero should call FailNow()") + } + }) +} + +// mockT is a mock testing.T for assertion tests +type mockT struct { + failed bool +} + +func (m *mockT) Helper() {} + +func (m *mockT) Errorf(format string, args ...any) { + m.failed = true +} + +type mockFailNowT struct { + failed bool +} + +// Helper is like [testing.T.Helper] but does nothing. +func (mockFailNowT) Helper() {} + +func (m *mockFailNowT) Errorf(format string, args ...any) { + _ = format + _ = args +} + +func (m *mockFailNowT) FailNow() { + m.failed = true +} + +func testDataPath() string { + return filepath.Join("..", "internal", "assertions", "testdata") +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/require/require_examples_test.go b/require/require_examples_test.go new file mode 100644 index 000000000..cd9ae59e6 --- /dev/null +++ b/require/require_examples_test.go @@ -0,0 +1,688 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require_test + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" + + "github.com/go-openapi/testify/v2/require" +) + +func ExampleCondition() { + t := new(testing.T) + require.Condition(t, func() bool { return true }) + fmt.Println("passed") + + // Output: passed +} + +func ExampleContains() { + t := new(testing.T) + require.Contains(t, []string{"A", "B"}, "A") + fmt.Println("passed") + + // Output: passed +} + +func ExampleDirExists() { + t := new(testing.T) + require.DirExists(t, filepath.Join(testDataPath(), "existing_dir")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleElementsMatch() { + t := new(testing.T) + require.ElementsMatch(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleEmpty() { + t := new(testing.T) + require.Empty(t, "") + fmt.Println("passed") + + // Output: passed +} + +func ExampleEqual() { + t := new(testing.T) + require.Equal(t, 123, 123) + fmt.Println("passed") + + // Output: passed +} + +func ExampleEqualError() { + t := new(testing.T) + require.EqualError(t, require.ErrTest, "assert.ErrTest general error for testing") + fmt.Println("passed") + + // Output: passed +} + +func ExampleEqualExportedValues() { + t := new(testing.T) + require.EqualExportedValues(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleEqualValues() { + t := new(testing.T) + require.EqualValues(t, uint32(123), int32(123)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleError() { + t := new(testing.T) + require.Error(t, require.ErrTest) + fmt.Println("passed") + + // Output: passed +} + +func ExampleErrorAs() { + t := new(testing.T) + require.ErrorAs(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleErrorContains() { + t := new(testing.T) + require.ErrorContains(t, require.ErrTest, "general error") + fmt.Println("passed") + + // Output: passed +} + +func ExampleErrorIs() { + t := new(testing.T) + require.ErrorIs(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF) + fmt.Println("passed") + + // Output: passed +} + +func ExampleEventually() { + t := new(testing.T) + require.Eventually(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Println("passed") + + // Output: passed +} + +func ExampleEventuallyWithT() { + t := new(testing.T) + require.EventuallyWithT(t, func(c *require.CollectT) { require.True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Println("passed") + + // Output: passed +} + +func ExampleExactly() { + t := new(testing.T) + require.Exactly(t, int32(123), int32(123)) + fmt.Println("passed") + + // Output: passed +} + +// func ExampleFail() { +// no success example available. Please add some examples to produce a testable example. +// } + +// func ExampleFailNow() { +// no success example available. Please add some examples to produce a testable example. +// } + +func ExampleFalse() { + t := new(testing.T) + require.False(t, 1 == 0) + fmt.Println("passed") + + // Output: passed +} + +func ExampleFileEmpty() { + t := new(testing.T) + require.FileEmpty(t, filepath.Join(testDataPath(), "empty_file")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleFileExists() { + t := new(testing.T) + require.FileExists(t, filepath.Join(testDataPath(), "existing_file")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleFileNotEmpty() { + t := new(testing.T) + require.FileNotEmpty(t, filepath.Join(testDataPath(), "existing_file")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleGreater() { + t := new(testing.T) + require.Greater(t, 2, 1) + fmt.Println("passed") + + // Output: passed +} + +func ExampleGreaterOrEqual() { + t := new(testing.T) + require.GreaterOrEqual(t, 2, 1) + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPBodyContains() { + t := new(testing.T) + require.HTTPBodyContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPBodyNotContains() { + t := new(testing.T) + require.HTTPBodyNotContains(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPError() { + t := new(testing.T) + require.HTTPError(t, httpError, "GET", "/", nil) + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPRedirect() { + t := new(testing.T) + require.HTTPRedirect(t, httpRedirect, "GET", "/", nil) + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPStatusCode() { + t := new(testing.T) + require.HTTPStatusCode(t, httpOK, "GET", "/", nil, http.StatusOK) + fmt.Println("passed") + + // Output: passed +} + +func ExampleHTTPSuccess() { + t := new(testing.T) + require.HTTPSuccess(t, httpOK, "GET", "/", nil) + fmt.Println("passed") + + // Output: passed +} + +func ExampleImplements() { + t := new(testing.T) + require.Implements(t, ptr(dummyInterface), new(testing.T)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleInDelta() { + t := new(testing.T) + require.InDelta(t, 1.0, 1.01, 0.02) + fmt.Println("passed") + + // Output: passed +} + +func ExampleInDeltaMapValues() { + t := new(testing.T) + require.InDeltaMapValues(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + fmt.Println("passed") + + // Output: passed +} + +func ExampleInDeltaSlice() { + t := new(testing.T) + require.InDeltaSlice(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + fmt.Println("passed") + + // Output: passed +} + +func ExampleInEpsilon() { + t := new(testing.T) + require.InEpsilon(t, 100.0, 101.0, 0.02) + fmt.Println("passed") + + // Output: passed +} + +func ExampleInEpsilonSlice() { + t := new(testing.T) + require.InEpsilonSlice(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsDecreasing() { + t := new(testing.T) + require.IsDecreasing(t, []int{3, 2, 1}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsIncreasing() { + t := new(testing.T) + require.IsIncreasing(t, []int{1, 2, 3}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsNonDecreasing() { + t := new(testing.T) + require.IsNonDecreasing(t, []int{1, 1, 2}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsNonIncreasing() { + t := new(testing.T) + require.IsNonIncreasing(t, []int{2, 1, 1}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsNotType() { + t := new(testing.T) + require.IsNotType(t, int32(123), int64(456)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleIsType() { + t := new(testing.T) + require.IsType(t, 123, 456) + fmt.Println("passed") + + // Output: passed +} + +func ExampleJSONEq() { + t := new(testing.T) + require.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + fmt.Println("passed") + + // Output: passed +} + +func ExampleJSONEqBytes() { + t := new(testing.T) + require.JSONEqBytes(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleLen() { + t := new(testing.T) + require.Len(t, []string{"A", "B"}, 2) + fmt.Println("passed") + + // Output: passed +} + +func ExampleLess() { + t := new(testing.T) + require.Less(t, 1, 2) + fmt.Println("passed") + + // Output: passed +} + +func ExampleLessOrEqual() { + t := new(testing.T) + require.LessOrEqual(t, 1, 2) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNegative() { + t := new(testing.T) + require.Negative(t, -1) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNever() { + t := new(testing.T) + require.Never(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNil() { + t := new(testing.T) + require.Nil(t, nil) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNoDirExists() { + t := new(testing.T) + require.NoDirExists(t, filepath.Join(testDataPath(), "non_existing_dir")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNoError() { + t := new(testing.T) + require.NoError(t, nil) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNoFileExists() { + t := new(testing.T) + require.NoFileExists(t, filepath.Join(testDataPath(), "non_existing_file")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotContains() { + t := new(testing.T) + require.NotContains(t, []string{"A", "B"}, "C") + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotElementsMatch() { + t := new(testing.T) + require.NotElementsMatch(t, []int{1, 2, 3}, []int{1, 2, 4}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotEmpty() { + t := new(testing.T) + require.NotEmpty(t, "not empty") + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotEqual() { + t := new(testing.T) + require.NotEqual(t, 123, 456) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotEqualValues() { + t := new(testing.T) + require.NotEqualValues(t, uint32(123), int32(456)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotErrorAs() { + t := new(testing.T) + require.NotErrorAs(t, require.ErrTest, new(*dummyError)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotErrorIs() { + t := new(testing.T) + require.NotErrorIs(t, require.ErrTest, io.EOF) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotImplements() { + t := new(testing.T) + require.NotImplements(t, (*error)(nil), new(testing.T)) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotNil() { + t := new(testing.T) + require.NotNil(t, "not nil") + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotPanics() { + t := new(testing.T) + require.NotPanics(t, func() {}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotRegexp() { + t := new(testing.T) + require.NotRegexp(t, "^start", "not starting") + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotSame() { + t := new(testing.T) + require.NotSame(t, &staticVar, ptr("static string")) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotSubset() { + t := new(testing.T) + require.NotSubset(t, []int{1, 2, 3}, []int{4, 5}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleNotZero() { + t := new(testing.T) + require.NotZero(t, 1) + fmt.Println("passed") + + // Output: passed +} + +func ExamplePanics() { + t := new(testing.T) + require.Panics(t, func() { panic("panicking") }) + fmt.Println("passed") + + // Output: passed +} + +func ExamplePanicsWithError() { + t := new(testing.T) + require.PanicsWithError(t, require.ErrTest.Error(), func() { panic(require.ErrTest) }) + fmt.Println("passed") + + // Output: passed +} + +func ExamplePanicsWithValue() { + t := new(testing.T) + require.PanicsWithValue(t, "panicking", func() { panic("panicking") }) + fmt.Println("passed") + + // Output: passed +} + +func ExamplePositive() { + t := new(testing.T) + require.Positive(t, 1) + fmt.Println("passed") + + // Output: passed +} + +func ExampleRegexp() { + t := new(testing.T) + require.Regexp(t, "^start", "starting") + fmt.Println("passed") + + // Output: passed +} + +func ExampleSame() { + t := new(testing.T) + require.Same(t, &staticVar, staticVarPtr) + fmt.Println("passed") + + // Output: passed +} + +func ExampleSubset() { + t := new(testing.T) + require.Subset(t, []int{1, 2, 3}, []int{1, 2}) + fmt.Println("passed") + + // Output: passed +} + +func ExampleTrue() { + t := new(testing.T) + require.True(t, 1 == 1) + fmt.Println("passed") + + // Output: passed +} + +func ExampleWithinDuration() { + t := new(testing.T) + require.WithinDuration(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + fmt.Println("passed") + + // Output: passed +} + +func ExampleWithinRange() { + t := new(testing.T) + require.WithinRange(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + fmt.Println("passed") + + // Output: passed +} + +// func ExampleYAMLEq() { +// no success example available. Please add some examples to produce a testable example. +// } + +func ExampleZero() { + t := new(testing.T) + require.Zero(t, 0) + fmt.Println("passed") + + // Output: passed +} + +// Test helpers (also in the tests for package require +// +// This code is duplicated because the current test is run as a separate test package: require_test + +func testDataPath() string { + return filepath.Join("..", "internal", "assertions", "testdata") +} + +func httpOK(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) +} + +func httpRedirect(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func httpBody(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + _, _ = fmt.Fprintf(w, "Hello, %s!", name) +} + +//nolint:gochecknoglobals // this is on purpose to share a common pointer when testing +var ( + staticVar = "static string" + staticVarPtr = &staticVar + dummyInterface require.T +) + +func ptr[T any](value T) *T { + p := value + + return &p +} + +type dummyStruct struct { + A string + b int +} + +type dummyError struct { +} + +func (d *dummyError) Error() string { + return "dummy error" +} diff --git a/require/require_format.go b/require/require_format.go new file mode 100644 index 000000000..826d4dba4 --- /dev/null +++ b/require/require_format.go @@ -0,0 +1,1124 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// Conditionf is the same as [Condition], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Conditionf(t T, comp Comparison, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Condition(t, comp, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Containsf is the same as [Contains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Containsf(t T, s any, contains any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Contains(t, s, contains, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// DirExistsf is the same as [DirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func DirExistsf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.DirExists(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// ElementsMatchf is the same as [ElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ElementsMatchf(t T, listA any, listB any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ElementsMatch(t, listA, listB, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Emptyf is the same as [Empty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Emptyf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Empty(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Equalf is the same as [Equal], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Equalf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Equal(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// EqualErrorf is the same as [EqualError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualErrorf(t T, theError error, errString string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualError(t, theError, errString, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// EqualExportedValuesf is the same as [EqualExportedValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualExportedValuesf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualExportedValues(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// EqualValuesf is the same as [EqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EqualValuesf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EqualValues(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Errorf is the same as [Error], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Errorf(t T, err error, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Error(t, err, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// ErrorAsf is the same as [ErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorAsf(t T, err error, target any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorAs(t, err, target, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// ErrorContainsf is the same as [ErrorContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorContainsf(t T, theError error, contains string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorContains(t, theError, contains, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// ErrorIsf is the same as [ErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func ErrorIsf(t T, err error, target error, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.ErrorIs(t, err, target, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Eventuallyf is the same as [Eventually], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Eventuallyf(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Eventually(t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// EventuallyWithTf is the same as [EventuallyWithT], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func EventuallyWithTf(t T, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.EventuallyWithT(t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Exactlyf is the same as [Exactly], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Exactlyf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Exactly(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Failf is the same as [Fail], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Failf(t T, failureMessage string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + _ = assertions.Fail(t, failureMessage, forwardArgs(msg, args)) + + t.FailNow() +} + +// FailNowf is the same as [FailNow], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FailNowf(t T, failureMessage string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + _ = assertions.FailNow(t, failureMessage, forwardArgs(msg, args)) + + t.FailNow() +} + +// Falsef is the same as [False], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Falsef(t T, value bool, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.False(t, value, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// FileEmptyf is the same as [FileEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileEmptyf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileEmpty(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// FileExistsf is the same as [FileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileExistsf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileExists(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// FileNotEmptyf is the same as [FileNotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func FileNotEmptyf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.FileNotEmpty(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Greaterf is the same as [Greater], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Greaterf(t T, e1 any, e2 any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Greater(t, e1, e2, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// GreaterOrEqualf is the same as [GreaterOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func GreaterOrEqualf(t T, e1 any, e2 any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.GreaterOrEqual(t, e1, e2, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPBodyContainsf is the same as [HTTPBodyContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPBodyContainsf(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPBodyContains(t, handler, method, url, values, str, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPBodyNotContainsf is the same as [HTTPBodyNotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPBodyNotContainsf(t T, handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPBodyNotContains(t, handler, method, url, values, str, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPErrorf is the same as [HTTPError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPErrorf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPError(t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPRedirectf is the same as [HTTPRedirect], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPRedirectf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPRedirect(t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPStatusCodef is the same as [HTTPStatusCode], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPStatusCodef(t T, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPStatusCode(t, handler, method, url, values, statuscode, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// HTTPSuccessf is the same as [HTTPSuccess], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func HTTPSuccessf(t T, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.HTTPSuccess(t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Implementsf is the same as [Implements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Implementsf(t T, interfaceObject any, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Implements(t, interfaceObject, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// InDeltaf is the same as [InDelta], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDeltaf(t T, expected any, actual any, delta float64, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InDelta(t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// InDeltaMapValuesf is the same as [InDeltaMapValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDeltaMapValuesf(t T, expected any, actual any, delta float64, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InDeltaMapValues(t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// InDeltaSlicef is the same as [InDeltaSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InDeltaSlicef(t T, expected any, actual any, delta float64, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InDeltaSlice(t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// InEpsilonf is the same as [InEpsilon], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InEpsilonf(t T, expected any, actual any, epsilon float64, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InEpsilon(t, expected, actual, epsilon, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// InEpsilonSlicef is the same as [InEpsilonSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func InEpsilonSlicef(t T, expected any, actual any, epsilon float64, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.InEpsilonSlice(t, expected, actual, epsilon, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsDecreasingf is the same as [IsDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsDecreasingf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsDecreasing(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsIncreasingf is the same as [IsIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsIncreasingf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsIncreasing(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsNonDecreasingf is the same as [IsNonDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNonDecreasingf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNonDecreasing(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsNonIncreasingf is the same as [IsNonIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNonIncreasingf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNonIncreasing(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsNotTypef is the same as [IsNotType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsNotTypef(t T, theType any, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsNotType(t, theType, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// IsTypef is the same as [IsType], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func IsTypef(t T, expectedType any, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.IsType(t, expectedType, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// JSONEqf is the same as [JSONEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func JSONEqf(t T, expected string, actual string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.JSONEq(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// JSONEqBytesf is the same as [JSONEqBytes], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func JSONEqBytesf(t T, expected []byte, actual []byte, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.JSONEqBytes(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Lenf is the same as [Len], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Lenf(t T, object any, length int, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Len(t, object, length, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Lessf is the same as [Less], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Lessf(t T, e1 any, e2 any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Less(t, e1, e2, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// LessOrEqualf is the same as [LessOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func LessOrEqualf(t T, e1 any, e2 any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.LessOrEqual(t, e1, e2, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Negativef is the same as [Negative], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Negativef(t T, e any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Negative(t, e, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Neverf is the same as [Never], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Neverf(t T, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Never(t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Nilf is the same as [Nil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Nilf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Nil(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NoDirExistsf is the same as [NoDirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoDirExistsf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoDirExists(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NoErrorf is the same as [NoError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoErrorf(t T, err error, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoError(t, err, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NoFileExistsf is the same as [NoFileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NoFileExistsf(t T, path string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NoFileExists(t, path, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotContainsf is the same as [NotContains], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotContainsf(t T, s any, contains any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotContains(t, s, contains, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotElementsMatchf is the same as [NotElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotElementsMatchf(t T, listA any, listB any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotElementsMatch(t, listA, listB, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotEmptyf is the same as [NotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEmptyf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEmpty(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotEqualf is the same as [NotEqual], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEqualf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEqual(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotEqualValuesf is the same as [NotEqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotEqualValuesf(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotEqualValues(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotErrorAsf is the same as [NotErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotErrorAsf(t T, err error, target any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotErrorAs(t, err, target, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotErrorIsf is the same as [NotErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotErrorIsf(t T, err error, target error, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotErrorIs(t, err, target, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotImplementsf is the same as [NotImplements], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotImplementsf(t T, interfaceObject any, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotImplements(t, interfaceObject, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotNilf is the same as [NotNil], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotNilf(t T, object any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotNil(t, object, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotPanicsf is the same as [NotPanics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotPanicsf(t T, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotPanics(t, f, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotRegexpf is the same as [NotRegexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotRegexpf(t T, rx any, str any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotRegexp(t, rx, str, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotSamef is the same as [NotSame], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotSamef(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotSame(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotSubsetf is the same as [NotSubset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotSubsetf(t T, list any, subset any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotSubset(t, list, subset, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// NotZerof is the same as [NotZero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func NotZerof(t T, i any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.NotZero(t, i, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Panicsf is the same as [Panics], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Panicsf(t T, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Panics(t, f, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// PanicsWithErrorf is the same as [PanicsWithError], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func PanicsWithErrorf(t T, errString string, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.PanicsWithError(t, errString, f, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// PanicsWithValuef is the same as [PanicsWithValue], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func PanicsWithValuef(t T, expected any, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.PanicsWithValue(t, expected, f, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Positivef is the same as [Positive], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Positivef(t T, e any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Positive(t, e, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Regexpf is the same as [Regexp], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Regexpf(t T, rx any, str any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Regexp(t, rx, str, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Samef is the same as [Same], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Samef(t T, expected any, actual any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Same(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Subsetf is the same as [Subset], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Subsetf(t T, list any, subset any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Subset(t, list, subset, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Truef is the same as [True], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Truef(t T, value bool, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.True(t, value, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// WithinDurationf is the same as [WithinDuration], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func WithinDurationf(t T, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.WithinDuration(t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// WithinRangef is the same as [WithinRange], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func WithinRangef(t T, actual time.Time, start time.Time, end time.Time, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.WithinRange(t, actual, start, end, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// YAMLEqf is the same as [YAMLEq], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func YAMLEqf(t T, expected string, actual string, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.YAMLEq(t, expected, actual, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +// Zerof is the same as [Zero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func Zerof(t T, i any, msg string, args ...any) { + if h, ok := t.(H); ok { + h.Helper() + } + if assertions.Zero(t, i, forwardArgs(msg, args)) { + return + } + + t.FailNow() +} + +func forwardArgs(msg string, args []any) []any { + result := make([]any, len(args)+1) + result[0] = msg + copy(result[1:], args) + + return result +} diff --git a/require/require_format_test.go b/require/require_format_test.go new file mode 100644 index 000000000..219c9fb35 --- /dev/null +++ b/require/require_format_test.go @@ -0,0 +1,1575 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestConditionf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Conditionf(t, func() bool { return true }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Conditionf(mock, func() bool { return false }, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Condition should call FailNow()") + } + }) +} + +func TestContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Containsf(t, []string{"A", "B"}, "A", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Containsf(mock, []string{"A", "B"}, "C", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Contains should call FailNow()") + } + }) +} + +func TestDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + DirExistsf(t, filepath.Join(testDataPath(), "existing_dir"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + DirExistsf(mock, filepath.Join(testDataPath(), "non_existing_dir"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("DirExists should call FailNow()") + } + }) +} + +func TestElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ElementsMatchf(t, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ElementsMatchf(mock, []int{1, 2, 3}, []int{1, 2, 4}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("ElementsMatch should call FailNow()") + } + }) +} + +func TestEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Emptyf(t, "", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Emptyf(mock, "not empty", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Empty should call FailNow()") + } + }) +} + +func TestEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Equalf(t, 123, 123, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Equalf(mock, 123, 456, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Equal should call FailNow()") + } + }) +} + +func TestEqualErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualErrorf(t, ErrTest, "assert.ErrTest general error for testing", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualErrorf(mock, ErrTest, "wrong error message", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("EqualError should call FailNow()") + } + }) +} + +func TestEqualExportedValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualExportedValuesf(t, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualExportedValuesf(mock, &dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("EqualExportedValues should call FailNow()") + } + }) +} + +func TestEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EqualValuesf(t, uint32(123), int32(123), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EqualValuesf(mock, uint32(123), int32(456), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("EqualValues should call FailNow()") + } + }) +} + +func TestErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Errorf(t, ErrTest, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Errorf(mock, nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Error should call FailNow()") + } + }) +} + +func TestErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorAsf(t, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorAsf(mock, ErrTest, new(*dummyError), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("ErrorAs should call FailNow()") + } + }) +} + +func TestErrorContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorContainsf(t, ErrTest, "general error", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorContainsf(mock, ErrTest, "not in message", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("ErrorContains should call FailNow()") + } + }) +} + +func TestErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + ErrorIsf(t, fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + ErrorIsf(mock, ErrTest, io.EOF, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("ErrorIs should call FailNow()") + } + }) +} + +func TestEventuallyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Eventuallyf(t, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Eventuallyf(mock, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Eventually should call FailNow()") + } + }) +} + +func TestEventuallyWithTf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + EventuallyWithTf(t, func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + EventuallyWithTf(mock, func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("EventuallyWithT should call FailNow()") + } + }) +} + +func TestExactlyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Exactlyf(t, int32(123), int32(123), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Exactlyf(mock, int32(123), int64(123), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Exactly should call FailNow()") + } + }) +} + +func TestFailf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Failf(mock, "failed", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Fail should call FailNow()") + } + }) +} + +func TestFailNowf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FailNowf(mock, "failed", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestFalsef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Falsef(t, 1 == 0, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Falsef(mock, 1 == 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("False should call FailNow()") + } + }) +} + +func TestFileEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileEmptyf(t, filepath.Join(testDataPath(), "empty_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileEmptyf(mock, filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("FileEmpty should call FailNow()") + } + }) +} + +func TestFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileExistsf(t, filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileExistsf(mock, filepath.Join(testDataPath(), "non_existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("FileExists should call FailNow()") + } + }) +} + +func TestFileNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + FileNotEmptyf(t, filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + FileNotEmptyf(mock, filepath.Join(testDataPath(), "empty_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("FileNotEmpty should call FailNow()") + } + }) +} + +func TestGreaterf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Greaterf(t, 2, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Greaterf(mock, 1, 2, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Greater should call FailNow()") + } + }) +} + +func TestGreaterOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + GreaterOrEqualf(t, 2, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + GreaterOrEqualf(mock, 1, 2, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("GreaterOrEqual should call FailNow()") + } + }) +} + +func TestHTTPBodyContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPBodyContainsf(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPBodyContainsf(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyContains should call FailNow()") + } + }) +} + +func TestHTTPBodyNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPBodyNotContainsf(t, httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPBodyNotContainsf(mock, httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyNotContains should call FailNow()") + } + }) +} + +func TestHTTPErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPErrorf(t, httpError, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPErrorf(mock, httpOK, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPError should call FailNow()") + } + }) +} + +func TestHTTPRedirectf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPRedirectf(t, httpRedirect, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPRedirectf(mock, httpError, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPRedirect should call FailNow()") + } + }) +} + +func TestHTTPStatusCodef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPStatusCodef(t, httpOK, "GET", "/", nil, http.StatusOK, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPStatusCodef(mock, httpError, "GET", "/", nil, http.StatusOK, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPStatusCode should call FailNow()") + } + }) +} + +func TestHTTPSuccessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + HTTPSuccessf(t, httpOK, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + HTTPSuccessf(mock, httpError, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPSuccess should call FailNow()") + } + }) +} + +func TestImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Implementsf(t, ptr(dummyInterface), new(testing.T), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Implementsf(mock, (*error)(nil), new(testing.T), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Implements should call FailNow()") + } + }) +} + +func TestInDeltaf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDeltaf(t, 1.0, 1.01, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDeltaf(mock, 1.0, 1.1, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("InDelta should call FailNow()") + } + }) +} + +func TestInDeltaMapValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDeltaMapValuesf(t, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDeltaMapValuesf(mock, map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaMapValues should call FailNow()") + } + }) +} + +func TestInDeltaSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InDeltaSlicef(t, []float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InDeltaSlicef(mock, []float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaSlice should call FailNow()") + } + }) +} + +func TestInEpsilonf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InEpsilonf(t, 100.0, 101.0, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InEpsilonf(mock, 100.0, 110.0, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilon should call FailNow()") + } + }) +} + +func TestInEpsilonSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + InEpsilonSlicef(t, []float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + InEpsilonSlicef(mock, []float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilonSlice should call FailNow()") + } + }) +} + +func TestIsDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsDecreasingf(t, []int{3, 2, 1}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsDecreasingf(mock, []int{1, 2, 3}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsDecreasing should call FailNow()") + } + }) +} + +func TestIsIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsIncreasingf(t, []int{1, 2, 3}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsIncreasingf(mock, []int{1, 1, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsIncreasing should call FailNow()") + } + }) +} + +func TestIsNonDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNonDecreasingf(t, []int{1, 1, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNonDecreasingf(mock, []int{2, 1, 1}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsNonDecreasing should call FailNow()") + } + }) +} + +func TestIsNonIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNonIncreasingf(t, []int{2, 1, 1}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNonIncreasingf(mock, []int{1, 2, 3}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsNonIncreasing should call FailNow()") + } + }) +} + +func TestIsNotTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsNotTypef(t, int32(123), int64(456), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsNotTypef(mock, 123, 456, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsNotType should call FailNow()") + } + }) +} + +func TestIsTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + IsTypef(t, 123, 456, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + IsTypef(mock, int32(123), int64(456), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("IsType should call FailNow()") + } + }) +} + +func TestJSONEqf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + JSONEqf(mock, `{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("JSONEq should call FailNow()") + } + }) +} + +func TestJSONEqBytesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + JSONEqBytesf(t, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + JSONEqBytesf(mock, []byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("JSONEqBytes should call FailNow()") + } + }) +} + +func TestLenf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Lenf(t, []string{"A", "B"}, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Lenf(mock, []string{"A", "B"}, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Len should call FailNow()") + } + }) +} + +func TestLessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Lessf(t, 1, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Lessf(mock, 2, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Less should call FailNow()") + } + }) +} + +func TestLessOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + LessOrEqualf(t, 1, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + LessOrEqualf(mock, 2, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("LessOrEqual should call FailNow()") + } + }) +} + +func TestNegativef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Negativef(t, -1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Negativef(mock, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Negative should call FailNow()") + } + }) +} + +func TestNeverf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Neverf(t, func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Neverf(mock, func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Never should call FailNow()") + } + }) +} + +func TestNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Nilf(t, nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Nilf(mock, "not nil", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Nil should call FailNow()") + } + }) +} + +func TestNoDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoDirExistsf(t, filepath.Join(testDataPath(), "non_existing_dir"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoDirExistsf(mock, filepath.Join(testDataPath(), "existing_dir"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NoDirExists should call FailNow()") + } + }) +} + +func TestNoErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoErrorf(t, nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoErrorf(mock, ErrTest, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NoError should call FailNow()") + } + }) +} + +func TestNoFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NoFileExistsf(t, filepath.Join(testDataPath(), "non_existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NoFileExistsf(mock, filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NoFileExists should call FailNow()") + } + }) +} + +func TestNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotContainsf(t, []string{"A", "B"}, "C", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotContainsf(mock, []string{"A", "B"}, "B", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotContains should call FailNow()") + } + }) +} + +func TestNotElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotElementsMatchf(t, []int{1, 2, 3}, []int{1, 2, 4}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotElementsMatchf(mock, []int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotElementsMatch should call FailNow()") + } + }) +} + +func TestNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEmptyf(t, "not empty", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEmptyf(mock, "", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotEmpty should call FailNow()") + } + }) +} + +func TestNotEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEqualf(t, 123, 456, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEqualf(mock, 123, 123, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotEqual should call FailNow()") + } + }) +} + +func TestNotEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotEqualValuesf(t, uint32(123), int32(456), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotEqualValuesf(mock, uint32(123), int32(123), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotEqualValues should call FailNow()") + } + }) +} + +func TestNotErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotErrorAsf(t, ErrTest, new(*dummyError), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotErrorAsf(mock, fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorAs should call FailNow()") + } + }) +} + +func TestNotErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotErrorIsf(t, ErrTest, io.EOF, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotErrorIsf(mock, fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorIs should call FailNow()") + } + }) +} + +func TestNotImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotImplementsf(t, (*error)(nil), new(testing.T), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotImplementsf(mock, ptr(dummyInterface), new(testing.T), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotImplements should call FailNow()") + } + }) +} + +func TestNotNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotNilf(t, "not nil", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotNilf(mock, nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotNil should call FailNow()") + } + }) +} + +func TestNotPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotPanicsf(t, func() {}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotPanicsf(mock, func() { panic("panicking") }, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotPanics should call FailNow()") + } + }) +} + +func TestNotRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotRegexpf(t, "^start", "not starting", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotRegexpf(mock, "^start", "starting", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotRegexp should call FailNow()") + } + }) +} + +func TestNotSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotSamef(t, &staticVar, ptr("static string"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotSamef(mock, &staticVar, staticVarPtr, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotSame should call FailNow()") + } + }) +} + +func TestNotSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotSubsetf(t, []int{1, 2, 3}, []int{4, 5}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotSubsetf(mock, []int{1, 2, 3}, []int{1, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotSubset should call FailNow()") + } + }) +} + +func TestNotZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + NotZerof(t, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + NotZerof(mock, 0, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("NotZero should call FailNow()") + } + }) +} + +func TestPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Panicsf(t, func() { panic("panicking") }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Panicsf(mock, func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Panics should call FailNow()") + } + }) +} + +func TestPanicsWithErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + PanicsWithErrorf(t, ErrTest.Error(), func() { panic(ErrTest) }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + PanicsWithErrorf(mock, ErrTest.Error(), func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithError should call FailNow()") + } + }) +} + +func TestPanicsWithValuef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + PanicsWithValuef(t, "panicking", func() { panic("panicking") }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + PanicsWithValuef(mock, "panicking", func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithValue should call FailNow()") + } + }) +} + +func TestPositivef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Positivef(t, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Positivef(mock, -1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Positive should call FailNow()") + } + }) +} + +func TestRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Regexpf(t, "^start", "starting", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Regexpf(mock, "^start", "not starting", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Regexp should call FailNow()") + } + }) +} + +func TestSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Samef(t, &staticVar, staticVarPtr, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Samef(mock, &staticVar, ptr("static string"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Same should call FailNow()") + } + }) +} + +func TestSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Subsetf(t, []int{1, 2, 3}, []int{1, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Subsetf(mock, []int{1, 2, 3}, []int{4, 5}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Subset should call FailNow()") + } + }) +} + +func TestTruef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Truef(t, 1 == 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Truef(mock, 1 == 0, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("True should call FailNow()") + } + }) +} + +func TestWithinDurationf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + WithinDurationf(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + WithinDurationf(mock, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("WithinDuration should call FailNow()") + } + }) +} + +func TestWithinRangef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + WithinRangef(t, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + WithinRangef(mock, time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("WithinRange should call FailNow()") + } + }) +} + +func TestYAMLEqf(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + Panicsf(t, func() { + YAMLEqf(t, "key: value", "key: value", "test message") + }, "should panic without the yaml feature enabled") + }) +} + +func TestZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + Zerof(t, 0, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + Zerof(mock, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Zero should call FailNow()") + } + }) +} diff --git a/require/require_forward.go b/require/require_forward.go index 82b921488..ed796027a 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -1,1804 +1,2234 @@ -// Code generated with github.com/go-openapi/testify/v2/_codegen; DO NOT EDIT. +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. package require import ( - assert "github.com/go-openapi/testify/v2/assert" - http "net/http" - url "net/url" - time "time" + "net/http" + "net/url" + "time" + + "github.com/go-openapi/testify/v2/internal/assertions" ) -// Condition uses a Comparison to assert a complex condition. -func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Assertions exposes all assertion functions as methods. +// +// NOTE: assertion methods with parameterized types (generics) are not supported as methods. +// +// Upon failure, the test [T] is marked as failed and stops execution. +type Assertions struct { + t T +} + +// New makes a new [Assertions] object for the specified [T] (e.g. [testing.T]). +func New(t T) *Assertions { + return &Assertions{ + t: t, + } +} + +// Condition is the same as [Condition], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Condition(comp Comparison, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Condition(a.t, comp, msgAndArgs...) + if assertions.Condition(a.t, comp, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Conditionf uses a Comparison to assert a complex condition. -func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Conditionf is the same as [Assertions.Condition], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Conditionf(comp Comparison, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Conditionf(a.t, comp, msg, args...) + if assertions.Condition(a.t, comp, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Contains asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. +// Contains is the same as [Contains], as a method rather than a package-level function. // -// a.Contains("Hello World", "World") -// a.Contains(["Hello", "World"], "World") -// a.Contains({"Hello": "World"}, "Hello") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Contains(s any, contains any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Contains(a.t, s, contains, msgAndArgs...) + if assertions.Contains(a.t, s, contains, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Containsf asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. +// Containsf is the same as [Assertions.Contains], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Containsf(s any, contains any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Containsf(a.t, s, contains, msg, args...) + if assertions.Contains(a.t, s, contains, forwardArgs(msg, args)) { + return + } + + a.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. +// DirExists is the same as [DirExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) DirExists(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - DirExists(a.t, path, msgAndArgs...) + if assertions.DirExists(a.t, path, msgAndArgs...) { + return + } + + a.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. +// DirExistsf is the same as [Assertions.DirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) DirExistsf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - DirExistsf(a.t, path, msg, args...) + if assertions.DirExists(a.t, path, forwardArgs(msg, args)) { + return + } + + a.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. +// ElementsMatch is the same as [ElementsMatch], as a method rather than a package-level function. // -// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ElementsMatch(listA any, listB any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ElementsMatch(a.t, listA, listB, msgAndArgs...) + if assertions.ElementsMatch(a.t, listA, listB, msgAndArgs...) { + return + } + + a.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. +// ElementsMatchf is the same as [Assertions.ElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted"). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ElementsMatchf(listA any, listB any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ElementsMatchf(a.t, listA, listB, msg, args...) + if assertions.ElementsMatch(a.t, listA, listB, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Empty asserts that the given value is "empty". +// Empty is the same as [Empty], as a method rather than a package-level function. // -// [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 +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Empty(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Empty(a.t, object, msgAndArgs...) + if assertions.Empty(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Emptyf asserts that the given value is "empty". +// Emptyf is the same as [Assertions.Empty], but accepts a format msg string to format arguments like [fmt.Printf]. // -// [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 +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Emptyf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Emptyf(a.t, object, msg, args...) + if assertions.Empty(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Equal asserts that two objects are equal. +// Equal is the same as [Equal], as a method rather than a package-level function. // -// 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. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Equal(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { + h.Helper() + } + if assertions.Equal(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() +} + +// Equalf is the same as [Assertions.Equal], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Equalf(expected any, actual any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Equal(a.t, expected, actual, msgAndArgs...) + if assertions.Equal(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.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. +// EqualError is the same as [EqualError], as a method rather than a package-level function. // -// actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualError(a.t, theError, errString, msgAndArgs...) + if assertions.EqualError(a.t, theError, errString, msgAndArgs...) { + return + } + + a.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. +// EqualErrorf is the same as [Assertions.EqualError], but accepts a format msg string to format arguments like [fmt.Printf]. // -// actualObj, err := SomeFunction() -// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualErrorf(a.t, theError, errString, msg, args...) + if assertions.EqualError(a.t, theError, errString, forwardArgs(msg, args)) { + return + } + + a.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. +// EqualExportedValues is the same as [EqualExportedValues], as a method rather than a package-level function. // -// 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 +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualExportedValues(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualExportedValues(a.t, expected, actual, msgAndArgs...) + if assertions.EqualExportedValues(a.t, expected, actual, msgAndArgs...) { + return + } + + a.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. +// EqualExportedValuesf is the same as [Assertions.EqualExportedValues], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualExportedValuesf(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualExportedValuesf(a.t, expected, actual, msg, args...) + if assertions.EqualExportedValues(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// EqualValues asserts that two objects are equal or convertible to the larger -// type and equal. +// EqualValues is the same as [EqualValues], as a method rather than a package-level function. // -// a.EqualValues(uint32(123), int32(123)) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualValues(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualValues(a.t, expected, actual, msgAndArgs...) + if assertions.EqualValues(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// EqualValuesf asserts that two objects are equal or convertible to the larger -// type and equal. +// EqualValuesf is the same as [Assertions.EqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) EqualValuesf(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - EqualValuesf(a.t, expected, actual, msg, args...) + if assertions.EqualValues(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Equalf asserts that two objects are equal. +// Error is the same as [Error], as a method rather than a package-level function. // -// 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 any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Error(err error, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Equalf(a.t, expected, actual, msg, args...) + if assertions.Error(a.t, err, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Error asserts that a function returned a non-nil error (ie. an error). +// Errorf is the same as [Assertions.Error], but accepts a format msg string to format arguments like [fmt.Printf]. // -// actualObj, err := SomeFunction() -// a.Error(err) -func (a *Assertions) Error(err error, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Errorf(err error, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Error(a.t, err, msgAndArgs...) + if assertions.Error(a.t, err, forwardArgs(msg, args)) { + return + } + + a.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. +// ErrorAs is the same as [ErrorAs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ErrorAs(err error, target any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ErrorAs(a.t, err, target, msgAndArgs...) + if assertions.ErrorAs(a.t, err, target, msgAndArgs...) { + return + } + + a.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. +// ErrorAsf is the same as [Assertions.ErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ErrorAsf(err error, target any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ErrorAsf(a.t, err, target, msg, args...) + if assertions.ErrorAs(a.t, err, target, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// ErrorContains asserts that a function returned a non-nil error (i.e. an -// error) and that the error contains the specified substring. +// ErrorContains is the same as [ErrorContains], as a method rather than a package-level function. // -// actualObj, err := SomeFunction() -// a.ErrorContains(err, expectedErrorSubString) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ErrorContains(a.t, theError, contains, msgAndArgs...) + if assertions.ErrorContains(a.t, theError, contains, msgAndArgs...) { + return + } + + a.t.FailNow() } -// ErrorContainsf asserts that a function returned a non-nil error (i.e. an -// error) and that the error contains the specified substring. +// ErrorContainsf is the same as [Assertions.ErrorContains], but accepts a format msg string to format arguments like [fmt.Printf]. // -// actualObj, err := SomeFunction() -// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - ErrorContainsf(a.t, theError, contains, msg, args...) + if assertions.ErrorContains(a.t, theError, contains, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// ErrorIs asserts that at least one of the errors in err's chain matches target. -// This is a wrapper for errors.Is. +// ErrorIs is the same as [ErrorIs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); 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 ...any) { - if h, ok := a.t.(tHelper); ok { - h.Helper() + if assertions.ErrorIs(a.t, err, target, msgAndArgs...) { + return } - ErrorIsf(a.t, err, target, msg, args...) + + a.t.FailNow() } -// Errorf asserts that a function returned a non-nil error (ie. an error). +// ErrorIsf is the same as [Assertions.ErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. // -// actualObj, err := SomeFunction() -// a.Errorf(err, "error message %s", "formatted") -func (a *Assertions) Errorf(err error, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Errorf(a.t, err, msg, args...) + if assertions.ErrorIs(a.t, err, target, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Eventually asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. +// Eventually is the same as [Eventually], as a method rather than a package-level function. // -// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Eventually(a.t, condition, waitFor, tick, msgAndArgs...) + if assertions.Eventually(a.t, condition, waitFor, tick, msgAndArgs...) { + return + } + + a.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. +// Eventuallyf is the same as [Assertions.Eventually], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) + if assertions.Eventually(a.t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + a.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. +// EventuallyWithT is the same as [EventuallyWithT], as a method rather than a package-level function. // -// externalValue := false -// go func() { -// time.Sleep(8*time.Second) -// externalValue = true -// }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { -// // 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) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) + if assertions.EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Eventuallyf asserts that given condition will be met in waitFor time, -// periodically checking target function each tick. +// EventuallyWithTf is the same as [Assertions.EventuallyWithT], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Eventuallyf(a.t, condition, waitFor, tick, msg, args...) + if assertions.EventuallyWithT(a.t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Exactly asserts that two objects are equal in value and type. +// Exactly is the same as [Exactly], as a method rather than a package-level function. // -// a.Exactly(int32(123), int64(123)) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Exactly(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Exactly(a.t, expected, actual, msgAndArgs...) + if assertions.Exactly(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Exactlyf asserts that two objects are equal in value and type. +// Exactlyf is the same as [Assertions.Exactly], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Exactlyf(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Exactlyf(a.t, expected, actual, msg, args...) + if assertions.Exactly(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Fail reports a failure through. +// Fail is the same as [Fail], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Fail(failureMessage string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Fail(a.t, failureMessage, msgAndArgs...) + _ = assertions.Fail(a.t, failureMessage, msgAndArgs...) + + a.t.FailNow() } -// FailNow fails test. -func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Failf is the same as [Assertions.Fail], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Failf(failureMessage string, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - FailNow(a.t, failureMessage, msgAndArgs...) + _ = assertions.Fail(a.t, failureMessage, forwardArgs(msg, args)) + + a.t.FailNow() } -// FailNowf fails test. -func (a *Assertions) FailNowf(failureMessage string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// FailNow is the same as [FailNow], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - FailNowf(a.t, failureMessage, msg, args...) + _ = assertions.FailNow(a.t, failureMessage, msgAndArgs...) + + a.t.FailNow() } -// Failf reports a failure through. -func (a *Assertions) Failf(failureMessage string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// FailNowf is the same as [Assertions.FailNow], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Failf(a.t, failureMessage, msg, args...) + _ = assertions.FailNow(a.t, failureMessage, forwardArgs(msg, args)) + + a.t.FailNow() } -// False asserts that the specified value is false. +// False is the same as [False], as a method rather than a package-level function. // -// a.False(myBool) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) False(value bool, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - False(a.t, value, msgAndArgs...) + if assertions.False(a.t, value, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Falsef asserts that the specified value is false. +// Falsef is the same as [Assertions.False], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Falsef(myBool, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Falsef(value bool, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Falsef(a.t, value, msg, args...) + if assertions.False(a.t, value, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// FileEmpty checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. +// FileEmpty is the same as [FileEmpty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileEmpty(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileEmpty(a.t, path, msgAndArgs...) + if assertions.FileEmpty(a.t, path, msgAndArgs...) { + return + } + + a.t.FailNow() } -// FileEmptyf checks whether a file exists in the given path and is empty. -// It fails if the file is not empty, if the path points to a directory or there is an error when trying to check the file. +// FileEmptyf is the same as [Assertions.FileEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileEmptyf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileEmptyf(a.t, path, msg, args...) + if assertions.FileEmpty(a.t, path, forwardArgs(msg, args)) { + return + } + + a.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. +// FileExists is the same as [FileExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileExists(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileExists(a.t, path, msgAndArgs...) + if assertions.FileExists(a.t, path, msgAndArgs...) { + return + } + + a.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. +// FileExistsf is the same as [Assertions.FileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileExistsf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileExistsf(a.t, path, msg, args...) + if assertions.FileExists(a.t, path, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// FileNotEmpty checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. +// FileNotEmpty is the same as [FileNotEmpty], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileNotEmpty(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileNotEmpty(a.t, path, msgAndArgs...) + if assertions.FileNotEmpty(a.t, path, msgAndArgs...) { + return + } + + a.t.FailNow() } -// FileNotEmptyf checks whether a file exists in the given path and is not empty. -// It fails if the file is empty, if the path points to a directory or there is an error when trying to check the file. +// FileNotEmptyf is the same as [Assertions.FileNotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) FileNotEmptyf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - FileNotEmptyf(a.t, path, msg, args...) + if assertions.FileNotEmpty(a.t, path, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Greater asserts that the first element is greater than the second +// Greater is the same as [Greater], as a method rather than a package-level function. // -// a.Greater(2, 1) -// a.Greater(float64(2), float64(1)) -// a.Greater("b", "a") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Greater(e1 any, e2 any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Greater(a.t, e1, e2, msgAndArgs...) + if assertions.Greater(a.t, e1, e2, msgAndArgs...) { + return + } + + a.t.FailNow() } -// GreaterOrEqual asserts that the first element is greater than or equal to the second +// Greaterf is the same as [Assertions.Greater], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.GreaterOrEqual(2, 1) -// a.GreaterOrEqual(2, 2) -// a.GreaterOrEqual("b", "a") -// a.GreaterOrEqual("b", "b") -func (a *Assertions) GreaterOrEqual(e1 any, e2 any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Greaterf(e1 any, e2 any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - GreaterOrEqual(a.t, e1, e2, msgAndArgs...) + if assertions.Greater(a.t, e1, e2, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// GreaterOrEqual is the same as [GreaterOrEqual], as a method rather than a package-level function. // -// 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 any, e2 any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) GreaterOrEqual(e1 any, e2 any, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - GreaterOrEqualf(a.t, e1, e2, msg, args...) + if assertions.GreaterOrEqual(a.t, e1, e2, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Greaterf asserts that the first element is greater than the second +// GreaterOrEqualf is the same as [Assertions.GreaterOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 any, e2 any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) GreaterOrEqualf(e1 any, e2 any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Greaterf(a.t, e1, e2, msg, args...) + if assertions.GreaterOrEqual(a.t, e1, e2, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// 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") +// HTTPBodyContains is the same as [HTTPBodyContains], as a method rather than a package-level function. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) + if assertions.HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) { + return + } + + a.t.FailNow() } -// 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") +// HTTPBodyContainsf is the same as [Assertions.HTTPBodyContains], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) + if assertions.HTTPBodyContains(a.t, handler, method, url, values, str, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// HTTPBodyNotContains asserts that a specified handler returns a -// body that does not contain a string. +// HTTPBodyNotContains is the same as [HTTPBodyNotContains], as a method rather than a package-level function. // -// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) + if assertions.HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) { + return + } + + a.t.FailNow() } -// 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") +// HTTPBodyNotContainsf is the same as [Assertions.HTTPBodyNotContains], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) + if assertions.HTTPBodyNotContains(a.t, handler, method, url, values, str, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// HTTPError asserts that a specified handler returns an error status code. -// -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// HTTPError is the same as [HTTPError], as a method rather than a package-level function. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPError(a.t, handler, method, url, values, msgAndArgs...) + if assertions.HTTPError(a.t, handler, method, url, values, msgAndArgs...) { + return + } + + a.t.FailNow() } -// HTTPErrorf asserts that a specified handler returns an error status code. +// HTTPErrorf is the same as [Assertions.HTTPError], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPErrorf(a.t, handler, method, url, values, msg, args...) + if assertions.HTTPError(a.t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// HTTPRedirect asserts that a specified handler returns a redirect status code. +// HTTPRedirect is the same as [HTTPRedirect], as a method rather than a package-level function. // -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) + if assertions.HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) { + return + } + + a.t.FailNow() } -// HTTPRedirectf asserts that a specified handler returns a redirect status code. -// -// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// HTTPRedirectf is the same as [Assertions.HTTPRedirect], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPRedirectf(a.t, handler, method, url, values, msg, args...) + if assertions.HTTPRedirect(a.t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// HTTPStatusCode asserts that a specified handler returns a specified status code. -// -// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// HTTPStatusCode is the same as [HTTPStatusCode], as a method rather than a package-level function. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) + if assertions.HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + + a.t.FailNow() } -// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// HTTPStatusCodef is the same as [Assertions.HTTPStatusCode], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) + if assertions.HTTPStatusCode(a.t, handler, method, url, values, statuscode, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// HTTPSuccess asserts that a specified handler returns a success status code. -// -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// HTTPSuccess is the same as [HTTPSuccess], as a method rather than a package-level function. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) + if assertions.HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) { + return + } + + a.t.FailNow() } -// HTTPSuccessf asserts that a specified handler returns a success status code. -// -// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// HTTPSuccessf is the same as [Assertions.HTTPSuccess], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Returns whether the assertion was successful (true) or not (false). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - HTTPSuccessf(a.t, handler, method, url, values, msg, args...) + if assertions.HTTPSuccess(a.t, handler, method, url, values, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Implements asserts that an object is implemented by the specified interface. +// Implements is the same as [Implements], as a method rather than a package-level function. // -// a.Implements((*MyInterface)(nil), new(MyObject)) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Implements(interfaceObject any, object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Implements(a.t, interfaceObject, object, msgAndArgs...) + if assertions.Implements(a.t, interfaceObject, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Implementsf asserts that an object is implemented by the specified interface. +// Implementsf is the same as [Assertions.Implements], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Implementsf(interfaceObject any, object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Implementsf(a.t, interfaceObject, object, msg, args...) + if assertions.Implements(a.t, interfaceObject, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// InDelta asserts that the two numerals are within delta of each other. +// InDelta is the same as [InDelta], as a method rather than a package-level function. // -// a.InDelta(math.Pi, 22/7.0, 0.01) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InDelta(expected any, actual any, delta float64, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { + h.Helper() + } + if assertions.InDelta(a.t, expected, actual, delta, msgAndArgs...) { + return + } + + a.t.FailNow() +} + +// InDeltaf is the same as [Assertions.InDelta], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) InDeltaf(expected any, actual any, delta float64, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - InDelta(a.t, expected, actual, delta, msgAndArgs...) + if assertions.InDelta(a.t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// InDeltaMapValues is the same as [InDeltaMapValues], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InDeltaMapValues(expected any, actual any, delta float64, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) + if assertions.InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) { + return + } + + a.t.FailNow() } -// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// InDeltaMapValuesf is the same as [Assertions.InDeltaMapValues], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InDeltaMapValuesf(expected any, actual any, delta float64, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) + if assertions.InDeltaMapValues(a.t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// InDeltaSlice is the same as InDelta, except it compares two slices. +// InDeltaSlice is the same as [InDeltaSlice], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InDeltaSlice(expected any, actual any, delta float64, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) + if assertions.InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) { + return + } + + a.t.FailNow() } -// InDeltaSlicef is the same as InDelta, except it compares two slices. +// InDeltaSlicef is the same as [Assertions.InDeltaSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InDeltaSlicef(expected any, actual any, delta float64, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - InDeltaSlicef(a.t, expected, actual, delta, msg, args...) + if assertions.InDeltaSlice(a.t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// InDeltaf asserts that the two numerals are within delta of each other. +// InEpsilon is the same as [InEpsilon], as a method rather than a package-level function. // -// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") -func (a *Assertions) InDeltaf(expected any, actual any, delta float64, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) InEpsilon(expected any, actual any, epsilon float64, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - InDeltaf(a.t, expected, actual, delta, msg, args...) + if assertions.InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) { + return + } + + a.t.FailNow() } -// InEpsilon asserts that expected and actual have a relative error less than epsilon. -func (a *Assertions) InEpsilon(expected any, actual any, epsilon float64, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// InEpsilonf is the same as [Assertions.InEpsilon], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) InEpsilonf(expected any, actual any, epsilon float64, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) + if assertions.InEpsilon(a.t, expected, actual, epsilon, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +// InEpsilonSlice is the same as [InEpsilonSlice], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InEpsilonSlice(expected any, actual any, epsilon float64, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) + if assertions.InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) { + return + } + + a.t.FailNow() } -// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +// InEpsilonSlicef is the same as [Assertions.InEpsilonSlice], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) InEpsilonSlicef(expected any, actual any, epsilon float64, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); 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 any, actual any, epsilon float64, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { - h.Helper() + if assertions.InEpsilonSlice(a.t, expected, actual, epsilon, forwardArgs(msg, args)) { + return } - InEpsilonf(a.t, expected, actual, epsilon, msg, args...) + + a.t.FailNow() } -// IsDecreasing asserts that the collection is decreasing +// IsDecreasing is the same as [IsDecreasing], as a method rather than a package-level function. // -// a.IsDecreasing([]int{2, 1, 0}) -// a.IsDecreasing([]float{2, 1}) -// a.IsDecreasing([]string{"b", "a"}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsDecreasing(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsDecreasing(a.t, object, msgAndArgs...) + if assertions.IsDecreasing(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsDecreasingf asserts that the collection is decreasing +// IsDecreasingf is the same as [Assertions.IsDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsDecreasingf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsDecreasingf(a.t, object, msg, args...) + if assertions.IsDecreasing(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// IsIncreasing asserts that the collection is increasing +// IsIncreasing is the same as [IsIncreasing], as a method rather than a package-level function. // -// a.IsIncreasing([]int{1, 2, 3}) -// a.IsIncreasing([]float{1, 2}) -// a.IsIncreasing([]string{"a", "b"}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsIncreasing(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsIncreasing(a.t, object, msgAndArgs...) + if assertions.IsIncreasing(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsIncreasingf asserts that the collection is increasing +// IsIncreasingf is the same as [Assertions.IsIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsIncreasingf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsIncreasingf(a.t, object, msg, args...) + if assertions.IsIncreasing(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// IsNonDecreasing asserts that the collection is not decreasing +// IsNonDecreasing is the same as [IsNonDecreasing], as a method rather than a package-level function. // -// a.IsNonDecreasing([]int{1, 1, 2}) -// a.IsNonDecreasing([]float{1, 2}) -// a.IsNonDecreasing([]string{"a", "b"}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNonDecreasing(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNonDecreasing(a.t, object, msgAndArgs...) + if assertions.IsNonDecreasing(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsNonDecreasingf asserts that the collection is not decreasing +// IsNonDecreasingf is the same as [Assertions.IsNonDecreasing], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNonDecreasingf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNonDecreasingf(a.t, object, msg, args...) + if assertions.IsNonDecreasing(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// IsNonIncreasing asserts that the collection is not increasing +// IsNonIncreasing is the same as [IsNonIncreasing], as a method rather than a package-level function. // -// a.IsNonIncreasing([]int{2, 1, 1}) -// a.IsNonIncreasing([]float{2, 1}) -// a.IsNonIncreasing([]string{"b", "a"}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNonIncreasing(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNonIncreasing(a.t, object, msgAndArgs...) + if assertions.IsNonIncreasing(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsNonIncreasingf asserts that the collection is not increasing +// IsNonIncreasingf is the same as [Assertions.IsNonIncreasing], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNonIncreasingf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNonIncreasingf(a.t, object, msg, args...) + if assertions.IsNonIncreasing(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// IsNotType asserts that the specified objects are not of the same type. +// IsNotType is the same as [IsNotType], as a method rather than a package-level function. // -// a.IsNotType(&NotMyStruct{}, &MyStruct{}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNotType(theType any, object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNotType(a.t, theType, object, msgAndArgs...) + if assertions.IsNotType(a.t, theType, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsNotTypef asserts that the specified objects are not of the same type. +// IsNotTypef is the same as [Assertions.IsNotType], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsNotTypef(theType any, object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsNotTypef(a.t, theType, object, msg, args...) + if assertions.IsNotType(a.t, theType, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// IsType asserts that the specified objects are of the same type. +// IsType is the same as [IsType], as a method rather than a package-level function. // -// a.IsType(&MyStruct{}, &MyStruct{}) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsType(expectedType any, object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsType(a.t, expectedType, object, msgAndArgs...) + if assertions.IsType(a.t, expectedType, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// IsTypef asserts that the specified objects are of the same type. +// IsTypef is the same as [Assertions.IsType], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) IsTypef(expectedType any, object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - IsTypef(a.t, expectedType, object, msg, args...) + if assertions.IsType(a.t, expectedType, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// JSONEq asserts that two JSON strings are equivalent. +// JSONEq is the same as [JSONEq], as a method rather than a package-level function. // -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - JSONEq(a.t, expected, actual, msgAndArgs...) + if assertions.JSONEq(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// JSONEqBytes asserts that two JSON byte slices are equivalent. +// JSONEqf is the same as [Assertions.JSONEq], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) -func (a *Assertions) JSONEqBytes(expected []byte, actual []byte, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - JSONEqBytes(a.t, expected, actual, msgAndArgs...) + if assertions.JSONEq(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// JSONEqBytesf asserts that two JSON byte slices are equivalent. +// JSONEqBytes is the same as [JSONEqBytes], as a method rather than a package-level function. // -// a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "error message %s", "formatted") -func (a *Assertions) JSONEqBytesf(expected []byte, actual []byte, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) JSONEqBytes(expected []byte, actual []byte, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - JSONEqBytesf(a.t, expected, actual, msg, args...) + if assertions.JSONEqBytes(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// JSONEqf asserts that two JSON strings are equivalent. +// JSONEqBytesf is the same as [Assertions.JSONEqBytes], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) JSONEqBytesf(expected []byte, actual []byte, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - JSONEqf(a.t, expected, actual, msg, args...) + if assertions.JSONEqBytes(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Len asserts that the specified object has specific length. -// Len also fails if the object has a type that len() not accept. +// Len is the same as [Len], as a method rather than a package-level function. // -// a.Len(mySlice, 3) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Len(object any, length int, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Len(a.t, object, length, msgAndArgs...) + if assertions.Len(a.t, object, length, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Lenf asserts that the specified object has specific length. -// Lenf also fails if the object has a type that len() not accept. +// Lenf is the same as [Assertions.Len], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Lenf(mySlice, 3, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Lenf(object any, length int, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Lenf(a.t, object, length, msg, args...) + if assertions.Len(a.t, object, length, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Less asserts that the first element is less than the second +// Less is the same as [Less], as a method rather than a package-level function. // -// a.Less(1, 2) -// a.Less(float64(1), float64(2)) -// a.Less("a", "b") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Less(e1 any, e2 any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Less(a.t, e1, e2, msgAndArgs...) + if assertions.Less(a.t, e1, e2, msgAndArgs...) { + return + } + + a.t.FailNow() } -// LessOrEqual asserts that the first element is less than or equal to the second +// Lessf is the same as [Assertions.Less], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.LessOrEqual(1, 2) -// a.LessOrEqual(2, 2) -// a.LessOrEqual("a", "b") -// a.LessOrEqual("b", "b") -func (a *Assertions) LessOrEqual(e1 any, e2 any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Lessf(e1 any, e2 any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - LessOrEqual(a.t, e1, e2, msgAndArgs...) + if assertions.Less(a.t, e1, e2, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// LessOrEqualf asserts that the first element is less than or equal to the second +// LessOrEqual is the same as [LessOrEqual], as a method rather than a package-level function. // -// 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 any, e2 any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) LessOrEqual(e1 any, e2 any, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - LessOrEqualf(a.t, e1, e2, msg, args...) + if assertions.LessOrEqual(a.t, e1, e2, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Lessf asserts that the first element is less than the second +// LessOrEqualf is the same as [Assertions.LessOrEqual], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 any, e2 any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) LessOrEqualf(e1 any, e2 any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Lessf(a.t, e1, e2, msg, args...) + if assertions.LessOrEqual(a.t, e1, e2, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Negative asserts that the specified element is negative +// Negative is the same as [Negative], as a method rather than a package-level function. // -// a.Negative(-1) -// a.Negative(-1.23) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Negative(e any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Negative(a.t, e, msgAndArgs...) + if assertions.Negative(a.t, e, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Negativef asserts that the specified element is negative +// Negativef is the same as [Assertions.Negative], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Negativef(-1, "error message %s", "formatted") -// a.Negativef(-1.23, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Negativef(e any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Negativef(a.t, e, msg, args...) + if assertions.Negative(a.t, e, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Never asserts that the given condition doesn't satisfy in waitFor time, -// periodically checking the target function each tick. +// Never is the same as [Never], as a method rather than a package-level function. // -// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Never(a.t, condition, waitFor, tick, msgAndArgs...) + if assertions.Never(a.t, condition, waitFor, tick, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Neverf asserts that the given condition doesn't satisfy in waitFor time, -// periodically checking the target function each tick. +// Neverf is the same as [Assertions.Never], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Neverf(a.t, condition, waitFor, tick, msg, args...) + if assertions.Never(a.t, condition, waitFor, tick, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Nil asserts that the specified object is nil. +// Nil is the same as [Nil], as a method rather than a package-level function. // -// a.Nil(err) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Nil(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Nil(a.t, object, msgAndArgs...) + if assertions.Nil(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Nilf asserts that the specified object is nil. +// Nilf is the same as [Assertions.Nil], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Nilf(err, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Nilf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Nilf(a.t, object, msg, args...) + if assertions.Nil(a.t, object, forwardArgs(msg, args)) { + return + } + + a.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. +// NoDirExists is the same as [NoDirExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoDirExists(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoDirExists(a.t, path, msgAndArgs...) + if assertions.NoDirExists(a.t, path, msgAndArgs...) { + return + } + + a.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. +// NoDirExistsf is the same as [Assertions.NoDirExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoDirExistsf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoDirExistsf(a.t, path, msg, args...) + if assertions.NoDirExists(a.t, path, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NoError asserts that a function returned a nil error (ie. no error). +// NoError is the same as [NoError], as a method rather than a package-level function. // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoError(err error, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoError(a.t, err, msgAndArgs...) + if assertions.NoError(a.t, err, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NoErrorf asserts that a function returned a nil error (ie. no error). +// NoErrorf is the same as [Assertions.NoError], but accepts a format msg string to format arguments like [fmt.Printf]. // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoErrorf(err error, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoErrorf(a.t, err, msg, args...) + if assertions.NoError(a.t, err, forwardArgs(msg, args)) { + return + } + + a.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. +// NoFileExists is the same as [NoFileExists], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoFileExists(path string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoFileExists(a.t, path, msgAndArgs...) + if assertions.NoFileExists(a.t, path, msgAndArgs...) { + return + } + + a.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. +// NoFileExistsf is the same as [Assertions.NoFileExists], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NoFileExistsf(path string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NoFileExistsf(a.t, path, msg, args...) + if assertions.NoFileExists(a.t, path, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. +// NotContains is the same as [NotContains], as a method rather than a package-level function. // -// a.NotContains("Hello World", "Earth") -// a.NotContains(["Hello", "World"], "Earth") -// a.NotContains({"Hello": "World"}, "Earth") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotContains(s any, contains any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotContains(a.t, s, contains, msgAndArgs...) + if assertions.NotContains(a.t, s, contains, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. +// NotContainsf is the same as [Assertions.NotContains], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotContainsf(s any, contains any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotContainsf(a.t, s, contains, msg, args...) + if assertions.NotContains(a.t, s, contains, forwardArgs(msg, args)) { + return + } + + a.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. -// -// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false -// -// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true +// NotElementsMatch is the same as [NotElementsMatch], as a method rather than a package-level function. // -// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotElementsMatch(listA any, listB any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotElementsMatch(a.t, listA, listB, msgAndArgs...) + if assertions.NotElementsMatch(a.t, listA, listB, msgAndArgs...) { + return + } + + a.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. -// -// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false +// NotElementsMatchf is the same as [Assertions.NotElementsMatch], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotElementsMatchf(listA any, listB any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotElementsMatchf(a.t, listA, listB, msg, args...) + if assertions.NotElementsMatch(a.t, listA, listB, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotEmpty asserts that the specified object is NOT [Empty]. +// NotEmpty is the same as [NotEmpty], as a method rather than a package-level function. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotEmpty(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotEmpty(a.t, object, msgAndArgs...) + if assertions.NotEmpty(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotEmptyf asserts that the specified object is NOT [Empty]. +// NotEmptyf is the same as [Assertions.NotEmpty], but accepts a format msg string to format arguments like [fmt.Printf]. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotEmptyf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotEmptyf(a.t, object, msg, args...) + if assertions.NotEmpty(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotEqual asserts that the specified values are NOT equal. +// NotEqual is the same as [NotEqual], as a method rather than a package-level function. // -// a.NotEqual(obj1, obj2) -// -// Pointer variable equality is determined based on the equality of the -// referenced values (as opposed to the memory addresses). +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotEqual(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotEqual(a.t, expected, actual, msgAndArgs...) + if assertions.NotEqual(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotEqualValues asserts that two objects are not equal even when converted to the same type +// NotEqualf is the same as [Assertions.NotEqual], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.NotEqualValues(obj1, obj2) -func (a *Assertions) NotEqualValues(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) NotEqualf(expected any, actual any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - NotEqualValues(a.t, expected, actual, msgAndArgs...) + if assertions.NotEqual(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// NotEqualValues is the same as [NotEqualValues], as a method rather than a package-level function. // -// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") -func (a *Assertions) NotEqualValuesf(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) NotEqualValues(expected any, actual any, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - NotEqualValuesf(a.t, expected, actual, msg, args...) + if assertions.NotEqualValues(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotEqualf asserts that the specified values are NOT equal. +// NotEqualValuesf is the same as [Assertions.NotEqualValues], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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 any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) NotEqualValuesf(expected any, actual any, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - NotEqualf(a.t, expected, actual, msg, args...) + if assertions.NotEqualValues(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotErrorAs asserts that none of the errors in err's chain matches target, -// but if so, sets target to that error value. +// NotErrorAs is the same as [NotErrorAs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotErrorAs(err error, target any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotErrorAs(a.t, err, target, msgAndArgs...) + if assertions.NotErrorAs(a.t, err, target, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotErrorAsf asserts that none of the errors in err's chain matches target, -// but if so, sets target to that error value. +// NotErrorAsf is the same as [Assertions.NotErrorAs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotErrorAsf(err error, target any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotErrorAsf(a.t, err, target, msg, args...) + if assertions.NotErrorAs(a.t, err, target, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotErrorIs asserts that none of the errors in err's chain matches target. -// This is a wrapper for errors.Is. +// NotErrorIs is the same as [NotErrorIs], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotErrorIs(a.t, err, target, msgAndArgs...) + if assertions.NotErrorIs(a.t, err, target, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotErrorIsf asserts that none of the errors in err's chain matches target. -// This is a wrapper for errors.Is. +// NotErrorIsf is the same as [Assertions.NotErrorIs], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotErrorIsf(a.t, err, target, msg, args...) + if assertions.NotErrorIs(a.t, err, target, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotImplements asserts that an object does not implement the specified interface. +// NotImplements is the same as [NotImplements], as a method rather than a package-level function. // -// a.NotImplements((*MyInterface)(nil), new(MyObject)) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotImplements(interfaceObject any, object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotImplements(a.t, interfaceObject, object, msgAndArgs...) + if assertions.NotImplements(a.t, interfaceObject, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotImplementsf asserts that an object does not implement the specified interface. +// NotImplementsf is the same as [Assertions.NotImplements], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotImplementsf(interfaceObject any, object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotImplementsf(a.t, interfaceObject, object, msg, args...) + if assertions.NotImplements(a.t, interfaceObject, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotNil asserts that the specified object is not nil. +// NotNil is the same as [NotNil], as a method rather than a package-level function. // -// a.NotNil(err) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotNil(object any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotNil(a.t, object, msgAndArgs...) + if assertions.NotNil(a.t, object, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotNilf asserts that the specified object is not nil. +// NotNilf is the same as [Assertions.NotNil], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.NotNilf(err, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotNilf(object any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotNilf(a.t, object, msg, args...) + if assertions.NotNil(a.t, object, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// NotPanics is the same as [NotPanics], as a method rather than a package-level function. // -// a.NotPanics(func(){ RemainCalm() }) -func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) NotPanics(f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - NotPanics(a.t, f, msgAndArgs...) + if assertions.NotPanics(a.t, f, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// NotPanicsf is the same as [Assertions.NotPanics], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") -func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) NotPanicsf(f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - NotPanicsf(a.t, f, msg, args...) + if assertions.NotPanics(a.t, f, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotRegexp asserts that a specified regexp does not match a string. +// NotRegexp is the same as [NotRegexp], as a method rather than a package-level function. // -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotRegexp(rx any, str any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotRegexp(a.t, rx, str, msgAndArgs...) + if assertions.NotRegexp(a.t, rx, str, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotRegexpf asserts that a specified regexp does not match a string. +// NotRegexpf is the same as [Assertions.NotRegexp], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotRegexpf(rx any, str any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotRegexpf(a.t, rx, str, msg, args...) + if assertions.NotRegexp(a.t, rx, str, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotSame asserts that two pointers do not reference the same object. +// NotSame is the same as [NotSame], as a method rather than a package-level function. // -// a.NotSame(ptr1, ptr2) -// -// Both arguments must be pointer variables. Pointer variable sameness is -// determined based on the equality of both type and value. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotSame(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotSame(a.t, expected, actual, msgAndArgs...) + if assertions.NotSame(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotSamef asserts that two pointers do not reference the same object. -// -// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// NotSamef is the same as [Assertions.NotSame], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Both arguments must be pointer variables. Pointer variable sameness is -// determined based on the equality of both type and value. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotSamef(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotSamef(a.t, expected, actual, msg, args...) + if assertions.NotSame(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.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. +// NotSubset is the same as [NotSubset], as a method rather than a package-level function. // -// 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"]) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotSubset(list any, subset any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotSubset(a.t, list, subset, msgAndArgs...) + if assertions.NotSubset(a.t, list, subset, msgAndArgs...) { + return + } + + a.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. +// NotSubsetf is the same as [Assertions.NotSubset], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotSubsetf(list any, subset any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotSubsetf(a.t, list, subset, msg, args...) + if assertions.NotSubset(a.t, list, subset, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// NotZero asserts that i is not the zero value for its type. +// NotZero is the same as [NotZero], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotZero(i any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotZero(a.t, i, msgAndArgs...) + if assertions.NotZero(a.t, i, msgAndArgs...) { + return + } + + a.t.FailNow() } -// NotZerof asserts that i is not the zero value for its type. +// NotZerof is the same as [Assertions.NotZero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) NotZerof(i any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - NotZerof(a.t, i, msg, args...) + if assertions.NotZero(a.t, i, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Panics asserts that the code inside the specified PanicTestFunc panics. +// Panics is the same as [Panics], as a method rather than a package-level function. // -// a.Panics(func(){ GoCrazy() }) -func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Panics(f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Panics(a.t, f, msgAndArgs...) + if assertions.Panics(a.t, f, msgAndArgs...) { + return + } + + a.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. +// Panicsf is the same as [Assertions.Panics], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.PanicsWithError("crazy error", func(){ GoCrazy() }) -func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) Panicsf(f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - PanicsWithError(a.t, errString, f, msgAndArgs...) + if assertions.Panics(a.t, f, forwardArgs(msg, args)) { + return + } + + a.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. +// PanicsWithError is the same as [PanicsWithError], as a method rather than a package-level function. // -// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") -func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) PanicsWithError(errString string, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - PanicsWithErrorf(a.t, errString, f, msg, args...) + if assertions.PanicsWithError(a.t, errString, f, msgAndArgs...) { + return + } + + a.t.FailNow() } -// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that -// the recovered panic value equals the expected panic value. +// PanicsWithErrorf is the same as [Assertions.PanicsWithError], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) -func (a *Assertions) PanicsWithValue(expected any, f assert.PanicTestFunc, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) PanicsWithErrorf(errString string, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - PanicsWithValue(a.t, expected, f, msgAndArgs...) + if assertions.PanicsWithError(a.t, errString, f, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that -// the recovered panic value equals the expected panic value. +// PanicsWithValue is the same as [PanicsWithValue], as a method rather than a package-level function. // -// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") -func (a *Assertions) PanicsWithValuef(expected any, f assert.PanicTestFunc, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) PanicsWithValue(expected any, f assertions.PanicTestFunc, msgAndArgs ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - PanicsWithValuef(a.t, expected, f, msg, args...) + if assertions.PanicsWithValue(a.t, expected, f, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// PanicsWithValuef is the same as [Assertions.PanicsWithValue], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") -func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { +// Upon failure, the test [T] is marked as failed and stops execution. +func (a *Assertions) PanicsWithValuef(expected any, f assertions.PanicTestFunc, msg string, args ...any) { + if h, ok := a.t.(H); ok { h.Helper() } - Panicsf(a.t, f, msg, args...) + if assertions.PanicsWithValue(a.t, expected, f, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Positive asserts that the specified element is positive +// Positive is the same as [Positive], as a method rather than a package-level function. // -// a.Positive(1) -// a.Positive(1.23) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Positive(e any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Positive(a.t, e, msgAndArgs...) + if assertions.Positive(a.t, e, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Positivef asserts that the specified element is positive +// Positivef is the same as [Assertions.Positive], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Positivef(1, "error message %s", "formatted") -// a.Positivef(1.23, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Positivef(e any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Positivef(a.t, e, msg, args...) + if assertions.Positive(a.t, e, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Regexp asserts that a specified regexp matches a string. +// Regexp is the same as [Regexp], as a method rather than a package-level function. // -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Regexp(rx any, str any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Regexp(a.t, rx, str, msgAndArgs...) + if assertions.Regexp(a.t, rx, str, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Regexpf asserts that a specified regexp matches a string. +// Regexpf is the same as [Assertions.Regexp], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Regexpf(rx any, str any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Regexpf(a.t, rx, str, msg, args...) + if assertions.Regexp(a.t, rx, str, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Same asserts that two pointers reference the same object. -// -// a.Same(ptr1, ptr2) +// Same is the same as [Same], as a method rather than a package-level function. // -// Both arguments must be pointer variables. Pointer variable sameness is -// determined based on the equality of both type and value. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Same(expected any, actual any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Same(a.t, expected, actual, msgAndArgs...) + if assertions.Same(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Samef asserts that two pointers reference the same object. -// -// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// Samef is the same as [Assertions.Same], but accepts a format msg string to format arguments like [fmt.Printf]. // -// Both arguments must be pointer variables. Pointer variable sameness is -// determined based on the equality of both type and value. +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Samef(expected any, actual any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Samef(a.t, expected, actual, msg, args...) + if assertions.Same(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.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. +// Subset is the same as [Subset], as a method rather than a package-level function. // -// 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"]) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Subset(list any, subset any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Subset(a.t, list, subset, msgAndArgs...) + if assertions.Subset(a.t, list, subset, msgAndArgs...) { + return + } + + a.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. +// Subsetf is the same as [Assertions.Subset], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Subsetf(list any, subset any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Subsetf(a.t, list, subset, msg, args...) + if assertions.Subset(a.t, list, subset, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// True asserts that the specified value is true. +// True is the same as [True], as a method rather than a package-level function. // -// a.True(myBool) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) True(value bool, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - True(a.t, value, msgAndArgs...) + if assertions.True(a.t, value, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Truef asserts that the specified value is true. +// Truef is the same as [Assertions.True], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.Truef(myBool, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Truef(value bool, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Truef(a.t, value, msg, args...) + if assertions.True(a.t, value, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// WithinDuration asserts that the two times are within duration delta of each other. +// WithinDuration is the same as [WithinDuration], as a method rather than a package-level function. // -// a.WithinDuration(time.Now(), 10*time.Second) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - WithinDuration(a.t, expected, actual, delta, msgAndArgs...) + if assertions.WithinDuration(a.t, expected, actual, delta, msgAndArgs...) { + return + } + + a.t.FailNow() } -// WithinDurationf asserts that the two times are within duration delta of each other. +// WithinDurationf is the same as [Assertions.WithinDuration], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.WithinDurationf(time.Now(), 10*time.Second, "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - WithinDurationf(a.t, expected, actual, delta, msg, args...) + if assertions.WithinDuration(a.t, expected, actual, delta, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// WithinRange asserts that a time is within a time range (inclusive). +// WithinRange is the same as [WithinRange], as a method rather than a package-level function. // -// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - WithinRange(a.t, actual, start, end, msgAndArgs...) + if assertions.WithinRange(a.t, actual, start, end, msgAndArgs...) { + return + } + + a.t.FailNow() } -// WithinRangef asserts that a time is within a time range (inclusive). +// WithinRangef is the same as [Assertions.WithinRange], but accepts a format msg string to format arguments like [fmt.Printf]. // -// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - WithinRangef(a.t, actual, start, end, msg, args...) + if assertions.WithinRange(a.t, actual, start, end, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// YAMLEq is the same as [YAMLEq], as a method rather than a package-level function. // -// 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) +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - YAMLEq(a.t, expected, actual, msgAndArgs...) + if assertions.YAMLEq(a.t, expected, actual, msgAndArgs...) { + return + } + + a.t.FailNow() } -// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// YAMLEqf is the same as [Assertions.YAMLEq], but accepts a format msg string to format arguments like [fmt.Printf]. // -// 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") +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - YAMLEqf(a.t, expected, actual, msg, args...) + if assertions.YAMLEq(a.t, expected, actual, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } -// Zero asserts that i is the zero value for its type. +// Zero is the same as [Zero], as a method rather than a package-level function. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Zero(i any, msgAndArgs ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Zero(a.t, i, msgAndArgs...) + if assertions.Zero(a.t, i, msgAndArgs...) { + return + } + + a.t.FailNow() } -// Zerof asserts that i is the zero value for its type. +// Zerof is the same as [Assertions.Zero], but accepts a format msg string to format arguments like [fmt.Printf]. +// +// Upon failure, the test [T] is marked as failed and stops execution. func (a *Assertions) Zerof(i any, msg string, args ...any) { - if h, ok := a.t.(tHelper); ok { + if h, ok := a.t.(H); ok { h.Helper() } - Zerof(a.t, i, msg, args...) + if assertions.Zero(a.t, i, forwardArgs(msg, args)) { + return + } + + a.t.FailNow() } diff --git a/require/require_forward.go.tmpl b/require/require_forward.go.tmpl deleted file mode 100644 index 54124df1d..000000000 --- a/require/require_forward.go.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -{{.CommentWithoutT "a"}} -func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { - if h, ok := a.t.(tHelper); ok { h.Helper() } - {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) -} diff --git a/require/require_forward_test.go b/require/require_forward_test.go new file mode 100644 index 000000000..4270cb15c --- /dev/null +++ b/require/require_forward_test.go @@ -0,0 +1,3830 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "fmt" + "io" + "net/http" + "net/url" + "path/filepath" + "testing" + "time" +) + +func TestAssertionsCondition(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Condition(func() bool { return true }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Condition(func() bool { return false }) + // require functions don't return a value + if !mock.failed { + t.Error("Condition should call FailNow()") + } + }) +} + +func TestAssertionsConditionf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Conditionf(func() bool { return true }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Conditionf(func() bool { return false }, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Condition should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Conditionf should call FailNow()") + } + }) +} + +func TestAssertionsContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Contains([]string{"A", "B"}, "A") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Contains([]string{"A", "B"}, "C") + // require functions don't return a value + if !mock.failed { + t.Error("Contains should call FailNow()") + } + }) +} + +func TestAssertionsContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Containsf([]string{"A", "B"}, "A", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Containsf([]string{"A", "B"}, "C", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Contains should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Containsf should call FailNow()") + } + }) +} + +func TestAssertionsDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.DirExists(filepath.Join(testDataPath(), "existing_dir")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.DirExists(filepath.Join(testDataPath(), "non_existing_dir")) + // require functions don't return a value + if !mock.failed { + t.Error("DirExists should call FailNow()") + } + }) +} + +func TestAssertionsDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.DirExistsf(filepath.Join(testDataPath(), "existing_dir"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.DirExistsf(filepath.Join(testDataPath(), "non_existing_dir"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.DirExists should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.DirExistsf should call FailNow()") + } + }) +} + +func TestAssertionsElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ElementsMatch([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ElementsMatch([]int{1, 2, 3}, []int{1, 2, 4}) + // require functions don't return a value + if !mock.failed { + t.Error("ElementsMatch should call FailNow()") + } + }) +} + +func TestAssertionsElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ElementsMatchf([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ElementsMatchf([]int{1, 2, 3}, []int{1, 2, 4}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.ElementsMatch should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.ElementsMatchf should call FailNow()") + } + }) +} + +func TestAssertionsEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Empty("") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Empty("not empty") + // require functions don't return a value + if !mock.failed { + t.Error("Empty should call FailNow()") + } + }) +} + +func TestAssertionsEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Emptyf("", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Emptyf("not empty", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Empty should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Emptyf should call FailNow()") + } + }) +} + +func TestAssertionsEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Equal(123, 123) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Equal(123, 456) + // require functions don't return a value + if !mock.failed { + t.Error("Equal should call FailNow()") + } + }) +} + +func TestAssertionsEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Equalf(123, 123, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Equalf(123, 456, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Equal should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Equalf should call FailNow()") + } + }) +} + +func TestAssertionsEqualError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualError(ErrTest, "assert.ErrTest general error for testing") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualError(ErrTest, "wrong error message") + // require functions don't return a value + if !mock.failed { + t.Error("EqualError should call FailNow()") + } + }) +} + +func TestAssertionsEqualErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualErrorf(ErrTest, "assert.ErrTest general error for testing", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualErrorf(ErrTest, "wrong error message", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.EqualError should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.EqualErrorf should call FailNow()") + } + }) +} + +func TestAssertionsEqualExportedValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualExportedValues(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualExportedValues(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}) + // require functions don't return a value + if !mock.failed { + t.Error("EqualExportedValues should call FailNow()") + } + }) +} + +func TestAssertionsEqualExportedValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualExportedValuesf(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "a", b: 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualExportedValuesf(&dummyStruct{A: "a", b: 1}, &dummyStruct{A: "b", b: 1}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.EqualExportedValues should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.EqualExportedValuesf should call FailNow()") + } + }) +} + +func TestAssertionsEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualValues(uint32(123), int32(123)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualValues(uint32(123), int32(456)) + // require functions don't return a value + if !mock.failed { + t.Error("EqualValues should call FailNow()") + } + }) +} + +func TestAssertionsEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EqualValuesf(uint32(123), int32(123), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EqualValuesf(uint32(123), int32(456), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.EqualValues should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.EqualValuesf should call FailNow()") + } + }) +} + +func TestAssertionsError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Error(ErrTest) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Error(nil) + // require functions don't return a value + if !mock.failed { + t.Error("Error should call FailNow()") + } + }) +} + +func TestAssertionsErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Errorf(ErrTest, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Errorf(nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Error should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Errorf should call FailNow()") + } + }) +} + +func TestAssertionsErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorAs(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorAs(ErrTest, new(*dummyError)) + // require functions don't return a value + if !mock.failed { + t.Error("ErrorAs should call FailNow()") + } + }) +} + +func TestAssertionsErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorAsf(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorAsf(ErrTest, new(*dummyError), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.ErrorAs should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.ErrorAsf should call FailNow()") + } + }) +} + +func TestAssertionsErrorContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorContains(ErrTest, "general error") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorContains(ErrTest, "not in message") + // require functions don't return a value + if !mock.failed { + t.Error("ErrorContains should call FailNow()") + } + }) +} + +func TestAssertionsErrorContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorContainsf(ErrTest, "general error", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorContainsf(ErrTest, "not in message", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.ErrorContains should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.ErrorContainsf should call FailNow()") + } + }) +} + +func TestAssertionsErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorIs(fmt.Errorf("wrap: %w", io.EOF), io.EOF) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorIs(ErrTest, io.EOF) + // require functions don't return a value + if !mock.failed { + t.Error("ErrorIs should call FailNow()") + } + }) +} + +func TestAssertionsErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.ErrorIsf(fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.ErrorIsf(ErrTest, io.EOF, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.ErrorIs should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.ErrorIsf should call FailNow()") + } + }) +} + +func TestAssertionsEventually(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Eventually(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Eventually(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("Eventually should call FailNow()") + } + }) +} + +func TestAssertionsEventuallyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Eventuallyf(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Eventuallyf(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Eventually should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Eventuallyf should call FailNow()") + } + }) +} + +func TestAssertionsEventuallyWithT(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EventuallyWithT(func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EventuallyWithT(func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("EventuallyWithT should call FailNow()") + } + }) +} + +func TestAssertionsEventuallyWithTf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.EventuallyWithTf(func(c *CollectT) { True(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.EventuallyWithTf(func(c *CollectT) { False(c, true) }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.EventuallyWithT should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.EventuallyWithTf should call FailNow()") + } + }) +} + +func TestAssertionsExactly(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Exactly(int32(123), int32(123)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Exactly(int32(123), int64(123)) + // require functions don't return a value + if !mock.failed { + t.Error("Exactly should call FailNow()") + } + }) +} + +func TestAssertionsExactlyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Exactlyf(int32(123), int32(123), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Exactlyf(int32(123), int64(123), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Exactly should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Exactlyf should call FailNow()") + } + }) +} + +func TestAssertionsFail(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Fail("failed") + // require functions don't return a value + if !mock.failed { + t.Error("Fail should call FailNow()") + } + }) +} + +func TestAssertionsFailf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Failf("failed", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Fail should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Failf should call FailNow()") + } + }) +} + +func TestAssertionsFailNow(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FailNow("failed") + // require functions don't return a value + if !mock.failed { + t.Error("FailNow should call FailNow()") + } + }) +} + +func TestAssertionsFailNowf(t *testing.T) { + t.Parallel() + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FailNowf("failed", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.FailNow should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.FailNowf should call FailNow()") + } + }) +} + +func TestAssertionsFalse(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.False(1 == 0) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.False(1 == 1) + // require functions don't return a value + if !mock.failed { + t.Error("False should call FailNow()") + } + }) +} + +func TestAssertionsFalsef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Falsef(1 == 0, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Falsef(1 == 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.False should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Falsef should call FailNow()") + } + }) +} + +func TestAssertionsFileEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileEmpty(filepath.Join(testDataPath(), "empty_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileEmpty(filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileEmpty should call FailNow()") + } + }) +} + +func TestAssertionsFileEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileEmptyf(filepath.Join(testDataPath(), "empty_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileEmptyf(filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.FileEmpty should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.FileEmptyf should call FailNow()") + } + }) +} + +func TestAssertionsFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileExists(filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileExists(filepath.Join(testDataPath(), "non_existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileExists should call FailNow()") + } + }) +} + +func TestAssertionsFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileExistsf(filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileExistsf(filepath.Join(testDataPath(), "non_existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.FileExists should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.FileExistsf should call FailNow()") + } + }) +} + +func TestAssertionsFileNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileNotEmpty(filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileNotEmpty(filepath.Join(testDataPath(), "empty_file")) + // require functions don't return a value + if !mock.failed { + t.Error("FileNotEmpty should call FailNow()") + } + }) +} + +func TestAssertionsFileNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.FileNotEmptyf(filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.FileNotEmptyf(filepath.Join(testDataPath(), "empty_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.FileNotEmpty should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.FileNotEmptyf should call FailNow()") + } + }) +} + +func TestAssertionsGreater(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Greater(2, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Greater(1, 2) + // require functions don't return a value + if !mock.failed { + t.Error("Greater should call FailNow()") + } + }) +} + +func TestAssertionsGreaterf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Greaterf(2, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Greaterf(1, 2, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Greater should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Greaterf should call FailNow()") + } + }) +} + +func TestAssertionsGreaterOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.GreaterOrEqual(2, 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.GreaterOrEqual(1, 2) + // require functions don't return a value + if !mock.failed { + t.Error("GreaterOrEqual should call FailNow()") + } + }) +} + +func TestAssertionsGreaterOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.GreaterOrEqualf(2, 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.GreaterOrEqualf(1, 2, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.GreaterOrEqual should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.GreaterOrEqualf should call FailNow()") + } + }) +} + +func TestAssertionsHTTPBodyContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPBodyContains(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPBodyContains(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyContains should call FailNow()") + } + }) +} + +func TestAssertionsHTTPBodyContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPBodyContainsf(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPBodyContainsf(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, World!", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPBodyContains should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPBodyContainsf should call FailNow()") + } + }) +} + +func TestAssertionsHTTPBodyNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPBodyNotContains(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPBodyNotContains(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!") + // require functions don't return a value + if !mock.failed { + t.Error("HTTPBodyNotContains should call FailNow()") + } + }) +} + +func TestAssertionsHTTPBodyNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPBodyNotContainsf(httpBody, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, Bob!", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPBodyNotContainsf(httpBody, "GET", "/", url.Values{"name": []string{"Bob"}}, "Hello, Bob!", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPBodyNotContains should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPBodyNotContainsf should call FailNow()") + } + }) +} + +func TestAssertionsHTTPError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPError(httpError, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPError(httpOK, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPError should call FailNow()") + } + }) +} + +func TestAssertionsHTTPErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPErrorf(httpError, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPErrorf(httpOK, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPError should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPErrorf should call FailNow()") + } + }) +} + +func TestAssertionsHTTPRedirect(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPRedirect(httpRedirect, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPRedirect(httpError, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPRedirect should call FailNow()") + } + }) +} + +func TestAssertionsHTTPRedirectf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPRedirectf(httpRedirect, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPRedirectf(httpError, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPRedirect should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPRedirectf should call FailNow()") + } + }) +} + +func TestAssertionsHTTPStatusCode(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPStatusCode(httpOK, "GET", "/", nil, http.StatusOK) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPStatusCode(httpError, "GET", "/", nil, http.StatusOK) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPStatusCode should call FailNow()") + } + }) +} + +func TestAssertionsHTTPStatusCodef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPStatusCodef(httpOK, "GET", "/", nil, http.StatusOK, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPStatusCodef(httpError, "GET", "/", nil, http.StatusOK, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPStatusCode should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPStatusCodef should call FailNow()") + } + }) +} + +func TestAssertionsHTTPSuccess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPSuccess(httpOK, "GET", "/", nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPSuccess(httpError, "GET", "/", nil) + // require functions don't return a value + if !mock.failed { + t.Error("HTTPSuccess should call FailNow()") + } + }) +} + +func TestAssertionsHTTPSuccessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.HTTPSuccessf(httpOK, "GET", "/", nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.HTTPSuccessf(httpError, "GET", "/", nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.HTTPSuccess should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.HTTPSuccessf should call FailNow()") + } + }) +} + +func TestAssertionsImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Implements(ptr(dummyInterface), new(testing.T)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Implements((*error)(nil), new(testing.T)) + // require functions don't return a value + if !mock.failed { + t.Error("Implements should call FailNow()") + } + }) +} + +func TestAssertionsImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Implementsf(ptr(dummyInterface), new(testing.T), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Implementsf((*error)(nil), new(testing.T), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Implements should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Implementsf should call FailNow()") + } + }) +} + +func TestAssertionsInDelta(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDelta(1.0, 1.01, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDelta(1.0, 1.1, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDelta should call FailNow()") + } + }) +} + +func TestAssertionsInDeltaf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDeltaf(1.0, 1.01, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDeltaf(1.0, 1.1, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.InDelta should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.InDeltaf should call FailNow()") + } + }) +} + +func TestAssertionsInDeltaMapValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDeltaMapValues(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDeltaMapValues(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaMapValues should call FailNow()") + } + }) +} + +func TestAssertionsInDeltaMapValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDeltaMapValuesf(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.01}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDeltaMapValuesf(map[string]float64{"a": 1.0}, map[string]float64{"a": 1.1}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.InDeltaMapValues should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.InDeltaMapValuesf should call FailNow()") + } + }) +} + +func TestAssertionsInDeltaSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDeltaSlice([]float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDeltaSlice([]float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InDeltaSlice should call FailNow()") + } + }) +} + +func TestAssertionsInDeltaSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InDeltaSlicef([]float64{1.0, 2.0}, []float64{1.01, 2.01}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InDeltaSlicef([]float64{1.0, 2.0}, []float64{1.1, 2.1}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.InDeltaSlice should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.InDeltaSlicef should call FailNow()") + } + }) +} + +func TestAssertionsInEpsilon(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InEpsilon(100.0, 101.0, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InEpsilon(100.0, 110.0, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilon should call FailNow()") + } + }) +} + +func TestAssertionsInEpsilonf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InEpsilonf(100.0, 101.0, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InEpsilonf(100.0, 110.0, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.InEpsilon should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.InEpsilonf should call FailNow()") + } + }) +} + +func TestAssertionsInEpsilonSlice(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InEpsilonSlice([]float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InEpsilonSlice([]float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05) + // require functions don't return a value + if !mock.failed { + t.Error("InEpsilonSlice should call FailNow()") + } + }) +} + +func TestAssertionsInEpsilonSlicef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.InEpsilonSlicef([]float64{100.0, 200.0}, []float64{101.0, 202.0}, 0.02, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.InEpsilonSlicef([]float64{100.0, 200.0}, []float64{110.0, 220.0}, 0.05, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.InEpsilonSlice should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.InEpsilonSlicef should call FailNow()") + } + }) +} + +func TestAssertionsIsDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsDecreasing([]int{3, 2, 1}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsDecreasing([]int{1, 2, 3}) + // require functions don't return a value + if !mock.failed { + t.Error("IsDecreasing should call FailNow()") + } + }) +} + +func TestAssertionsIsDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsDecreasingf([]int{3, 2, 1}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsDecreasingf([]int{1, 2, 3}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsDecreasing should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsDecreasingf should call FailNow()") + } + }) +} + +func TestAssertionsIsIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsIncreasing([]int{1, 2, 3}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsIncreasing([]int{1, 1, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("IsIncreasing should call FailNow()") + } + }) +} + +func TestAssertionsIsIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsIncreasingf([]int{1, 2, 3}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsIncreasingf([]int{1, 1, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsIncreasing should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsIncreasingf should call FailNow()") + } + }) +} + +func TestAssertionsIsNonDecreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNonDecreasing([]int{1, 1, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNonDecreasing([]int{2, 1, 1}) + // require functions don't return a value + if !mock.failed { + t.Error("IsNonDecreasing should call FailNow()") + } + }) +} + +func TestAssertionsIsNonDecreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNonDecreasingf([]int{1, 1, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNonDecreasingf([]int{2, 1, 1}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsNonDecreasing should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsNonDecreasingf should call FailNow()") + } + }) +} + +func TestAssertionsIsNonIncreasing(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNonIncreasing([]int{2, 1, 1}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNonIncreasing([]int{1, 2, 3}) + // require functions don't return a value + if !mock.failed { + t.Error("IsNonIncreasing should call FailNow()") + } + }) +} + +func TestAssertionsIsNonIncreasingf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNonIncreasingf([]int{2, 1, 1}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNonIncreasingf([]int{1, 2, 3}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsNonIncreasing should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsNonIncreasingf should call FailNow()") + } + }) +} + +func TestAssertionsIsNotType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNotType(int32(123), int64(456)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNotType(123, 456) + // require functions don't return a value + if !mock.failed { + t.Error("IsNotType should call FailNow()") + } + }) +} + +func TestAssertionsIsNotTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsNotTypef(int32(123), int64(456), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsNotTypef(123, 456, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsNotType should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsNotTypef should call FailNow()") + } + }) +} + +func TestAssertionsIsType(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsType(123, 456) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsType(int32(123), int64(456)) + // require functions don't return a value + if !mock.failed { + t.Error("IsType should call FailNow()") + } + }) +} + +func TestAssertionsIsTypef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.IsTypef(123, 456, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.IsTypef(int32(123), int64(456), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.IsType should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.IsTypef should call FailNow()") + } + }) +} + +func TestAssertionsJSONEq(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.JSONEq(`{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`) + // require functions don't return a value + if !mock.failed { + t.Error("JSONEq should call FailNow()") + } + }) +} + +func TestAssertionsJSONEqf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `[{"foo": "bar"}, {"hello": "world"}]`, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.JSONEq should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.JSONEqf should call FailNow()") + } + }) +} + +func TestAssertionsJSONEqBytes(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.JSONEqBytes([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`)) + // require functions don't return a value + if !mock.failed { + t.Error("JSONEqBytes should call FailNow()") + } + }) +} + +func TestAssertionsJSONEqBytesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`{"foo": "bar", "hello": "world"}`), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.JSONEqBytesf([]byte(`{"hello": "world", "foo": "bar"}`), []byte(`[{"foo": "bar"}, {"hello": "world"}]`), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.JSONEqBytes should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.JSONEqBytesf should call FailNow()") + } + }) +} + +func TestAssertionsLen(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Len([]string{"A", "B"}, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Len([]string{"A", "B"}, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Len should call FailNow()") + } + }) +} + +func TestAssertionsLenf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Lenf([]string{"A", "B"}, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Lenf([]string{"A", "B"}, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Len should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Lenf should call FailNow()") + } + }) +} + +func TestAssertionsLess(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Less(1, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Less(2, 1) + // require functions don't return a value + if !mock.failed { + t.Error("Less should call FailNow()") + } + }) +} + +func TestAssertionsLessf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Lessf(1, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Lessf(2, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Less should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Lessf should call FailNow()") + } + }) +} + +func TestAssertionsLessOrEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.LessOrEqual(1, 2) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.LessOrEqual(2, 1) + // require functions don't return a value + if !mock.failed { + t.Error("LessOrEqual should call FailNow()") + } + }) +} + +func TestAssertionsLessOrEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.LessOrEqualf(1, 2, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.LessOrEqualf(2, 1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.LessOrEqual should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.LessOrEqualf should call FailNow()") + } + }) +} + +func TestAssertionsNegative(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Negative(-1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Negative(1) + // require functions don't return a value + if !mock.failed { + t.Error("Negative should call FailNow()") + } + }) +} + +func TestAssertionsNegativef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Negativef(-1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Negativef(1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Negative should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Negativef should call FailNow()") + } + }) +} + +func TestAssertionsNever(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Never(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Never(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond) + // require functions don't return a value + if !mock.failed { + t.Error("Never should call FailNow()") + } + }) +} + +func TestAssertionsNeverf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Neverf(func() bool { return false }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Neverf(func() bool { return true }, 100*time.Millisecond, 20*time.Millisecond, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Never should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Neverf should call FailNow()") + } + }) +} + +func TestAssertionsNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Nil(nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Nil("not nil") + // require functions don't return a value + if !mock.failed { + t.Error("Nil should call FailNow()") + } + }) +} + +func TestAssertionsNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Nilf(nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Nilf("not nil", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Nil should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Nilf should call FailNow()") + } + }) +} + +func TestAssertionsNoDirExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoDirExists(filepath.Join(testDataPath(), "non_existing_dir")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoDirExists(filepath.Join(testDataPath(), "existing_dir")) + // require functions don't return a value + if !mock.failed { + t.Error("NoDirExists should call FailNow()") + } + }) +} + +func TestAssertionsNoDirExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoDirExistsf(filepath.Join(testDataPath(), "non_existing_dir"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoDirExistsf(filepath.Join(testDataPath(), "existing_dir"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NoDirExists should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NoDirExistsf should call FailNow()") + } + }) +} + +func TestAssertionsNoError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoError(nil) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoError(ErrTest) + // require functions don't return a value + if !mock.failed { + t.Error("NoError should call FailNow()") + } + }) +} + +func TestAssertionsNoErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoErrorf(nil, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoErrorf(ErrTest, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NoError should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NoErrorf should call FailNow()") + } + }) +} + +func TestAssertionsNoFileExists(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoFileExists(filepath.Join(testDataPath(), "non_existing_file")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoFileExists(filepath.Join(testDataPath(), "existing_file")) + // require functions don't return a value + if !mock.failed { + t.Error("NoFileExists should call FailNow()") + } + }) +} + +func TestAssertionsNoFileExistsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NoFileExistsf(filepath.Join(testDataPath(), "non_existing_file"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NoFileExistsf(filepath.Join(testDataPath(), "existing_file"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NoFileExists should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NoFileExistsf should call FailNow()") + } + }) +} + +func TestAssertionsNotContains(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotContains([]string{"A", "B"}, "C") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotContains([]string{"A", "B"}, "B") + // require functions don't return a value + if !mock.failed { + t.Error("NotContains should call FailNow()") + } + }) +} + +func TestAssertionsNotContainsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotContainsf([]string{"A", "B"}, "C", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotContainsf([]string{"A", "B"}, "B", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotContains should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotContainsf should call FailNow()") + } + }) +} + +func TestAssertionsNotElementsMatch(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotElementsMatch([]int{1, 2, 3}, []int{1, 2, 4}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotElementsMatch([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("NotElementsMatch should call FailNow()") + } + }) +} + +func TestAssertionsNotElementsMatchf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotElementsMatchf([]int{1, 2, 3}, []int{1, 2, 4}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotElementsMatchf([]int{1, 3, 2, 3}, []int{1, 3, 3, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotElementsMatch should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotElementsMatchf should call FailNow()") + } + }) +} + +func TestAssertionsNotEmpty(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEmpty("not empty") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEmpty("") + // require functions don't return a value + if !mock.failed { + t.Error("NotEmpty should call FailNow()") + } + }) +} + +func TestAssertionsNotEmptyf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEmptyf("not empty", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEmptyf("", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotEmpty should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotEmptyf should call FailNow()") + } + }) +} + +func TestAssertionsNotEqual(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEqual(123, 456) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEqual(123, 123) + // require functions don't return a value + if !mock.failed { + t.Error("NotEqual should call FailNow()") + } + }) +} + +func TestAssertionsNotEqualf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEqualf(123, 456, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEqualf(123, 123, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotEqual should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotEqualf should call FailNow()") + } + }) +} + +func TestAssertionsNotEqualValues(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEqualValues(uint32(123), int32(456)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEqualValues(uint32(123), int32(123)) + // require functions don't return a value + if !mock.failed { + t.Error("NotEqualValues should call FailNow()") + } + }) +} + +func TestAssertionsNotEqualValuesf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotEqualValuesf(uint32(123), int32(456), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotEqualValuesf(uint32(123), int32(123), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotEqualValues should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotEqualValuesf should call FailNow()") + } + }) +} + +func TestAssertionsNotErrorAs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotErrorAs(ErrTest, new(*dummyError)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotErrorAs(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError)) + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorAs should call FailNow()") + } + }) +} + +func TestAssertionsNotErrorAsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotErrorAsf(ErrTest, new(*dummyError), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotErrorAsf(fmt.Errorf("wrap: %w", &dummyError{}), new(*dummyError), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotErrorAs should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotErrorAsf should call FailNow()") + } + }) +} + +func TestAssertionsNotErrorIs(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotErrorIs(ErrTest, io.EOF) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotErrorIs(fmt.Errorf("wrap: %w", io.EOF), io.EOF) + // require functions don't return a value + if !mock.failed { + t.Error("NotErrorIs should call FailNow()") + } + }) +} + +func TestAssertionsNotErrorIsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotErrorIsf(ErrTest, io.EOF, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotErrorIsf(fmt.Errorf("wrap: %w", io.EOF), io.EOF, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotErrorIs should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotErrorIsf should call FailNow()") + } + }) +} + +func TestAssertionsNotImplements(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotImplements((*error)(nil), new(testing.T)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotImplements(ptr(dummyInterface), new(testing.T)) + // require functions don't return a value + if !mock.failed { + t.Error("NotImplements should call FailNow()") + } + }) +} + +func TestAssertionsNotImplementsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotImplementsf((*error)(nil), new(testing.T), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotImplementsf(ptr(dummyInterface), new(testing.T), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotImplements should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotImplementsf should call FailNow()") + } + }) +} + +func TestAssertionsNotNil(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotNil("not nil") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotNil(nil) + // require functions don't return a value + if !mock.failed { + t.Error("NotNil should call FailNow()") + } + }) +} + +func TestAssertionsNotNilf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotNilf("not nil", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotNilf(nil, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotNil should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotNilf should call FailNow()") + } + }) +} + +func TestAssertionsNotPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotPanics(func() {}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotPanics(func() { panic("panicking") }) + // require functions don't return a value + if !mock.failed { + t.Error("NotPanics should call FailNow()") + } + }) +} + +func TestAssertionsNotPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotPanicsf(func() {}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotPanicsf(func() { panic("panicking") }, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotPanics should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotPanicsf should call FailNow()") + } + }) +} + +func TestAssertionsNotRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotRegexp("^start", "not starting") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotRegexp("^start", "starting") + // require functions don't return a value + if !mock.failed { + t.Error("NotRegexp should call FailNow()") + } + }) +} + +func TestAssertionsNotRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotRegexpf("^start", "not starting", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotRegexpf("^start", "starting", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotRegexp should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotRegexpf should call FailNow()") + } + }) +} + +func TestAssertionsNotSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotSame(&staticVar, ptr("static string")) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotSame(&staticVar, staticVarPtr) + // require functions don't return a value + if !mock.failed { + t.Error("NotSame should call FailNow()") + } + }) +} + +func TestAssertionsNotSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotSamef(&staticVar, ptr("static string"), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotSamef(&staticVar, staticVarPtr, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotSame should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotSamef should call FailNow()") + } + }) +} + +func TestAssertionsNotSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotSubset([]int{1, 2, 3}, []int{4, 5}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotSubset([]int{1, 2, 3}, []int{1, 2}) + // require functions don't return a value + if !mock.failed { + t.Error("NotSubset should call FailNow()") + } + }) +} + +func TestAssertionsNotSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotSubsetf([]int{1, 2, 3}, []int{4, 5}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotSubsetf([]int{1, 2, 3}, []int{1, 2}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotSubset should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotSubsetf should call FailNow()") + } + }) +} + +func TestAssertionsNotZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotZero(1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotZero(0) + // require functions don't return a value + if !mock.failed { + t.Error("NotZero should call FailNow()") + } + }) +} + +func TestAssertionsNotZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.NotZerof(1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.NotZerof(0, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.NotZero should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.NotZerof should call FailNow()") + } + }) +} + +func TestAssertionsPanics(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { panic("panicking") }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Panics(func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("Panics should call FailNow()") + } + }) +} + +func TestAssertionsPanicsf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panicsf(func() { panic("panicking") }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Panicsf(func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Panics should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Panicsf should call FailNow()") + } + }) +} + +func TestAssertionsPanicsWithError(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.PanicsWithError(ErrTest.Error(), func() { panic(ErrTest) }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.PanicsWithError(ErrTest.Error(), func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithError should call FailNow()") + } + }) +} + +func TestAssertionsPanicsWithErrorf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.PanicsWithErrorf(ErrTest.Error(), func() { panic(ErrTest) }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.PanicsWithErrorf(ErrTest.Error(), func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.PanicsWithError should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.PanicsWithErrorf should call FailNow()") + } + }) +} + +func TestAssertionsPanicsWithValue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.PanicsWithValue("panicking", func() { panic("panicking") }) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.PanicsWithValue("panicking", func() {}) + // require functions don't return a value + if !mock.failed { + t.Error("PanicsWithValue should call FailNow()") + } + }) +} + +func TestAssertionsPanicsWithValuef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.PanicsWithValuef("panicking", func() { panic("panicking") }, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.PanicsWithValuef("panicking", func() {}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.PanicsWithValue should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.PanicsWithValuef should call FailNow()") + } + }) +} + +func TestAssertionsPositive(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Positive(1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Positive(-1) + // require functions don't return a value + if !mock.failed { + t.Error("Positive should call FailNow()") + } + }) +} + +func TestAssertionsPositivef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Positivef(1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Positivef(-1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Positive should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Positivef should call FailNow()") + } + }) +} + +func TestAssertionsRegexp(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Regexp("^start", "starting") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Regexp("^start", "not starting") + // require functions don't return a value + if !mock.failed { + t.Error("Regexp should call FailNow()") + } + }) +} + +func TestAssertionsRegexpf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Regexpf("^start", "starting", "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Regexpf("^start", "not starting", "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Regexp should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Regexpf should call FailNow()") + } + }) +} + +func TestAssertionsSame(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Same(&staticVar, staticVarPtr) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Same(&staticVar, ptr("static string")) + // require functions don't return a value + if !mock.failed { + t.Error("Same should call FailNow()") + } + }) +} + +func TestAssertionsSamef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Samef(&staticVar, staticVarPtr, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Samef(&staticVar, ptr("static string"), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Same should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Samef should call FailNow()") + } + }) +} + +func TestAssertionsSubset(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Subset([]int{1, 2, 3}, []int{1, 2}) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Subset([]int{1, 2, 3}, []int{4, 5}) + // require functions don't return a value + if !mock.failed { + t.Error("Subset should call FailNow()") + } + }) +} + +func TestAssertionsSubsetf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Subsetf([]int{1, 2, 3}, []int{1, 2}, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Subsetf([]int{1, 2, 3}, []int{4, 5}, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Subset should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Subsetf should call FailNow()") + } + }) +} + +func TestAssertionsTrue(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.True(1 == 1) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.True(1 == 0) + // require functions don't return a value + if !mock.failed { + t.Error("True should call FailNow()") + } + }) +} + +func TestAssertionsTruef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Truef(1 == 1, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Truef(1 == 0, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.True should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Truef should call FailNow()") + } + }) +} + +func TestAssertionsWithinDuration(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.WithinDuration(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.WithinDuration(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second) + // require functions don't return a value + if !mock.failed { + t.Error("WithinDuration should call FailNow()") + } + }) +} + +func TestAssertionsWithinDurationf(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.WithinDurationf(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 1, 0, time.UTC), 2*time.Second, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.WithinDurationf(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 12, 0, 10, 0, time.UTC), 1*time.Second, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.WithinDuration should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.WithinDurationf should call FailNow()") + } + }) +} + +func TestAssertionsWithinRange(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.WithinRange(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.WithinRange(time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC)) + // require functions don't return a value + if !mock.failed { + t.Error("WithinRange should call FailNow()") + } + }) +} + +func TestAssertionsWithinRangef(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.WithinRangef(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.WithinRangef(time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 11, 0, 0, 0, time.UTC), time.Date(2024, 1, 1, 13, 0, 0, 0, time.UTC), "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.WithinRange should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.WithinRangef should call FailNow()") + } + }) +} + +func TestAssertionsYAMLEq(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.YAMLEq("key: value", "key: value") + }, "should panic without the yaml feature enabled") + }) +} + +func TestAssertionsYAMLEqf(t *testing.T) { + t.Parallel() + t.Run("panic", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Panics(func() { + a.YAMLEqf("key: value", "key: value", "test message") + }, "should panic without the yaml feature enabled") + }) +} + +func TestAssertionsZero(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Zero(0) + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Zero(1) + // require functions don't return a value + if !mock.failed { + t.Error("Zero should call FailNow()") + } + }) +} + +func TestAssertionsZerof(t *testing.T) { + t.Parallel() + t.Run("success", func(t *testing.T) { + t.Parallel() + + a := New(t) + a.Zerof(0, "test message") + // require functions don't return a value + }) + + t.Run("failure", func(t *testing.T) { + t.Parallel() + + mock := new(mockFailNowT) + a := New(mock) + a.Zerof(1, "test message") + // require functions don't return a value + if !mock.failed { + t.Error("Assertions.Zero should mark test as failed") + } + if !mock.failed { + t.Error("Assertions.Zerof should call FailNow()") + } + }) +} diff --git a/require/require_helpers.go b/require/require_helpers.go new file mode 100644 index 000000000..0b0a7f093 --- /dev/null +++ b/require/require_helpers.go @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "net/http" + "net/url" + + "github.com/go-openapi/testify/v2/internal/assertions" +) + +// 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 { + return assertions.CallerInfo() +} + +// HTTPBody is a helper that returns the HTTP body of the response. +// It returns the empty string if building a new request fails. +func HTTPBody(handler http.HandlerFunc, method string, url string, values url.Values) string { + return assertions.HTTPBody(handler, method, url, values) +} + +// ObjectsAreEqual determines if two objects are considered equal. +// +// This function does no assertion of any kind. +func ObjectsAreEqual(expected any, actual any) bool { + return assertions.ObjectsAreEqual(expected, actual) +} + +// ObjectsAreEqualValues gets whether two objects are equal, or if their +// values are equal. +func ObjectsAreEqualValues(expected any, actual any) bool { + return assertions.ObjectsAreEqualValues(expected, actual) +} + +// 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 any, actual any) bool { + return assertions.ObjectsExportedFieldsAreEqual(expected, actual) +} diff --git a/require/require_helpers_test.go b/require/require_helpers_test.go new file mode 100644 index 000000000..1ef368de7 --- /dev/null +++ b/require/require_helpers_test.go @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "testing" +) + +func TestCallerInfof(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestHTTPBodyf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsAreEqualf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsAreEqualValuesf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} + +func TestObjectsExportedFieldsAreEqualf(t *testing.T) { + t.Skip() // this function doesn't have tests yet +} diff --git a/require/require_types.go b/require/require_types.go new file mode 100644 index 000000000..6c13db3cd --- /dev/null +++ b/require/require_types.go @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +// Code generated with github.com/go-openapi/testify/v2/codegen@master [sha: bb2c19fba6c03f46cb643b3bcdc1d647ea1453ab]; DO NOT EDIT. + +package require + +import ( + "github.com/go-openapi/testify/v2/internal/assertions" +) + +var ( + // ErrTest 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. + ErrTest = assertions.ErrTest +) + +type ( + // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful + // for table driven tests. + BoolAssertionFunc func(T, bool, ...any) + + // CollectT implements the T interface and collects all errors. + CollectT = assertions.CollectT + + // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it. + CompareType = assertions.CompareType + + // Comparison is a custom function that returns true on success and false on failure. + Comparison = assertions.Comparison + + // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful + // for table driven tests. + ComparisonAssertionFunc func(T, any, any, ...any) + + // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful + // for table driven tests. + ErrorAssertionFunc func(T, error, ...any) + + // H is an interface for types that implement the Helper method. + // This allows marking functions as test helpers. + H = assertions.H + + // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful + // for table driven tests. + PanicAssertionFunc func(t T, f assertions.PanicTestFunc, msgAndArgs ...any) + + // 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. + PanicTestFunc = assertions.PanicTestFunc + + // T is an interface wrapper around [testing.T]. + T interface { + assertions.T + FailNow() + } + + // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful + // for table driven tests. + ValueAssertionFunc func(T, any, ...any) +) + +// Type declarations for backward compatibility. +type ( + // TestingT is like [T] and is declared here to remain compatible with previous versions of this package. + // + // Most users should not be affected, as the implementation of [T] that is widely used is [testing.T]. + // + // Deprecated: use [T] as a more concise alternative. + TestingT = T +) diff --git a/require/requirements.go b/require/requirements.go deleted file mode 100644 index 290110e7d..000000000 --- a/require/requirements.go +++ /dev/null @@ -1,29 +0,0 @@ -package require - -// TestingT is an interface wrapper around *testing.T. -type TestingT interface { - Errorf(format string, args ...any) - 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, any, any, ...any) - -// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful -// for table driven tests. -type ValueAssertionFunc func(TestingT, any, ...any) - -// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful -// for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...any) - -// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful -// for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...any) - -//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/require/requirements_test.go b/require/requirements_test.go deleted file mode 100644 index 240557a0d..000000000 --- a/require/requirements_test.go +++ /dev/null @@ -1,561 +0,0 @@ -package require - -import ( - "errors" - "fmt" - "testing" - "time" - - "github.com/go-openapi/testify/v2/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 ...any) { - _, _ = 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, someError()) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestError(t *testing.T) { - t.Parallel() - - Error(t, someError()) - - mockT := new(MockT) - Error(mockT, nil) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestErrorContains(t *testing.T) { - t.Parallel() - - ErrorContains(t, fmt.Errorf("some error: another error: %w", errSentinel), "some error") - - mockT := new(MockT) - ErrorContains(mockT, someError(), "different error") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqualError(t *testing.T) { - t.Parallel() - - EqualError(t, someError(), "some error: test error") - - mockT := new(MockT) - EqualError(mockT, someError(), "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, simpleJSONObject, simpleJSONObject) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_EquivalentButNotEqual(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, simpleJSONObject, simpleJSONObjectReversed) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, nestedJSONObject, nestedJSONObjectShuffled) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_Array(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, simpleJSONNested, simpleJSONNestedReversed) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, simpleJSONNested, simpleJSONNestedNotEq) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_HashesNotEquivalent(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, fooBarObject, simpleJSONObjectReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ActualIsNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, fooBarObject, notJSONString) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, notJSONString, simpleJSONObjectReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, notJSONString, notJSONString) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { - t.Parallel() - - mockT := new(MockT) - JSONEq(mockT, simpleJSONArray, simpleJSONArrayReversed) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestComparisonAssertionFunc(t *testing.T) { - t.Parallel() - - type iface interface { - Name() string - } - - tests := []struct { - name string - expect any - got any - 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 TestValueAssertionFunc(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - value any - 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 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 TestErrorAssertionFunc(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - err error - assertion ErrorAssertionFunc - }{ - {"noError", nil, NoError}, - {"error", fmt.Errorf("whoops: %w", errSentinel), 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++ - }() - 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") -} - -var errSentinel = errors.New("test error") - -func someError() error { - return fmt.Errorf("some error: %w", errSentinel) -}