From e378d7d936b317a25a5c0ec9385cc14494bb2f3f Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Sun, 14 Dec 2025 14:39:36 +0100 Subject: [PATCH] feat: complete code generation architecture for assert/require packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inverts the generation model: internal/assertions is now the single source of truth, with assert/ and require/ packages fully generated including all variants (format, forward, tests, examples). Architecture: - Scanner: AST/types analysis extracts functions, signatures, and test examples - Generator: Template-based generation of 76 functions × 8 variants = 608 functions - Model: Structured representation bridging scanner and generator Key improvements: - Example-driven test generation from godoc "Examples:" sections - Achieves ~100% coverage in generated packages (99.5% - 0.5% gap from helpers) - Modern Go 1.23 iterator-based table-driven tests throughout - Domain-organized source (boolean, collection, compare, equal, error, etc.) - Function type detection for proper generation of type/var function signatures - Comprehensive documentation (MAINTAINERS.md, CLAUDE.md) - Codegen smoke tests (24.4% coverage) Generated packages: - assert/require: assertions, format variants, forward methods - All with corresponding tests and runnable examples - Helper types and interfaces This replaces the previous semi-hand-written/semi-generated approach where adding a single assertion required manually updating 6+ files that already had thousands of lines. Now: write once in internal/assertions/ in small focused source files, run go generate, done. Trade-off: the existing code generator has been rewritten entirely. The new one is more complex, but also more readable. This added (mostly stable) complexity should be outweighted by the simplification of the assertion development workflow. Signed-off-by: Frederic BIDON ci: enforced Windows TMP to reside on the same drive Signed-off-by: Frederic BIDON --- .claude/CLAUDE.md | 271 +- .codecov.yml | 2 +- .github/CONTRIBUTING.md | 234 +- .github/DCO.md | 40 + .github/workflows/go-test.yml | 10 + README.md | 9 +- SECURITY.md | 19 + _codegen/.gitignore | 1 - _codegen/go.mod | 3 - _codegen/internal/imports/LICENSE | 21 - _codegen/internal/imports/imports.go | 114 - _codegen/main.go | 344 -- assert/assert_adhoc_example_1_test.go | 49 + assert/assert_adhoc_example_2_test.go | 48 + assert/assert_adhoc_example_3_test.go | 44 + assert/assert_adhoc_example_4_test.go | 46 + assert/assert_adhoc_example_5_test.go | 38 + assert/assert_assertions.go | 1482 ++++++ assert/assert_assertions_test.go | 1956 ++++++++ assert/assert_examples_test.go | 688 +++ assert/assert_format.go | 812 ++++ assert/assert_format_test.go | 1883 ++++++++ assert/assert_forward.go | 1610 +++++++ assert/assert_forward_test.go | 4215 +++++++++++++++++ assert/assert_helpers.go | 50 + assert/assert_helpers_test.go | 30 + assert/assert_types.go | 71 + assert/assertion_compare_test.go | 474 -- assert/assertion_format.go | 906 ---- assert/assertion_format.go.tmpl | 5 - assert/assertion_forward.go | 1803 ------- assert/assertion_forward.go.tmpl | 5 - assert/assertions.go | 2402 ---------- assert/assertions_test.go | 4159 ---------------- assert/doc.go | 49 - assert/enable/yaml/enable_yaml.go | 23 + assert/errors.go | 12 - assert/examples_test.go | 135 - assert/forward_assertions.go | 16 - assert/forward_assertions_test.go | 725 --- assert/http_assertions_test.go | 232 - assert/yaml/yaml_default.go | 29 - codegen/.gitignore | 1 + codegen/go.mod | 15 + codegen/go.sum | 10 + codegen/internal/generator/doc.go | 8 + codegen/internal/generator/funcmap.go | 201 + codegen/internal/generator/generator.go | 444 ++ codegen/internal/generator/generator_test.go | 256 + codegen/internal/generator/options.go | 107 + .../templates/assertion_assertions.gotmpl | 29 + .../assertion_assertions_test.gotmpl | 150 + .../templates/assertion_examples_test.gotmpl | 108 + .../templates/assertion_format.gotmpl | 35 + .../templates/assertion_format_test.gotmpl | 78 + .../templates/assertion_forward.gotmpl | 51 + .../templates/assertion_forward_test.gotmpl | 147 + .../templates/assertion_helpers.gotmpl | 22 + .../templates/assertion_helpers_test.gotmpl | 26 + .../templates/assertion_types.gotmpl | 73 + .../templates/requirement_assertions.gotmpl | 35 + .../templates/requirement_format.gotmpl | 43 + .../templates/requirement_forward.gotmpl | 69 + codegen/internal/model/model.go | 160 + codegen/internal/scanner/doc.go | 10 + codegen/internal/scanner/options.go | 38 + codegen/internal/scanner/scanner.go | 646 +++ codegen/internal/scanner/scanner_test.go | 34 + codegen/main.go | 88 + codegen/main_test.go | 152 + doc.go | 45 +- docs/EXAMPLES_STATUS.md | 148 + docs/MAINTAINERS.md | 315 ++ original.md => docs/ORIGINAL.md | 0 docs/STYLE.md | 83 + enable/yaml/enable_yaml.go | 4 +- enable/yaml/go.mod | 2 +- go.work | 2 +- go.work.sum | 4 + internal/assertions/assertion.go | 16 + internal/assertions/assertion_test.go | 21 + internal/assertions/benchmarks_test.go | 40 + internal/assertions/boolean.go | 46 + internal/assertions/boolean_test.go | 37 + internal/assertions/collection.go | 442 ++ internal/assertions/collection_impl_test.go | 130 + internal/assertions/collection_test.go | 555 +++ .../assertions/compare.go | 102 +- internal/assertions/compare_impl_test.go | 229 + internal/assertions/compare_test.go | 312 ++ internal/assertions/condition.go | 228 + internal/assertions/condition_test.go | 228 + internal/assertions/doc.go | 10 + internal/assertions/embed_test.go | 16 + internal/assertions/enable/doc.go | 3 + .../assertions/enable/yaml/enable_yaml.go | 34 + internal/assertions/equal.go | 500 ++ internal/assertions/equal_impl_test.go | 209 + internal/assertions/equal_test.go | 745 +++ internal/assertions/error.go | 261 + internal/assertions/error_test.go | 460 ++ internal/assertions/file.go | 174 + internal/assertions/file_test.go | 161 + internal/assertions/helpers.go | 88 + internal/assertions/helpers_impl_test.go | 273 ++ internal/assertions/helpers_test.go | 4 + .../assertions/http.go | 66 +- internal/assertions/http_test.go | 221 + internal/assertions/ifaces.go | 23 + internal/assertions/ifaces_test.go | 18 + internal/assertions/json.go | 52 + internal/assertions/json_test.go | 138 + internal/assertions/mock_test.go | 183 + internal/assertions/number.go | 254 + internal/assertions/number_test.go | 235 + internal/assertions/object.go | 88 + internal/assertions/object_test.go | 456 ++ .../assertions/order.go | 51 +- .../assertions/order_test.go | 69 +- internal/assertions/panic.go | 140 + internal/assertions/panic_test.go | 167 + internal/assertions/spew.go | 28 + internal/assertions/string.go | 73 + internal/assertions/string_test.go | 180 + .../assertions}/testdata/empty_file | 0 .../assertions/testdata/existing_dir/.gitkeep | 0 internal/assertions/testdata/existing_file | 1 + .../assertions/testdata/json/fixtures.json | 19 + internal/assertions/testing.go | 248 + internal/assertions/testing_test.go | 24 + internal/assertions/time.go | 56 + internal/assertions/time_test.go | 60 + internal/assertions/type.go | 129 + internal/assertions/type_test.go | 218 + .../assertions}/unsafetests/doc.go | 0 .../unsafetests/unsafetests_test.go | 29 +- internal/assertions/yaml.go | 52 + internal/assertions/yaml_test.go | 20 + require/assert_adhoc_example_1_test.go | 49 + require/assert_adhoc_example_2_test.go | 48 + require/assert_adhoc_example_3_test.go | 44 + require/assert_adhoc_example_4_test.go | 46 + require/assert_adhoc_example_5_test.go | 38 + require/examples_test.go | 126 - require/fixtures_test.go | 26 - require/forward_requirements.go | 16 - require/forward_requirements_test.go | 476 -- require/require.go | 2278 --------- require/require.go.tmpl | 6 - require/require_assertions.go | 1794 +++++++ require/require_assertions_test.go | 1648 +++++++ require/require_examples_test.go | 688 +++ require/require_format.go | 1124 +++++ require/require_format_test.go | 1575 ++++++ require/require_forward.go | 2290 +++++---- require/require_forward.go.tmpl | 5 - require/require_forward_test.go | 3830 +++++++++++++++ require/require_helpers.go | 50 + require/require_helpers_test.go | 30 + require/require_types.go | 74 + require/requirements.go | 29 - require/requirements_test.go | 561 --- 162 files changed, 38111 insertions(+), 16066 deletions(-) create mode 100644 .github/DCO.md create mode 100644 SECURITY.md delete mode 100644 _codegen/.gitignore delete mode 100644 _codegen/go.mod delete mode 100644 _codegen/internal/imports/LICENSE delete mode 100644 _codegen/internal/imports/imports.go delete mode 100644 _codegen/main.go create mode 100644 assert/assert_adhoc_example_1_test.go create mode 100644 assert/assert_adhoc_example_2_test.go create mode 100644 assert/assert_adhoc_example_3_test.go create mode 100644 assert/assert_adhoc_example_4_test.go create mode 100644 assert/assert_adhoc_example_5_test.go create mode 100644 assert/assert_assertions.go create mode 100644 assert/assert_assertions_test.go create mode 100644 assert/assert_examples_test.go create mode 100644 assert/assert_format.go create mode 100644 assert/assert_format_test.go create mode 100644 assert/assert_forward.go create mode 100644 assert/assert_forward_test.go create mode 100644 assert/assert_helpers.go create mode 100644 assert/assert_helpers_test.go create mode 100644 assert/assert_types.go delete mode 100644 assert/assertion_compare_test.go delete mode 100644 assert/assertion_format.go delete mode 100644 assert/assertion_format.go.tmpl delete mode 100644 assert/assertion_forward.go delete mode 100644 assert/assertion_forward.go.tmpl delete mode 100644 assert/assertions.go delete mode 100644 assert/assertions_test.go create mode 100644 assert/enable/yaml/enable_yaml.go delete mode 100644 assert/errors.go delete mode 100644 assert/examples_test.go delete mode 100644 assert/forward_assertions.go delete mode 100644 assert/forward_assertions_test.go delete mode 100644 assert/http_assertions_test.go delete mode 100644 assert/yaml/yaml_default.go create mode 100644 codegen/.gitignore create mode 100644 codegen/go.mod create mode 100644 codegen/go.sum create mode 100644 codegen/internal/generator/doc.go create mode 100644 codegen/internal/generator/funcmap.go create mode 100644 codegen/internal/generator/generator.go create mode 100644 codegen/internal/generator/generator_test.go create mode 100644 codegen/internal/generator/options.go create mode 100644 codegen/internal/generator/templates/assertion_assertions.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_assertions_test.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_examples_test.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_format.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_format_test.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_forward.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_forward_test.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_helpers.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_helpers_test.gotmpl create mode 100644 codegen/internal/generator/templates/assertion_types.gotmpl create mode 100644 codegen/internal/generator/templates/requirement_assertions.gotmpl create mode 100644 codegen/internal/generator/templates/requirement_format.gotmpl create mode 100644 codegen/internal/generator/templates/requirement_forward.gotmpl create mode 100644 codegen/internal/model/model.go create mode 100644 codegen/internal/scanner/doc.go create mode 100644 codegen/internal/scanner/options.go create mode 100644 codegen/internal/scanner/scanner.go create mode 100644 codegen/internal/scanner/scanner_test.go create mode 100644 codegen/main.go create mode 100644 codegen/main_test.go create mode 100644 docs/EXAMPLES_STATUS.md create mode 100644 docs/MAINTAINERS.md rename original.md => docs/ORIGINAL.md (100%) create mode 100644 docs/STYLE.md create mode 100644 internal/assertions/assertion.go create mode 100644 internal/assertions/assertion_test.go create mode 100644 internal/assertions/benchmarks_test.go create mode 100644 internal/assertions/boolean.go create mode 100644 internal/assertions/boolean_test.go create mode 100644 internal/assertions/collection.go create mode 100644 internal/assertions/collection_impl_test.go create mode 100644 internal/assertions/collection_test.go rename assert/assertion_compare.go => internal/assertions/compare.go (76%) create mode 100644 internal/assertions/compare_impl_test.go create mode 100644 internal/assertions/compare_test.go create mode 100644 internal/assertions/condition.go create mode 100644 internal/assertions/condition_test.go create mode 100644 internal/assertions/doc.go create mode 100644 internal/assertions/embed_test.go create mode 100644 internal/assertions/enable/doc.go create mode 100644 internal/assertions/enable/yaml/enable_yaml.go create mode 100644 internal/assertions/equal.go create mode 100644 internal/assertions/equal_impl_test.go create mode 100644 internal/assertions/equal_test.go create mode 100644 internal/assertions/error.go create mode 100644 internal/assertions/error_test.go create mode 100644 internal/assertions/file.go create mode 100644 internal/assertions/file_test.go create mode 100644 internal/assertions/helpers.go create mode 100644 internal/assertions/helpers_impl_test.go create mode 100644 internal/assertions/helpers_test.go rename assert/http_assertions.go => internal/assertions/http.go (69%) create mode 100644 internal/assertions/http_test.go create mode 100644 internal/assertions/ifaces.go create mode 100644 internal/assertions/ifaces_test.go create mode 100644 internal/assertions/json.go create mode 100644 internal/assertions/json_test.go create mode 100644 internal/assertions/mock_test.go create mode 100644 internal/assertions/number.go create mode 100644 internal/assertions/number_test.go create mode 100644 internal/assertions/object.go create mode 100644 internal/assertions/object_test.go rename assert/assertion_order.go => internal/assertions/order.go (69%) rename assert/assertion_order_test.go => internal/assertions/order_test.go (84%) create mode 100644 internal/assertions/panic.go create mode 100644 internal/assertions/panic_test.go create mode 100644 internal/assertions/spew.go create mode 100644 internal/assertions/string.go create mode 100644 internal/assertions/string_test.go rename {assert => internal/assertions}/testdata/empty_file (100%) rename _codegen/go.sum => internal/assertions/testdata/existing_dir/.gitkeep (100%) create mode 100644 internal/assertions/testdata/existing_file create mode 100644 internal/assertions/testdata/json/fixtures.json create mode 100644 internal/assertions/testing.go create mode 100644 internal/assertions/testing_test.go create mode 100644 internal/assertions/time.go create mode 100644 internal/assertions/time_test.go create mode 100644 internal/assertions/type.go create mode 100644 internal/assertions/type_test.go rename {assert/internal => internal/assertions}/unsafetests/doc.go (100%) rename {assert/internal => internal/assertions}/unsafetests/unsafetests_test.go (71%) create mode 100644 internal/assertions/yaml.go create mode 100644 internal/assertions/yaml_test.go create mode 100644 require/assert_adhoc_example_1_test.go create mode 100644 require/assert_adhoc_example_2_test.go create mode 100644 require/assert_adhoc_example_3_test.go create mode 100644 require/assert_adhoc_example_4_test.go create mode 100644 require/assert_adhoc_example_5_test.go delete mode 100644 require/examples_test.go delete mode 100644 require/fixtures_test.go delete mode 100644 require/forward_requirements.go delete mode 100644 require/forward_requirements_test.go delete mode 100644 require/require.go delete mode 100644 require/require.go.tmpl create mode 100644 require/require_assertions.go create mode 100644 require/require_assertions_test.go create mode 100644 require/require_examples_test.go create mode 100644 require/require_format.go create mode 100644 require/require_format_test.go delete mode 100644 require/require_forward.go.tmpl create mode 100644 require/require_forward_test.go create mode 100644 require/require_helpers.go create mode 100644 require/require_helpers_test.go create mode 100644 require/require_types.go delete mode 100644 require/requirements.go delete mode 100644 require/requirements_test.go 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) -}