├── .gitattributes ├── .github ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── .markdownlint.yaml ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── and.go ├── and_test.go ├── any.go ├── any_test.go ├── assertion_error.go ├── bool.go ├── bool_test.go ├── build ├── all.go ├── clean.go ├── diff.go ├── find.go ├── go.mod ├── go.sum ├── golint.go ├── lint.go ├── main.go ├── mdlint.go ├── mod.go ├── spell.go ├── test.go └── tools.go ├── comparable.go ├── comparable_test.go ├── doc.go ├── error.go ├── error_test.go ├── eventually.go ├── eventually_test.go ├── failmsg.go ├── failmsg_test.go ├── go.mod ├── go.sum ├── goyek.ps1 ├── goyek.sh ├── helpers_test.go ├── map.go ├── map_test.go ├── nil.go ├── nil_test.go ├── number.go ├── number_test.go ├── or.go ├── or_test.go ├── ordered.go ├── ordered_test.go ├── panic.go ├── panic_test.go ├── slice.go ├── slice_test.go ├── string.go └── string_test.go /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.{cmd,[cC][mM][dD]} text eol=crlf 3 | *.{bat,[bB][aA][tT]} text eol=crlf 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for Go 9 | - package-ecosystem: "gomod" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | 14 | # Maintain dependencies for build tools 15 | - package-ecosystem: "gomod" 16 | directory: "/build" 17 | schedule: 18 | interval: "weekly" 19 | 20 | # Maintain dependencies for GitHub Actions 21 | - package-ecosystem: "github-actions" 22 | directory: "/" 23 | schedule: 24 | interval: "weekly" 25 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | 5 | 6 | ## What 7 | 8 | 10 | 11 | ## Checklist 12 | 13 | 15 | 16 | - [ ] `CHANGELOG.md` is updated. 17 | - [ ] `README.md` is updated. 18 | - [ ] The code changes follow [Effective Go](https://golang.org/doc/effective_go). 19 | - [ ] The code changes follow [CodeReviewComments](https://github.com/golang/go/wiki/CodeReviewComments). 20 | - [ ] The code changes are covered by tests. 21 | 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | ci-build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-go@v5 16 | with: 17 | go-version: '1.23' 18 | cache-dependency-path: '**/go.sum' 19 | - run: ./goyek.sh -v all diff 20 | - name: Upload HTML coverage 21 | uses: actions/upload-artifact@v4 22 | with: 23 | name: coverage 24 | path: coverage.* 25 | - name: Upload coverage to Codecov 26 | uses: codecov/codecov-action@v5 27 | with: 28 | fail_ci_if_error: true 29 | files: ./coverage.out 30 | token: ${{ secrets.CODECOV_TOKEN }} 31 | 32 | compatibility: 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | go-version: 37 | - '1.18' 38 | - '1.19' 39 | - '1.20' 40 | - '1.21' 41 | - '1.22' 42 | - '1.23' 43 | runs-on: ubuntu-latest 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: actions/setup-go@v5 47 | with: 48 | go-version: ${{ matrix.go-version }} 49 | - run: go test -race ./... 50 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: [ 'v*' ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | godoc: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Wait 1 minute 13 | # make sure that new the tag is available for pkg.go.dev 14 | run: sleep 60 15 | - name: Update pkg.go.dev 16 | run: curl https://proxy.golang.org/github.com/${{ github.repository }}/@v/${{ github.ref_name }}.info 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # MacOS DS_Store files 2 | .DS_Store 3 | 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | coverage.html 17 | 18 | # Dependency directories (remove the comment below to include it) 19 | #vendor/ 20 | 21 | # Visual Studio Code files 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | *.code-workspace 28 | .history/ 29 | 30 | # GoLand and IntelliJ IDEA files 31 | .idea/ 32 | 33 | # env files that usually contain secrets or local config 34 | .env 35 | .envrc 36 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | gocyclo: 3 | min-complexity: 15 4 | goimports: 5 | local-prefixes: github.com/fluentassert/verify 6 | govet: 7 | enable-all: true 8 | disable: 9 | - fieldalignment 10 | - nilness 11 | misspell: 12 | locale: US 13 | nolintlint: 14 | allow-leading-space: false # require machine-readable nolint directives (with no leading space) 15 | allow-unused: false # report any unused nolint directives 16 | require-explanation: true # require an explanation for nolint directives 17 | require-specific: false # don't require nolint directives to be specific about which linter is being skipped 18 | revive: 19 | confidence: 0 20 | 21 | linters: 22 | # please, do not use `enable-all`: it's deprecated and will be removed soon. 23 | # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint 24 | disable-all: true 25 | enable: 26 | - dogsled 27 | - errcheck 28 | - gochecknoinits 29 | - gocritic 30 | - goconst 31 | - gocyclo 32 | - gofumpt 33 | - goimports 34 | - revive 35 | - goprintffuncname 36 | - gosec 37 | - gosimple 38 | - govet 39 | - ineffassign 40 | - misspell 41 | - mnd 42 | - nolintlint 43 | - staticcheck 44 | - stylecheck 45 | - typecheck 46 | - unconvert 47 | - unparam 48 | - unused 49 | - whitespace 50 | 51 | issues: 52 | exclude: 53 | - EXC0001 54 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Default state for all rules 2 | default: true 3 | 4 | # hard-tabs 5 | MD010: false 6 | 7 | # 80 char line-length 8 | MD013: 9 | code_blocks: false 10 | tables: false 11 | 12 | # no-duplicate-header 13 | MD024: 14 | siblings_only: true 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "golang.Go" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${fileDirname}", 13 | "env": {}, 14 | "args": [] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[go]": { 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.organizeImports": "explicit" 6 | }, 7 | }, 8 | "[go.mod]": { 9 | "editor.formatOnSave": true, 10 | "editor.codeActionsOnSave": { 11 | "source.organizeImports": "explicit" 12 | }, 13 | }, 14 | "gopls": { 15 | "formatting.local": "github.com/fluentassert/verify", 16 | "formatting.gofumpt": true, 17 | }, 18 | "go.lintTool": "golangci-lint", 19 | "go.lintFlags": [ 20 | "--fast" 21 | ], 22 | "[go][go.mod]": { 23 | "editor.codeActionsOnSave": { 24 | "source.organizeImports": "explicit" 25 | } 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "dev", 8 | "type": "shell", 9 | "command": "./goyek.sh", 10 | "problemMatcher": [ 11 | "$go" 12 | ], 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this library are documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 | and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.3.0](https://github.com/fluentassert/verify/releases/tag/v1.2.0) - 2025-02-17 9 | 10 | ### Deprecated 11 | 12 | - Deprecate the whole library. Avoid using assertion libraries. 13 | Use the standard library and [github.com/google/go-cmp/cmp](https://pkg.go.dev/github.com/google/go-cmp/cmp) 14 | instead. Follow the official [Go Test Comments](https://go.dev/wiki/TestComments). 15 | 16 | ## [1.2.0](https://github.com/fluentassert/verify/releases/tag/v1.2.0) - 2024-09-10 17 | 18 | ### Added 19 | 20 | - Add `FailureMessage.Err` method together with `AssertionError` type 21 | to represent assertion results as `error` type. 22 | 23 | ## [1.1.0](https://github.com/fluentassert/verify/releases/tag/v1.1.0) - 2024-02-06 24 | 25 | This release adds length assertions. 26 | 27 | ### Added 28 | 29 | - Add `Len` assertion for `string`, `[]T`, `map[K]V` types. 30 | 31 | ## [1.0.0](https://github.com/fluentassert/verify/releases/tag/v1.0.0) - 2023-04-05 32 | 33 | This release contains breaking changes. 34 | 35 | The repository is moved to `github.com/fluentassert/verify` 36 | and the `f` package is renamed to `verify`. 37 | 38 | The main additions are the new assertions for 39 | `bool`, `constraints.Ordered`, `constraints.Float`, `constraints.Integer`, 40 | `string`, `error`, `[]T`, `map[K]V`, `func()` types. 41 | 42 | ### Added 43 | 44 | - Add `True`, `False`, assertion functions. 45 | - Add `Nil`, `NotNil`, assertion functions. 46 | - Add `NoError`, `IsError` assertion functions. 47 | - Add `Panics`, `NoPanic` assertion functions. 48 | - Add `Eventually`, `EventuallyChan` assertion functions. 49 | - Add `Ordered` function which provides following assertions, 50 | in addition to `Comparable`, via `FluentOrdered` type: 51 | - `Lesser` 52 | - `LesserOrEqual` 53 | - `GreaterOrEqual` 54 | - `Greater` 55 | - Add `String` function which provides following assertions, 56 | in addition to `Ordered`, via `FluentString` type: 57 | - `Empty` 58 | - `NotEmpty` 59 | - `Contain` 60 | - `NotContain` 61 | - `Prefix` 62 | - `NoPrefix` 63 | - `Sufix` 64 | - `NoSufix` 65 | - `EqualFold` 66 | - `NotEqualFold` 67 | - `MatchRegex` 68 | - `NotMatchRegex` 69 | - Add `Number` function which provides following assertions, 70 | in addition to `Ordered`, via `FluentNumber` type: 71 | - `InDelta` 72 | - `NotInDelta` 73 | - `InEpsilon` 74 | - `NotInEpsilon` 75 | - Add `Error` function which provides following assertions, 76 | in addition to `Any` and `String` (for error message), 77 | via `FluentObj` and `FluentString` types: 78 | - `Is` 79 | - `IsNot` 80 | - `As` 81 | - `NotAs` 82 | - Add `Slice` function which provides following assertions, 83 | in addition to `Any`, via `FluentSlice` type: 84 | - `Empty` 85 | - `NotEmpty` 86 | - `Equivalent` 87 | - `NotEquivalent` 88 | - `Contain` 89 | - `NotContain` 90 | - `Any` 91 | - `All` 92 | - `None` 93 | - Add `Map` function which provides following assertions, 94 | in addition to `Any`, via `FlientMap` type: 95 | - `Empty` 96 | - `NotEmpty` 97 | - `Contain` 98 | - `NotContain` 99 | - `ContainPair` 100 | - `NotContainPair` 101 | - `Any` 102 | - `All` 103 | - `None` 104 | - Add `FailureMessage.Prefix` method together with `And` and `Or` functions 105 | to facilitate creating complex assertions. 106 | 107 | ### Changed 108 | 109 | - The `f` package is renamed to `verify`. 110 | - Rename `Obj` and `FluentObj` to `Any` and `FluentAny`. 111 | - Rename `Comparable` and `FluentComparable` to `Obj` and `FluentObj`. 112 | - Change the `Check` assertion for `any` object so that the 113 | provided function has to return `FailureMessage` 114 | instead of a `string`. 115 | - `Zero` and `NonZero` methods are moved to `FluentComparable`. 116 | - Better failure messages. 117 | 118 | ## [0.2.0](https://github.com/fluentassert/verify/releases/tag/v0.2.0) - 2022-10-01 119 | 120 | This release is a complete rewrite. 121 | It is not compatible with the previous release. 122 | 123 | The new API is type-safe and easier to extend. 124 | 125 | The release provides assertions for `any`, `comparable`. 126 | 127 | The next release is supposed to provide assertions for 128 | `constraints.Ordered`, `string`, `error`, `[]T`, `map[K]V`, `func()`. 129 | 130 | ### Added 131 | 132 | - Add `FailureMessage` which encapsulates the failure message 133 | and methods for error reporting. 134 | - Add `Obj` function which provides following assertions 135 | via `FluentObject` type: 136 | - `Check` 137 | - `Should` 138 | - `ShouldNot` 139 | - `DeepEqual` 140 | - `NotDeepEqual` 141 | - `Zero` 142 | - `NonZero` 143 | - Add `Comparable` function which provides following assertions, 144 | in addition to `Obj`, via `FluentComparable` type: 145 | - `Equal` 146 | - `NotEqual` 147 | 148 | ### Changed 149 | 150 | - Require Go 1.18. 151 | 152 | ### Fixed 153 | 154 | - Fix error reporting line (use `t.Helper()` when available). 155 | 156 | ### Removed 157 | 158 | - Remove all previous functions and types (API rewrite). 159 | 160 | ## [0.1.0](https://github.com/fluentassert/verify/releases/tag/v0.1.0) - 2021-05-11 161 | 162 | First release after the experiential phase. 163 | 164 | ### Added 165 | 166 | - Add `f.Assert` that can be used instead of `t.Error` methods. 167 | - Add `f.Require` that can be used instead of `t.Fatal` methods. 168 | - Add `Should` assertion that can be used with custom predicates. 169 | - Add `Eq` assertion that checks if `got` is deeply equal to `want`. 170 | - Add `Nil` assertion that checks if `got` is `nil`. 171 | - Add `Err` assertion that checks if `got` is an `error`. 172 | - Add `Panic` assertion that checks if calling `got` results in a panic. 173 | - Add `NoPanic` assertion that checks if calling `got` returns without panicking. 174 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 71 | version 1.4, available at . 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | . 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Feel free to create an issue or propose a pull request. 4 | 5 | Follow the [Code of Conduct](CODE_OF_CONDUCT.md). 6 | 7 | ## Developing 8 | 9 | The latest version of Go is required. 10 | 11 | Docker is recommended. 12 | 13 | Run `./goyek.sh` (Bash) or `.\goyek.ps1` (PowerShell) 14 | to execute the build pipeline. 15 | 16 | The repository contains basic confiugration for 17 | [Visual Studio Code](https://code.visualstudio.com/). 18 | 19 | ## Releasing 20 | 21 | This section describes how to prepare and publish a new release. 22 | 23 | ### Pre-release 24 | 25 | Create a pull request named `Release ` that does the following: 26 | 27 | 1. Update the examples in [README.md](README.md) 28 | and make sure the documentation is up to date. 29 | 30 | 2. Update [`CHANGELOG.md`](CHANGELOG.md). 31 | - Change the `Unreleased` header to represent the new release. 32 | - Consider adding a description for the new release. 33 | Especially if it adds new features or introduces breaking changes. 34 | - Add a new `Unreleased` header above the new release, with no details. 35 | 36 | ### Release 37 | 38 | 1. Add and push a signed tag: 39 | 40 | ```sh 41 | TAG='v' 42 | COMMIT='' 43 | git tag -s -m $TAG $TAG $COMMIT 44 | git push upstream $TAG 45 | ``` 46 | 47 | 2. Create a GitHib Release named `` with `v` tag. 48 | 49 | The release description should include all the release notes 50 | from the [`CHANGELOG.md`](CHANGELOG.md) for this release. 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Robert Pająk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fluentassert 2 | 3 | > [!CAUTION] 4 | > [Avoid using assertion libraries](https://go.dev/wiki/TestComments#assert-libraries). 5 | > Instead, use [`go-cmp`](https://github.com/google/go-cmp) 6 | > and write custom test helpers. 7 | > Using the popular [`testify`](https://github.com/stretchr/testify) 8 | > may be also an acceptable choice, 9 | > especially together with [`testifylint`](https://github.com/Antonboom/testifylint) 10 | > to avoid common mistakes. 11 | > Use this library if you still want to. 12 | > Consider yourself warned. 13 | 14 | [![Go Reference](https://pkg.go.dev/badge/github.com/fluentassert/verify.svg)](https://pkg.go.dev/github.com/fluentassert/verify) 15 | [![Keep a Changelog](https://img.shields.io/badge/changelog-Keep%20a%20Changelog-%23E05735)](CHANGELOG.md) 16 | [![GitHub Release](https://img.shields.io/github/v/release/fluentassert/verify)](https://github.com/fluentassert/verify/releases) 17 | [![go.mod](https://img.shields.io/github/go-mod/go-version/fluentassert/verify)](go.mod) 18 | [![LICENSE](https://img.shields.io/github/license/fluentassert/verify)](LICENSE) 19 | 20 | [![Build Status](https://img.shields.io/github/actions/workflow/status/fluentassert/verify/build.yml?branch=main)](https://github.com/fluentassert/verify/actions?query=workflow%3Abuild+branch%3Amain) 21 | [![Go Report Card](https://goreportcard.com/badge/github.com/fluentassert/verify)](https://goreportcard.com/report/github.com/fluentassert/verify) 22 | [![Codecov](https://codecov.io/gh/fluentassert/verify/branch/main/graph/badge.svg)](https://codecov.io/gh/fluentassert/verify) 23 | 24 | ## Description 25 | 26 | The fluent API makes the assertion code easier 27 | to read and write ([more](https://dave.cheney.net/2019/09/24/be-wary-of-functions-which-take-several-parameters-of-the-same-type)). 28 | 29 | The generics (type parameters) make the usage type-safe. 30 | 31 | The library is [extensible](#extensibility) by design. 32 | 33 | ### Quick start 34 | 35 | ```go 36 | package test 37 | 38 | import ( 39 | "testing" 40 | 41 | "github.com/fluentassert/verify" 42 | ) 43 | 44 | func Foo() (string, error) { 45 | return "wrong", nil 46 | } 47 | 48 | func TestFoo(t *testing.T) { 49 | got, err := Foo() 50 | 51 | verify.NoError(err).Require(t) // Require(f) uses t.Fatal(f), stops execution if fails 52 | verify.String(got).Equal("ok").Assert(t) // Assert(f) uses t.Error(f), continues execution if fails 53 | } 54 | ``` 55 | 56 | ```sh 57 | $ go test 58 | --- FAIL: TestFoo (0.00s) 59 | basic_test.go:17: 60 | the objects are not equal 61 | got: "wrong" 62 | want: "ok" 63 | ``` 64 | 65 | ⚠ Do not forget calling 66 | [`Assert(t)`](https://pkg.go.dev/github.com/fluentassert/verify#FailureMessage.Assert) 67 | or [`Require(t)`](https://pkg.go.dev/github.com/fluentassert/verify#FailureMessage.Require) 68 | which executes the actual assertion. 69 | 70 | ## Supported types 71 | 72 | Out-of-the-box the package provides fluent assertions for the following types. 73 | The more specific function you use, the more assertions you get. 74 | 75 | | Go type | Assertion entry point | 76 | | - | - | 77 | | `interface{}` ([`any`](https://pkg.go.dev/builtin#any)) | [`verify.Any()`](https://pkg.go.dev/github.com/fluentassert/verify#Any) | 78 | | [`comparable`](https://pkg.go.dev/builtin#comparable) | [`verify.Obj()`](https://pkg.go.dev/github.com/fluentassert/verify#Obj) | 79 | | [`constraints.Ordered`](https://pkg.go.dev/golang.org/x/exp/constraints#Ordered) | [`verify.Ordered()`](https://pkg.go.dev/github.com/fluentassert/verify#Ordered) | 80 | | [`constraints.Number`](https://pkg.go.dev/golang.org/x/exp/constraints#Number) | [`verify.Number()`](https://pkg.go.dev/github.com/fluentassert/verify#Number) | 81 | | [`string`](https://pkg.go.dev/builtin#string) | [`verify.String()`](https://pkg.go.dev/github.com/fluentassert/verify#String) | 82 | | [`error`](https://go.dev/ref/spec#Errors) | [`verify.Error()`](https://pkg.go.dev/github.com/fluentassert/verify#Error) | 83 | | `[]T` ([slice](https://go.dev/ref/spec#Slice_types)) | [`verify.Slice()`](https://pkg.go.dev/github.com/fluentassert/verify#Slice) | 84 | | `map[K]V` ([map](https://go.dev/ref/spec#Map_types)) | [`verify.Map()`](https://pkg.go.dev/github.com/fluentassert/verify#Map) | 85 | 86 | Below you can find some convenience functions. 87 | 88 | - [`verify.NoError()`](https://pkg.go.dev/github.com/fluentassert/verify#NoError) 89 | - [`verify.IsError()`](https://pkg.go.dev/github.com/fluentassert/verify#IsError) 90 | - [`verify.Nil()`](https://pkg.go.dev/github.com/fluentassert/verify#Nil) 91 | - [`verify.NotNil()`](https://pkg.go.dev/github.com/fluentassert/verify#NotNil) 92 | - [`verify.True()`](https://pkg.go.dev/github.com/fluentassert/verify#True) 93 | - [`verify.False()`](https://pkg.go.dev/github.com/fluentassert/verify#False) 94 | 95 | ### Deep equality 96 | 97 | For testing deep equality use 98 | [`DeepEqual()`](https://pkg.go.dev/github.com/fluentassert/verify#FluentAny.DeepEqual) 99 | or [`NotDeepEqual()`](https://pkg.go.dev/github.com/fluentassert/verify#FluentAny.NotDeepEqual). 100 | 101 | ```go 102 | package test 103 | 104 | import ( 105 | "testing" 106 | 107 | "github.com/fluentassert/verify" 108 | ) 109 | 110 | type A struct { 111 | Str string 112 | Bool bool 113 | Slice []int 114 | } 115 | 116 | func TestDeepEqual(t *testing.T) { 117 | got := A{Str: "wrong", Slice: []int{1, 4}} 118 | 119 | verify.Any(got).DeepEqual( 120 | A{Str: "string", Bool: true, Slice: []int{1, 2}}, 121 | ).Assert(t) 122 | } 123 | ``` 124 | 125 | ```sh 126 | $ go test 127 | --- FAIL: TestDeepEqual (0.00s) 128 | deepeq_test.go:20: 129 | mismatch (-want +got): 130 | test.A{ 131 | - Str: "string", 132 | + Str: "wrong", 133 | - Bool: true, 134 | + Bool: false, 135 | Slice: []int{ 136 | 1, 137 | - 2, 138 | + 4, 139 | }, 140 | } 141 | ``` 142 | 143 | ### Collection assertions 144 | 145 | The library contains many collection assertions. 146 | Below is an example of checking unordered equality. 147 | 148 | ```go 149 | package test 150 | 151 | import ( 152 | "testing" 153 | 154 | "github.com/fluentassert/verify" 155 | ) 156 | 157 | func TestSlice(t *testing.T) { 158 | got := []int { 3, 1, 2 } 159 | 160 | verify.Slice(got).Equivalent([]int { 2, 3, 4 }).Assert(t) 161 | } 162 | ``` 163 | 164 | ```sh 165 | $ go test 166 | --- FAIL: TestSlice (0.00s) 167 | slice_test.go:12: 168 | not equivalent 169 | got: [3 1 2] 170 | want: [2 3 4] 171 | extra got: [1] 172 | extra want: [4] 173 | ``` 174 | 175 | ### Periodic polling 176 | 177 | For asynchronous testing you can use 178 | [`verify.Eventually()`](https://pkg.go.dev/github.com/fluentassert/verify#Eventually) 179 | or [`verify.EventuallyChan()`](https://pkg.go.dev/github.com/fluentassert/verify#EventuallyChan). 180 | 181 | ```go 182 | package test 183 | 184 | import ( 185 | "net/http" 186 | "testing" 187 | "time" 188 | 189 | "github.com/fluentassert/verify" 190 | ) 191 | 192 | func TestPeriodic(t *testing.T) { 193 | verify.Eventually(10*time.Second, time.Second, func() verify.FailureMessage { 194 | client := http.Client{Timeout: time.Second} 195 | resp, err := client.Get("http://not-existing:1234") 196 | if err != nil { 197 | return verify.NoError(err) 198 | } 199 | return verify.Number(resp.StatusCode).Lesser(300) 200 | }).Assert(t) 201 | } 202 | ``` 203 | 204 | ```sh 205 | $ go test 206 | --- FAIL: TestPeriodic (10.00s) 207 | async_test.go:19: 208 | function never passed, last failure message: 209 | Get "http://not-existing:1234": context deadline exceeded (Client.Timeout exceeded while awaiting headers) 210 | ``` 211 | 212 | ### Custom predicates 213 | 214 | For the most basic scenarios, you can use one of the 215 | [`Check()`](https://pkg.go.dev/github.com/fluentassert/verify#FluentAny.Check), 216 | [`Should()`](https://pkg.go.dev/github.com/fluentassert/verify#FluentAny.Should), 217 | [`ShouldNot()`](https://pkg.go.dev/github.com/fluentassert/verify#FluentAny.ShouldNot) 218 | assertions. 219 | 220 | ```go 221 | package test 222 | 223 | import ( 224 | "strings" 225 | "testing" 226 | 227 | "github.com/fluentassert/verify" 228 | ) 229 | 230 | func TestShould(t *testing.T) { 231 | got := "wrong" 232 | 233 | chars := "abc" 234 | verify.Any(got).Should(func(got string) bool { 235 | return strings.ContainsAny(got, chars) 236 | }).Assertf(t, "does not contain any of: %s", chars) 237 | } 238 | ``` 239 | 240 | ```sh 241 | $ go test 242 | --- FAIL: TestShould (0.00s) 243 | should_test.go:16: does not contain any of: abc 244 | object does not meet the predicate criteria 245 | got: "wrong" 246 | ``` 247 | 248 | ### Panics 249 | 250 | For testing panics use [`verify.Panics()`](https://pkg.go.dev/github.com/fluentassert/verify#Panics) 251 | and [`verify.NotPanics()`](https://pkg.go.dev/github.com/fluentassert/verify#NotPanics). 252 | 253 | ### Custom assertion function 254 | 255 | You can create a function that returns [`FailureMessage`](https://pkg.go.dev/github.com/fluentassert/verify#FailureMessage). 256 | Use [`verify.And()`](https://pkg.go.dev/github.com/fluentassert/verify#And) 257 | and [`verify.Or()`](https://pkg.go.dev/github.com/fluentassert/verify#Or) 258 | functions together with [`Prefix()`](https://pkg.go.dev/github.com/fluentassert/verify#FailureMessage.Prefix) 259 | method to create complex assertions. 260 | 261 | ```go 262 | package test 263 | 264 | import ( 265 | "testing" 266 | 267 | "github.com/fluentassert/verify" 268 | ) 269 | 270 | type A struct { 271 | Str string 272 | Ok bool 273 | } 274 | 275 | func TestCustom(t *testing.T) { 276 | got := A{Str: "something was wrong"} 277 | 278 | verifyA(got).Assert(t) 279 | } 280 | 281 | func verifyA(got A) verify.FailureMessage { 282 | return verify.And( 283 | verify.String(got.Str).Contain("ok").Prefix("got.String: "), 284 | verify.True(got.Ok).Prefix("got.Ok: "), 285 | ) 286 | } 287 | ``` 288 | 289 | ```sh 290 | $ go test 291 | --- FAIL: TestCustom (0.00s) 292 | custom_test.go:17: 293 | got.String: the value does not contain the substring 294 | got: "something was wrong" 295 | substr: "ok" 296 | 297 | got.Ok: the value is false 298 | ``` 299 | 300 | ## Extensibility 301 | 302 | You can take advantage of the [`FailureMessage`](https://pkg.go.dev/github.com/fluentassert/verify#FailureMessage) 303 | and `Fluent*` types 304 | to create your own fluent assertions for a given type. 305 | 306 | For reference, take a look at the implementation 307 | of existing fluent assertions in this repository 308 | (for example [comparable.go](comparable.go)). 309 | 310 | ## Supported Go versions 311 | 312 | Minimal supported Go version is 1.18. 313 | 314 | ## Contributing 315 | 316 | See [CONTRIBUTING.md](CONTRIBUTING.md) if you want to help. 317 | 318 | ## License 319 | 320 | **fluentassert** is licensed under the terms of [the MIT license](LICENSE). 321 | 322 | [`github.com/google/go-cmp`](https://github.com/google/go-cmp) 323 | (license: [BSD-3-Clause](https://pkg.go.dev/github.com/google/go-cmp/cmp?tab=licenses)) 324 | is the only [third-party dependency](go.mod). 325 | -------------------------------------------------------------------------------- /and.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | // And accumalates non-empty failure messages. 4 | func And(assertions ...FailureMessage) FailureMessage { 5 | var msg FailureMessage 6 | for _, assertion := range assertions { 7 | if assertion == "" { 8 | continue 9 | } 10 | if msg == "" { 11 | msg = assertion 12 | continue 13 | } 14 | msg = msg + "\n\n" + assertion 15 | } 16 | return msg 17 | } 18 | -------------------------------------------------------------------------------- /and_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestAnd(t *testing.T) { 10 | t.Run("Empty", func(t *testing.T) { 11 | msg := verify.And() 12 | assertPassed(t, msg) 13 | }) 14 | t.Run("NoneFailed", func(t *testing.T) { 15 | msg := verify.And("", "") 16 | assertPassed(t, msg) 17 | }) 18 | t.Run("OneFailed", func(t *testing.T) { 19 | msg := verify.And("", "failure") 20 | assertFailed(t, msg, "failure") 21 | }) 22 | t.Run("TwoFailed", func(t *testing.T) { 23 | msg := verify.And("one", "two") 24 | assertFailed(t, msg, "one\n\ntwo") 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /any.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | ) 8 | 9 | // FluentAny encapsulates assertions for any object. 10 | type FluentAny[T any] struct { 11 | Got T 12 | } 13 | 14 | // Any is used for testing any object. 15 | func Any[T any](got T) FluentAny[T] { 16 | return FluentAny[T]{got} 17 | } 18 | 19 | // Check tests the object using the provided function. 20 | func (x FluentAny[T]) Check(fn func(got T) FailureMessage) FailureMessage { 21 | return fn(x.Got) 22 | } 23 | 24 | // Should tests if the object meets the predicate criteria. 25 | func (x FluentAny[T]) Should(pred func(got T) bool) FailureMessage { 26 | if pred(x.Got) { 27 | return "" 28 | } 29 | return FailureMessage(fmt.Sprintf("object does not meet the predicate criteria\ngot: %+v", x.Got)) 30 | } 31 | 32 | // ShouldNot tests if the object does not meet the predicate criteria. 33 | func (x FluentAny[T]) ShouldNot(fn func(got T) bool) FailureMessage { 34 | if !fn(x.Got) { 35 | return "" 36 | } 37 | return FailureMessage(fmt.Sprintf("object meets the predicate criteria\ngot: %+v", x.Got)) 38 | } 39 | 40 | // DeepEqual tests if the objects are deep equal using github.com/google/go-cmp/cmp. 41 | func (x FluentAny[T]) DeepEqual(want T, opts ...cmp.Option) FailureMessage { 42 | diff := cmp.Diff(want, x.Got, opts...) 43 | if diff == "" { 44 | return "" 45 | } 46 | return FailureMessage("mismatch (-want +got):\n" + diff) 47 | } 48 | 49 | // NotDeepEqual tests if the objects are not deep equal using github.com/google/go-cmp/cmp. 50 | func (x FluentAny[T]) NotDeepEqual(obj T, opts ...cmp.Option) FailureMessage { 51 | ok := cmp.Equal(obj, x.Got, opts...) 52 | if !ok { 53 | return "" 54 | } 55 | return FailureMessage(fmt.Sprintf("the objects are equal\ngot: %+v", x.Got)) 56 | } 57 | -------------------------------------------------------------------------------- /any_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestAny(t *testing.T) { 10 | type A struct { 11 | Str string 12 | Bool bool 13 | Slice []int 14 | } 15 | 16 | t.Run("DeepEqual", func(t *testing.T) { 17 | t.Run("Passed", func(t *testing.T) { 18 | want := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 19 | got := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 20 | msg := verify.Any(got).DeepEqual(want) 21 | assertPassed(t, msg) 22 | }) 23 | t.Run("Failed", func(t *testing.T) { 24 | want := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 25 | got := A{Str: "wrong", Bool: true, Slice: []int{1, 3}} 26 | msg := verify.Any(got).DeepEqual(want) 27 | assertFailed(t, msg, "mismatch (-want +got):\n") 28 | }) 29 | t.Run("nil", func(t *testing.T) { 30 | var got *A 31 | msg := verify.Any(got).DeepEqual(nil) 32 | assertPassed(t, msg) 33 | }) 34 | }) 35 | 36 | t.Run("NotDeepEqual", func(t *testing.T) { 37 | t.Run("Passed", func(t *testing.T) { 38 | want := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 39 | got := A{Str: "wrong", Bool: true, Slice: []int{1, 3}} 40 | msg := verify.Any(got).NotDeepEqual(want) 41 | assertPassed(t, msg) 42 | }) 43 | t.Run("Failed", func(t *testing.T) { 44 | want := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 45 | got := A{Str: "string", Bool: true, Slice: []int{1, 2, 3}} 46 | msg := verify.Any(got).NotDeepEqual(want) 47 | assertFailed(t, msg, "the objects are equal") 48 | }) 49 | t.Run("nil", func(t *testing.T) { 50 | var got *A 51 | msg := verify.Any(got).NotDeepEqual(nil) 52 | assertFailed(t, msg, "the objects are equal") 53 | }) 54 | }) 55 | 56 | t.Run("Check", func(t *testing.T) { 57 | t.Run("Passed", func(t *testing.T) { 58 | fn := func(A) verify.FailureMessage { 59 | return "" 60 | } 61 | msg := verify.Any(A{}).Check(fn) 62 | assertPassed(t, msg) 63 | }) 64 | t.Run("Failed", func(t *testing.T) { 65 | fn := func(A) verify.FailureMessage { 66 | return "failure" 67 | } 68 | msg := verify.Any(A{}).Check(fn) 69 | assertFailed(t, msg, "failure") 70 | }) 71 | }) 72 | 73 | t.Run("Should", func(t *testing.T) { 74 | t.Run("Passed", func(t *testing.T) { 75 | pred := func(A) bool { 76 | return true 77 | } 78 | msg := verify.Any(A{}).Should(pred) 79 | assertPassed(t, msg) 80 | }) 81 | t.Run("Failed", func(t *testing.T) { 82 | pred := func(A) bool { 83 | return false 84 | } 85 | msg := verify.Any(A{}).Should(pred) 86 | assertFailed(t, msg, "object does not meet the predicate criteria") 87 | }) 88 | }) 89 | 90 | t.Run("ShouldNot", func(t *testing.T) { 91 | t.Run("Passed", func(t *testing.T) { 92 | pred := func(A) bool { 93 | return false 94 | } 95 | msg := verify.Any(A{}).ShouldNot(pred) 96 | assertPassed(t, msg) 97 | }) 98 | t.Run("Failed", func(t *testing.T) { 99 | pred := func(A) bool { 100 | return true 101 | } 102 | msg := verify.Any(A{}).ShouldNot(pred) 103 | assertFailed(t, msg, "object meets the predicate criteria") 104 | }) 105 | }) 106 | } 107 | -------------------------------------------------------------------------------- /assertion_error.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | // AssertionError is an error type used to represent failure messages from assertions. 4 | // It is compatible with the error interface and can be used in instances where an error shall be returned instead of failing a test. 5 | type AssertionError struct { 6 | Message FailureMessage 7 | } 8 | 9 | // Error returns the failure message as a string. It makes AssertionError compatible with the error interface. 10 | func (err *AssertionError) Error() string { 11 | return string(err.Message) 12 | } 13 | -------------------------------------------------------------------------------- /bool.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | // True tests if the object is a true value. 4 | func True[T ~bool](got T) FailureMessage { 5 | if got { 6 | return "" 7 | } 8 | return "the value is false" 9 | } 10 | 11 | // False tests if the object is a false value. 12 | func False[T ~bool](got T) FailureMessage { 13 | if !got { 14 | return "" 15 | } 16 | return "the value is true" 17 | } 18 | -------------------------------------------------------------------------------- /bool_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestTrue(t *testing.T) { 10 | t.Run("Passed", func(t *testing.T) { 11 | got := verify.True(true) 12 | assertPassed(t, got) 13 | }) 14 | t.Run("Failed", func(t *testing.T) { 15 | got := verify.True(false) 16 | assertFailed(t, got, "the value is false") 17 | }) 18 | } 19 | 20 | func TestFalse(t *testing.T) { 21 | t.Run("Passed", func(t *testing.T) { 22 | got := verify.False(false) 23 | assertPassed(t, got) 24 | }) 25 | t.Run("Failed", func(t *testing.T) { 26 | got := verify.False(true) 27 | assertFailed(t, got, "the value is true") 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /build/all.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/goyek/goyek/v2" 4 | 5 | var all = goyek.Define(goyek.Task{ 6 | Name: "all", 7 | Usage: "build pipeline", 8 | Deps: goyek.Deps{ 9 | mod, 10 | lint, 11 | test, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /build/clean.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/goyek/goyek/v2" 7 | ) 8 | 9 | var _ = goyek.Define(goyek.Task{ 10 | Name: "clean", 11 | Usage: "remove files created during build pipeline", 12 | Action: func(a *goyek.A) { 13 | remove(a, "coverage.out") 14 | remove(a, "coverage.html") 15 | }, 16 | }) 17 | 18 | func remove(a *goyek.A, path string) { 19 | a.Helper() 20 | if _, err := os.Stat(path); err != nil { 21 | return 22 | } 23 | a.Log("Remove: " + path) 24 | if err := os.RemoveAll(path); err != nil { 25 | a.Error(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /build/diff.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | 7 | "github.com/goyek/goyek/v2" 8 | "github.com/goyek/x/cmd" 9 | ) 10 | 11 | var _ = goyek.Define(goyek.Task{ 12 | Name: "diff", 13 | Usage: "git diff", 14 | Action: func(a *goyek.A) { 15 | cmd.Exec(a, "git diff --exit-code") 16 | 17 | sb := &strings.Builder{} 18 | out := io.MultiWriter(a.Output(), sb) 19 | cmd.Exec(a, "git status --porcelain", cmd.Stdout(out), cmd.Stderr(out)) 20 | if sb.Len() > 0 { 21 | a.Error("git status --porcelain returned output") 22 | } 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /build/find.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/fs" 5 | "path/filepath" 6 | 7 | "github.com/goyek/goyek/v2" 8 | ) 9 | 10 | func find(a *goyek.A, ext string) []string { 11 | a.Helper() 12 | var files []string 13 | err := filepath.WalkDir(dirRoot, func(path string, d fs.DirEntry, err error) error { 14 | if err != nil { 15 | return err 16 | } 17 | if filepath.Ext(d.Name()) == ext { 18 | files = append(files, filepath.ToSlash(path)) 19 | } 20 | return nil 21 | }) 22 | if err != nil { 23 | a.Fatal(err) 24 | } 25 | return files 26 | } 27 | -------------------------------------------------------------------------------- /build/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fluentassert/verify/build 2 | 3 | go 1.22.1 4 | 5 | require ( 6 | github.com/client9/misspell v0.3.4 7 | github.com/golangci/golangci-lint v1.62.2 8 | github.com/goyek/goyek/v2 v2.2.0 9 | github.com/goyek/x v0.2.0 10 | ) 11 | 12 | require ( 13 | 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 14 | 4d63.com/gochecknoglobals v0.2.1 // indirect 15 | github.com/4meepo/tagalign v1.3.4 // indirect 16 | github.com/Abirdcfly/dupword v0.1.3 // indirect 17 | github.com/Antonboom/errname v1.0.0 // indirect 18 | github.com/Antonboom/nilnil v1.0.0 // indirect 19 | github.com/Antonboom/testifylint v1.5.2 // indirect 20 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect 21 | github.com/Crocmagnon/fatcontext v0.5.3 // indirect 22 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect 23 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect 24 | github.com/Masterminds/semver/v3 v3.3.0 // indirect 25 | github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect 26 | github.com/alecthomas/go-check-sumtype v0.2.0 // indirect 27 | github.com/alexkohler/nakedret/v2 v2.0.5 // indirect 28 | github.com/alexkohler/prealloc v1.0.0 // indirect 29 | github.com/alingse/asasalint v0.0.11 // indirect 30 | github.com/ashanbrown/forbidigo v1.6.0 // indirect 31 | github.com/ashanbrown/makezero v1.1.1 // indirect 32 | github.com/beorn7/perks v1.0.1 // indirect 33 | github.com/bkielbasa/cyclop v1.2.3 // indirect 34 | github.com/blizzy78/varnamelen v0.8.0 // indirect 35 | github.com/bombsimon/wsl/v4 v4.4.1 // indirect 36 | github.com/breml/bidichk v0.3.2 // indirect 37 | github.com/breml/errchkjson v0.4.0 // indirect 38 | github.com/butuzov/ireturn v0.3.0 // indirect 39 | github.com/butuzov/mirror v1.2.0 // indirect 40 | github.com/catenacyber/perfsprint v0.7.1 // indirect 41 | github.com/ccojocar/zxcvbn-go v1.0.2 // indirect 42 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 43 | github.com/charithe/durationcheck v0.0.10 // indirect 44 | github.com/chavacava/garif v0.1.0 // indirect 45 | github.com/ckaznocha/intrange v0.2.1 // indirect 46 | github.com/curioswitch/go-reassign v0.2.0 // indirect 47 | github.com/daixiang0/gci v0.13.5 // indirect 48 | github.com/davecgh/go-spew v1.1.1 // indirect 49 | github.com/denis-tingaikin/go-header v0.5.0 // indirect 50 | github.com/ettle/strcase v0.2.0 // indirect 51 | github.com/fatih/color v1.18.0 // indirect 52 | github.com/fatih/structtag v1.2.0 // indirect 53 | github.com/firefart/nonamedreturns v1.0.5 // indirect 54 | github.com/fsnotify/fsnotify v1.5.4 // indirect 55 | github.com/fzipp/gocyclo v0.6.0 // indirect 56 | github.com/ghostiam/protogetter v0.3.8 // indirect 57 | github.com/go-critic/go-critic v0.11.5 // indirect 58 | github.com/go-toolsmith/astcast v1.1.0 // indirect 59 | github.com/go-toolsmith/astcopy v1.1.0 // indirect 60 | github.com/go-toolsmith/astequal v1.2.0 // indirect 61 | github.com/go-toolsmith/astfmt v1.1.0 // indirect 62 | github.com/go-toolsmith/astp v1.1.0 // indirect 63 | github.com/go-toolsmith/strparse v1.1.0 // indirect 64 | github.com/go-toolsmith/typep v1.1.0 // indirect 65 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 66 | github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect 67 | github.com/gobwas/glob v0.2.3 // indirect 68 | github.com/gofrs/flock v0.12.1 // indirect 69 | github.com/golang/protobuf v1.5.3 // indirect 70 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect 71 | github.com/golangci/go-printf-func-name v0.1.0 // indirect 72 | github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect 73 | github.com/golangci/misspell v0.6.0 // indirect 74 | github.com/golangci/modinfo v0.3.4 // indirect 75 | github.com/golangci/plugin-module-register v0.1.1 // indirect 76 | github.com/golangci/revgrep v0.5.3 // indirect 77 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect 78 | github.com/google/go-cmp v0.6.0 // indirect 79 | github.com/gordonklaus/ineffassign v0.1.0 // indirect 80 | github.com/gostaticanalysis/analysisutil v0.7.1 // indirect 81 | github.com/gostaticanalysis/comment v1.4.2 // indirect 82 | github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect 83 | github.com/gostaticanalysis/nilerr v0.1.1 // indirect 84 | github.com/hashicorp/go-version v1.7.0 // indirect 85 | github.com/hashicorp/hcl v1.0.0 // indirect 86 | github.com/hexops/gotextdiff v1.0.3 // indirect 87 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 88 | github.com/jgautheron/goconst v1.7.1 // indirect 89 | github.com/jingyugao/rowserrcheck v1.1.1 // indirect 90 | github.com/jjti/go-spancheck v0.6.2 // indirect 91 | github.com/julz/importas v0.1.0 // indirect 92 | github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect 93 | github.com/kisielk/errcheck v1.8.0 // indirect 94 | github.com/kkHAIKE/contextcheck v1.1.5 // indirect 95 | github.com/kulti/thelper v0.6.3 // indirect 96 | github.com/kunwardeep/paralleltest v1.0.10 // indirect 97 | github.com/kyoh86/exportloopref v0.1.11 // indirect 98 | github.com/lasiar/canonicalheader v1.1.2 // indirect 99 | github.com/ldez/gomoddirectives v0.2.4 // indirect 100 | github.com/ldez/tagliatelle v0.5.0 // indirect 101 | github.com/leonklingele/grouper v1.1.2 // indirect 102 | github.com/macabu/inamedparam v0.1.3 // indirect 103 | github.com/magiconair/properties v1.8.6 // indirect 104 | github.com/maratori/testableexamples v1.0.0 // indirect 105 | github.com/maratori/testpackage v1.1.1 // indirect 106 | github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect 107 | github.com/mattn/go-colorable v0.1.13 // indirect 108 | github.com/mattn/go-isatty v0.0.20 // indirect 109 | github.com/mattn/go-runewidth v0.0.16 // indirect 110 | github.com/mattn/go-shellwords v1.0.12 // indirect 111 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 112 | github.com/mgechev/revive v1.5.1 // indirect 113 | github.com/mitchellh/go-homedir v1.1.0 // indirect 114 | github.com/mitchellh/mapstructure v1.5.0 // indirect 115 | github.com/moricho/tparallel v0.3.2 // indirect 116 | github.com/nakabonne/nestif v0.3.1 // indirect 117 | github.com/nishanths/exhaustive v0.12.0 // indirect 118 | github.com/nishanths/predeclared v0.2.2 // indirect 119 | github.com/nunnatsa/ginkgolinter v0.18.3 // indirect 120 | github.com/olekukonko/tablewriter v0.0.5 // indirect 121 | github.com/pelletier/go-toml v1.9.5 // indirect 122 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 123 | github.com/pmezard/go-difflib v1.0.0 // indirect 124 | github.com/polyfloyd/go-errorlint v1.7.0 // indirect 125 | github.com/prometheus/client_golang v1.12.1 // indirect 126 | github.com/prometheus/client_model v0.2.0 // indirect 127 | github.com/prometheus/common v0.32.1 // indirect 128 | github.com/prometheus/procfs v0.7.3 // indirect 129 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect 130 | github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect 131 | github.com/quasilyte/gogrep v0.5.0 // indirect 132 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect 133 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect 134 | github.com/raeperd/recvcheck v0.1.2 // indirect 135 | github.com/rivo/uniseg v0.4.7 // indirect 136 | github.com/rogpeppe/go-internal v1.13.1 // indirect 137 | github.com/ryancurrah/gomodguard v1.3.5 // indirect 138 | github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect 139 | github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect 140 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect 141 | github.com/sashamelentyev/interfacebloat v1.1.0 // indirect 142 | github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect 143 | github.com/securego/gosec/v2 v2.21.4 // indirect 144 | github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect 145 | github.com/sirupsen/logrus v1.9.3 // indirect 146 | github.com/sivchari/containedctx v1.0.3 // indirect 147 | github.com/sivchari/tenv v1.12.1 // indirect 148 | github.com/sonatard/noctx v0.1.0 // indirect 149 | github.com/sourcegraph/go-diff v0.7.0 // indirect 150 | github.com/spf13/afero v1.11.0 // indirect 151 | github.com/spf13/cast v1.5.0 // indirect 152 | github.com/spf13/cobra v1.8.1 // indirect 153 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 154 | github.com/spf13/pflag v1.0.5 // indirect 155 | github.com/spf13/viper v1.12.0 // indirect 156 | github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect 157 | github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect 158 | github.com/stretchr/objx v0.5.2 // indirect 159 | github.com/stretchr/testify v1.10.0 // indirect 160 | github.com/subosito/gotenv v1.4.1 // indirect 161 | github.com/tdakkota/asciicheck v0.2.0 // indirect 162 | github.com/tetafro/godot v1.4.18 // indirect 163 | github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect 164 | github.com/timonwong/loggercheck v0.10.1 // indirect 165 | github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect 166 | github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect 167 | github.com/ultraware/funlen v0.1.0 // indirect 168 | github.com/ultraware/whitespace v0.1.1 // indirect 169 | github.com/uudashr/gocognit v1.1.3 // indirect 170 | github.com/uudashr/iface v1.2.1 // indirect 171 | github.com/xen0n/gosmopolitan v1.2.2 // indirect 172 | github.com/yagipy/maintidx v1.0.0 // indirect 173 | github.com/yeya24/promlinter v0.3.0 // indirect 174 | github.com/ykadowak/zerologlint v0.1.5 // indirect 175 | gitlab.com/bosi/decorder v0.4.2 // indirect 176 | go-simpler.org/musttag v0.13.0 // indirect 177 | go-simpler.org/sloglint v0.7.2 // indirect 178 | go.uber.org/atomic v1.7.0 // indirect 179 | go.uber.org/automaxprocs v1.6.0 // indirect 180 | go.uber.org/multierr v1.6.0 // indirect 181 | go.uber.org/zap v1.24.0 // indirect 182 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect 183 | golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect 184 | golang.org/x/mod v0.22.0 // indirect 185 | golang.org/x/sync v0.9.0 // indirect 186 | golang.org/x/sys v0.27.0 // indirect 187 | golang.org/x/text v0.18.0 // indirect 188 | golang.org/x/tools v0.27.0 // indirect 189 | google.golang.org/protobuf v1.34.2 // indirect 190 | gopkg.in/ini.v1 v1.67.0 // indirect 191 | gopkg.in/yaml.v2 v2.4.0 // indirect 192 | gopkg.in/yaml.v3 v3.0.1 // indirect 193 | honnef.co/go/tools v0.5.1 // indirect 194 | mvdan.cc/gofumpt v0.7.0 // indirect 195 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect 196 | ) 197 | -------------------------------------------------------------------------------- /build/go.sum: -------------------------------------------------------------------------------- 1 | 4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= 2 | 4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= 3 | 4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= 4 | 4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= 5 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 6 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 7 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 8 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 9 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 10 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 11 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 12 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 13 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 14 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 15 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 16 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 17 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 18 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 19 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 20 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 21 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 22 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 23 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 24 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 25 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 26 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 27 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 28 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 29 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 30 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 31 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 32 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 33 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 34 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 35 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 36 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 37 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 38 | github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= 39 | github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= 40 | github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= 41 | github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= 42 | github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA= 43 | github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI= 44 | github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk= 45 | github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII= 46 | github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk= 47 | github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8= 48 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 49 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= 50 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 51 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 52 | github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps= 53 | github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM= 54 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= 55 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= 56 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= 57 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= 58 | github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= 59 | github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 60 | github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= 61 | github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= 62 | github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= 63 | github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= 64 | github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY= 65 | github.com/alecthomas/go-check-sumtype v0.2.0/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= 66 | github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= 67 | github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 68 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 69 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 70 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 71 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 72 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 73 | github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= 74 | github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= 75 | github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= 76 | github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= 77 | github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= 78 | github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= 79 | github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= 80 | github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= 81 | github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= 82 | github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= 83 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 84 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 85 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 86 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 87 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 88 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 89 | github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= 90 | github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= 91 | github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= 92 | github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= 93 | github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= 94 | github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= 95 | github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs= 96 | github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos= 97 | github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk= 98 | github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8= 99 | github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= 100 | github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= 101 | github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= 102 | github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= 103 | github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= 104 | github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= 105 | github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= 106 | github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= 107 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 108 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 109 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 110 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 111 | github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= 112 | github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= 113 | github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= 114 | github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= 115 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 116 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 117 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 118 | github.com/ckaznocha/intrange v0.2.1 h1:M07spnNEQoALOJhwrImSrJLaxwuiQK+hA2DeajBlwYk= 119 | github.com/ckaznocha/intrange v0.2.1/go.mod h1:7NEhVyf8fzZO5Ds7CRaqPEm52Ut83hsTiL5zbER/HYk= 120 | github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 121 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 122 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 123 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 124 | github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= 125 | github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= 126 | github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= 127 | github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= 128 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 129 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 130 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 131 | github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= 132 | github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= 133 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 134 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 135 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 136 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 137 | github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= 138 | github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= 139 | github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= 140 | github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= 141 | github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= 142 | github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 143 | github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= 144 | github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= 145 | github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= 146 | github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 147 | github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= 148 | github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= 149 | github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= 150 | github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= 151 | github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY= 152 | github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= 153 | github.com/go-critic/go-critic v0.11.5 h1:TkDTOn5v7EEngMxu8KbuFqFR43USaaH8XRJLz1jhVYA= 154 | github.com/go-critic/go-critic v0.11.5/go.mod h1:wu6U7ny9PiaHaZHcvMDmdysMqvDem162Rh3zWTrqk8M= 155 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 156 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 157 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 158 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 159 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 160 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 161 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 162 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 163 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 164 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 165 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 166 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 167 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 168 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 169 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 170 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 171 | github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= 172 | github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= 173 | github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= 174 | github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= 175 | github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= 176 | github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= 177 | github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= 178 | github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= 179 | github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= 180 | github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= 181 | github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= 182 | github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= 183 | github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= 184 | github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= 185 | github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= 186 | github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= 187 | github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= 188 | github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= 189 | github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= 190 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= 191 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 192 | github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= 193 | github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= 194 | github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= 195 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 196 | github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= 197 | github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= 198 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 199 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 200 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 201 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 202 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 203 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 204 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 205 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 206 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 207 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 208 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 209 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 210 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 211 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 212 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 213 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 214 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 215 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 216 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 217 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 218 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 219 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 220 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 221 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 222 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 223 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 224 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 225 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 226 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 227 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 228 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= 229 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= 230 | github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU= 231 | github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= 232 | github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= 233 | github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= 234 | github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw= 235 | github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g= 236 | github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= 237 | github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= 238 | github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= 239 | github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= 240 | github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= 241 | github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= 242 | github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= 243 | github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= 244 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= 245 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= 246 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 247 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 248 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 249 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 250 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 251 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 252 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 253 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 254 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 255 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 256 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 257 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 258 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 259 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 260 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 261 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 262 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 263 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 264 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 265 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 266 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 267 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 268 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 269 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 270 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 271 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 272 | github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= 273 | github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 274 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 275 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 276 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 277 | github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= 278 | github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= 279 | github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= 280 | github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= 281 | github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= 282 | github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= 283 | github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= 284 | github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= 285 | github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= 286 | github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= 287 | github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= 288 | github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= 289 | github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= 290 | github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= 291 | github.com/goyek/goyek/v2 v2.2.0 h1:FXdta04rwVN/HE33XKcBtYht6iaDkJ9Z5Bdh1TdXjO0= 292 | github.com/goyek/goyek/v2 v2.2.0/go.mod h1:mqU0PSD8q3TRCzhJ1mL79/X7FOrXJcpvOtDEBXi92+E= 293 | github.com/goyek/x v0.2.0 h1:vLTzDTqbUQnWTM3NOnejGAWwWZA+hJHElv/cd/3ybQc= 294 | github.com/goyek/x v0.2.0/go.mod h1:I1yv17Zj0g3Zv5iDC+kB9gh3cqJquJSTEgfognEfe94= 295 | github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 296 | github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= 297 | github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 298 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 299 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 300 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 301 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 302 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 303 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 304 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 305 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 306 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 307 | github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= 308 | github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= 309 | github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= 310 | github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= 311 | github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= 312 | github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= 313 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 314 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 315 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 316 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 317 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 318 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 319 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 320 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 321 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 322 | github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= 323 | github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= 324 | github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= 325 | github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= 326 | github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg= 327 | github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= 328 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 329 | github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= 330 | github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= 331 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 332 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 333 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 334 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 335 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 336 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 337 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 338 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 339 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 340 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 341 | github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= 342 | github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= 343 | github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= 344 | github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= 345 | github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= 346 | github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= 347 | github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= 348 | github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= 349 | github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= 350 | github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= 351 | github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= 352 | github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= 353 | github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= 354 | github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= 355 | github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= 356 | github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= 357 | github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= 358 | github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 359 | github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= 360 | github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= 361 | github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= 362 | github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= 363 | github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= 364 | github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= 365 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= 366 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 367 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 368 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 369 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 370 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 371 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 372 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 373 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 374 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 375 | github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= 376 | github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= 377 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 378 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 379 | github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M= 380 | github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o= 381 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 382 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 383 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 384 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 385 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 386 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 387 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 388 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 389 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 390 | github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= 391 | github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= 392 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 393 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 394 | github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= 395 | github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= 396 | github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= 397 | github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= 398 | github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= 399 | github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= 400 | github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB0j1noDw= 401 | github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs= 402 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 403 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 404 | github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= 405 | github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= 406 | github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= 407 | github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= 408 | github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= 409 | github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= 410 | github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= 411 | github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= 412 | github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= 413 | github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= 414 | github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= 415 | github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= 416 | github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 417 | github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= 418 | github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 419 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 420 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 421 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 422 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 423 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 424 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 425 | github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU= 426 | github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY= 427 | github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= 428 | github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= 429 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 430 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 431 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 432 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 433 | github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= 434 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= 435 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 436 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 437 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 438 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 439 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 440 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 441 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 442 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 443 | github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= 444 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 445 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 446 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 447 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 448 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 449 | github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= 450 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 451 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= 452 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= 453 | github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= 454 | github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= 455 | github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= 456 | github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= 457 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= 458 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= 459 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= 460 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= 461 | github.com/raeperd/recvcheck v0.1.2 h1:SjdquRsRXJc26eSonWIo8b7IMtKD3OAT2Lb5G3ZX1+4= 462 | github.com/raeperd/recvcheck v0.1.2/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= 463 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 464 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 465 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 466 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 467 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 468 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 469 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 470 | github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= 471 | github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= 472 | github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= 473 | github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= 474 | github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= 475 | github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= 476 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= 477 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= 478 | github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= 479 | github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= 480 | github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= 481 | github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= 482 | github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk= 483 | github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA= 484 | github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= 485 | github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= 486 | github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= 487 | github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= 488 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 489 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 490 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 491 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 492 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 493 | github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= 494 | github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= 495 | github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY= 496 | github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw= 497 | github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= 498 | github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= 499 | github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= 500 | github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= 501 | github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= 502 | github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= 503 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= 504 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 505 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= 506 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 507 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 508 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 509 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 510 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 511 | github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= 512 | github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= 513 | github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= 514 | github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= 515 | github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= 516 | github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= 517 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 518 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 519 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 520 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 521 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 522 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 523 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 524 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 525 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 526 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 527 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 528 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 529 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 530 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 531 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 532 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 533 | github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= 534 | github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= 535 | github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= 536 | github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= 537 | github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= 538 | github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= 539 | github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= 540 | github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= 541 | github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI= 542 | github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= 543 | github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= 544 | github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= 545 | github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= 546 | github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= 547 | github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= 548 | github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= 549 | github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= 550 | github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= 551 | github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= 552 | github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= 553 | github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= 554 | github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= 555 | github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= 556 | github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= 557 | github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8= 558 | github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= 559 | github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= 560 | github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= 561 | github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= 562 | github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= 563 | github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= 564 | github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= 565 | github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= 566 | github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= 567 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 568 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 569 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 570 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 571 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 572 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 573 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 574 | gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= 575 | gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= 576 | go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= 577 | go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= 578 | go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= 579 | go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= 580 | go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= 581 | go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= 582 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 583 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 584 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 585 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 586 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 587 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 588 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 589 | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= 590 | go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= 591 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 592 | go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 593 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= 594 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 595 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= 596 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= 597 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 598 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 599 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 600 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 601 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 602 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 603 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 604 | golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 605 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 606 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 607 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 608 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 609 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 610 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 611 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 612 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 613 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 614 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 615 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= 616 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 617 | golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 618 | golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 619 | golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA= 620 | golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 621 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 622 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 623 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 624 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 625 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 626 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 627 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 628 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 629 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 630 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 631 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 632 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 633 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 634 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 635 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 636 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 637 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 638 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 639 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 640 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 641 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 642 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 643 | golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 644 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 645 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 646 | golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= 647 | golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 648 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 649 | golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= 650 | golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 651 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 652 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 653 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 654 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 655 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 656 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 657 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 658 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 659 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 660 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 661 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 662 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 663 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 664 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 665 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 666 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 667 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 668 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 669 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 670 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 671 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 672 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 673 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 674 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 675 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 676 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 677 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 678 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 679 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 680 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 681 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 682 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 683 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 684 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 685 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= 686 | golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= 687 | golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= 688 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 689 | golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= 690 | golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 691 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 692 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 693 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 694 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 695 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 696 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 697 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 698 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 699 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 700 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 701 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 702 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 703 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 704 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 705 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 706 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 707 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 708 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 709 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 710 | golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= 711 | golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 712 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 713 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 714 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 715 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 716 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 717 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 718 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 719 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 720 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 721 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 722 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 723 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 724 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 725 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 726 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 727 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 728 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 729 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 730 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 731 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 732 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 733 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 734 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 735 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 736 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 737 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 738 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 739 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 740 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 741 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 742 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 743 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 744 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 745 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 746 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 747 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 748 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 749 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 750 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 751 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 752 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 753 | golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 754 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 755 | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 756 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 757 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 758 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 759 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 760 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 761 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 762 | golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 763 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 764 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 765 | golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= 766 | golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 767 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 768 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 769 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 770 | golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 771 | golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 772 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 773 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 774 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 775 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 776 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 777 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 778 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 779 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 780 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 781 | golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 782 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 783 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 784 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 785 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 786 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 787 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 788 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 789 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 790 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 791 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 792 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 793 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 794 | golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 795 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 796 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 797 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 798 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 799 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 800 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 801 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 802 | golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 803 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 804 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 805 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 806 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 807 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 808 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 809 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 810 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 811 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 812 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 813 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 814 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 815 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 816 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 817 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 818 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 819 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 820 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 821 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 822 | golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 823 | golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 824 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 825 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 826 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 827 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 828 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 829 | golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 830 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 831 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 832 | golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 833 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 834 | golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 835 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 836 | golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= 837 | golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= 838 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 839 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 840 | golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= 841 | golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 842 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 843 | golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= 844 | golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= 845 | golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= 846 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 847 | golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= 848 | golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= 849 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 850 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 851 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 852 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 853 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 854 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 855 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 856 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 857 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 858 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 859 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 860 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 861 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 862 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 863 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 864 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 865 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 866 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 867 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 868 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 869 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 870 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 871 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 872 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 873 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 874 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 875 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 876 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 877 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 878 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 879 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 880 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 881 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 882 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 883 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 884 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 885 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 886 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 887 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 888 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 889 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 890 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 891 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 892 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 893 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 894 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 895 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 896 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 897 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 898 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 899 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 900 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 901 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 902 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 903 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 904 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 905 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 906 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 907 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 908 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 909 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 910 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 911 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 912 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 913 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 914 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 915 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 916 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 917 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 918 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 919 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 920 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 921 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 922 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 923 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 924 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 925 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 926 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 927 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 928 | google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 929 | google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 930 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 931 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 932 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 933 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 934 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 935 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 936 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 937 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 938 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 939 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 940 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 941 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 942 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 943 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 944 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 945 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 946 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 947 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 948 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 949 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 950 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 951 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 952 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 953 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 954 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 955 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 956 | honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= 957 | honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= 958 | mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= 959 | mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= 960 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= 961 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= 962 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 963 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 964 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 965 | -------------------------------------------------------------------------------- /build/golint.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/goyek/goyek/v2" 5 | "github.com/goyek/x/cmd" 6 | ) 7 | 8 | var golint = goyek.Define(goyek.Task{ 9 | Name: "golint", 10 | Usage: "golangci-lint run --fix", 11 | Action: func(a *goyek.A) { 12 | if !cmd.Exec(a, "go install github.com/golangci/golangci-lint/cmd/golangci-lint", cmd.Dir(dirBuild)) { 13 | return 14 | } 15 | cmd.Exec(a, "golangci-lint run --fix", cmd.Dir(dirRoot)) 16 | cmd.Exec(a, "golangci-lint run --fix", cmd.Dir(dirBuild)) 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /build/lint.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/goyek/goyek/v2" 4 | 5 | var lint = goyek.Define(goyek.Task{ 6 | Name: "lint", 7 | Usage: "all linters", 8 | Deps: goyek.Deps{ 9 | golint, 10 | spell, 11 | mdlint, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /build/main.go: -------------------------------------------------------------------------------- 1 | // Build is the build pipeline for this repository. 2 | package main 3 | 4 | import ( 5 | "os" 6 | 7 | "github.com/goyek/goyek/v2" 8 | "github.com/goyek/x/boot" 9 | ) 10 | 11 | // Directories used in repository. 12 | const ( 13 | dirRoot = "." 14 | dirBuild = "build" 15 | ) 16 | 17 | func main() { 18 | if err := os.Chdir(".."); err != nil { 19 | panic(err) 20 | } 21 | goyek.SetDefault(all) 22 | boot.Main() 23 | } 24 | -------------------------------------------------------------------------------- /build/mdlint.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "strings" 7 | 8 | "github.com/goyek/goyek/v2" 9 | "github.com/goyek/x/cmd" 10 | ) 11 | 12 | var mdlint = goyek.Define(goyek.Task{ 13 | Name: "mdlint", 14 | Usage: "markdownlint-cli (uses docker)", 15 | Action: func(a *goyek.A) { 16 | if _, err := exec.LookPath("docker"); err != nil { 17 | a.Skip(err) 18 | } 19 | curDir, err := os.Getwd() 20 | if err != nil { 21 | a.Fatal(err) 22 | } 23 | mdFiles := find(a, ".md") 24 | if len(mdFiles) == 0 { 25 | a.Skip("no .md files") 26 | } 27 | dockerImage := "ghcr.io/igorshubovych/markdownlint-cli:v0.41.0" 28 | cmd.Exec(a, "docker run --rm -v '"+curDir+":/workdir' "+dockerImage+" "+strings.Join(mdFiles, " ")) 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /build/mod.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/goyek/goyek/v2" 5 | "github.com/goyek/x/cmd" 6 | ) 7 | 8 | var mod = goyek.Define(goyek.Task{ 9 | Name: "mod", 10 | Usage: "go mod tidy", 11 | Action: func(a *goyek.A) { 12 | cmd.Exec(a, "go mod tidy", cmd.Dir(dirRoot)) 13 | cmd.Exec(a, "go mod tidy", cmd.Dir(dirBuild)) 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /build/spell.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/goyek/goyek/v2" 7 | "github.com/goyek/x/cmd" 8 | ) 9 | 10 | var spell = goyek.Define(goyek.Task{ 11 | Name: "spell", 12 | Usage: "misspell", 13 | Action: func(a *goyek.A) { 14 | if !cmd.Exec(a, "go install github.com/client9/misspell/cmd/misspell", cmd.Dir(dirBuild)) { 15 | return 16 | } 17 | mdFiles := find(a, ".md") 18 | if len(mdFiles) == 0 { 19 | a.Skip("no .md files") 20 | } 21 | cmd.Exec(a, "misspell -error -locale=US -w "+strings.Join(mdFiles, " ")) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /build/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/goyek/goyek/v2" 5 | "github.com/goyek/x/cmd" 6 | ) 7 | 8 | var test = goyek.Define(goyek.Task{ 9 | Name: "test", 10 | Usage: "go test", 11 | Action: func(a *goyek.A) { 12 | if !cmd.Exec(a, "go test -race -covermode=atomic -coverprofile=coverage.out -coverpkg=./... ./...") { 13 | return 14 | } 15 | cmd.Exec(a, "go tool cover -html=coverage.out -o coverage.html") 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /build/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package main 5 | 6 | // Manage tool dependencies via go.mod. 7 | // 8 | // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 9 | // https://github.com/golang/go/issues/25922 10 | import ( 11 | _ "github.com/client9/misspell/cmd/misspell" 12 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint" 13 | ) 14 | -------------------------------------------------------------------------------- /comparable.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import "fmt" 4 | 5 | // FluentObj encapsulates assertions for comparable object. 6 | type FluentObj[T comparable] struct { 7 | FluentAny[T] 8 | } 9 | 10 | // Obj is used for testing a comparable object. 11 | func Obj[T comparable](got T) FluentObj[T] { 12 | return FluentObj[T]{FluentAny[T]{got}} 13 | } 14 | 15 | // Equal tests the objects using == operator. 16 | func (x FluentObj[T]) Equal(want T) FailureMessage { 17 | if x.Got == want { 18 | return "" 19 | } 20 | return FailureMessage(fmt.Sprintf("the objects are not equal\ngot: %+v\nwant: %+v", x.Got, want)) 21 | } 22 | 23 | // NotEqual tests the objects using != operator. 24 | func (x FluentObj[T]) NotEqual(obj T) FailureMessage { 25 | if x.Got != obj { 26 | return "" 27 | } 28 | return "the objects are equal" 29 | } 30 | 31 | // Zero tests if the object is a zero value. 32 | func (x FluentObj[T]) Zero() FailureMessage { 33 | var want T 34 | if want == x.Got { 35 | return "" 36 | } 37 | return FailureMessage(fmt.Sprintf("not a zero value\ngot: %+v", x.Got)) 38 | } 39 | 40 | // NonZero tests if the object is a non-zero value. 41 | func (x FluentObj[T]) NonZero() FailureMessage { 42 | var want T 43 | if want != x.Got { 44 | return "" 45 | } 46 | return FailureMessage(fmt.Sprintf("not a zero value\ngot: %+v", x.Got)) 47 | } 48 | -------------------------------------------------------------------------------- /comparable_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestObj(t *testing.T) { 10 | type A struct { 11 | Str string 12 | Bool bool 13 | } 14 | 15 | t.Run("Equal", func(t *testing.T) { 16 | t.Run("Passed", func(t *testing.T) { 17 | want := A{Str: "string", Bool: true} 18 | got := A{Str: "string", Bool: true} 19 | msg := verify.Obj(got).Equal(want) 20 | assertPassed(t, msg) 21 | }) 22 | t.Run("Failed", func(t *testing.T) { 23 | want := A{Str: "string", Bool: true} 24 | got := A{Str: "wrong", Bool: true} 25 | msg := verify.Obj(got).Equal(want) 26 | assertFailed(t, msg, "the objects are not equal") 27 | }) 28 | t.Run("nil", func(t *testing.T) { 29 | var got *A 30 | msg := verify.Obj(got).Equal(nil) 31 | assertPassed(t, msg) 32 | }) 33 | }) 34 | 35 | t.Run("NotEqual", func(t *testing.T) { 36 | t.Run("Passed", func(t *testing.T) { 37 | want := A{Str: "string", Bool: true} 38 | got := A{Str: "wrong", Bool: true} 39 | msg := verify.Obj(got).NotEqual(want) 40 | assertPassed(t, msg) 41 | }) 42 | t.Run("Failed", func(t *testing.T) { 43 | want := A{Str: "string", Bool: true} 44 | got := A{Str: "string", Bool: true} 45 | msg := verify.Obj(got).NotEqual(want) 46 | assertFailed(t, msg, "the objects are equal") 47 | }) 48 | t.Run("nil", func(t *testing.T) { 49 | var got *A 50 | msg := verify.Obj(got).NotEqual(nil) 51 | assertFailed(t, msg, "the objects are equal") 52 | }) 53 | }) 54 | 55 | t.Run("Zero", func(t *testing.T) { 56 | t.Run("Passed", func(t *testing.T) { 57 | got := A{} 58 | msg := verify.Obj(got).Zero() 59 | assertPassed(t, msg) 60 | }) 61 | t.Run("Failed", func(t *testing.T) { 62 | got := A{Str: "wrong"} 63 | msg := verify.Obj(got).Zero() 64 | assertFailed(t, msg, "not a zero value\n") 65 | }) 66 | t.Run("nil", func(t *testing.T) { 67 | var got *A 68 | msg := verify.Obj(got).Zero() 69 | assertPassed(t, msg) 70 | }) 71 | }) 72 | 73 | t.Run("NonZero", func(t *testing.T) { 74 | t.Run("Passed", func(t *testing.T) { 75 | got := A{Str: "string"} 76 | msg := verify.Obj(got).NonZero() 77 | assertPassed(t, msg) 78 | }) 79 | t.Run("Failed", func(t *testing.T) { 80 | got := A{} 81 | msg := verify.Obj(got).NonZero() 82 | assertFailed(t, msg, "a zero value") 83 | }) 84 | t.Run("nil", func(t *testing.T) { 85 | var got *A 86 | msg := verify.Obj(got).NonZero() 87 | assertFailed(t, msg, "a zero value") 88 | }) 89 | }) 90 | 91 | t.Run("has assertions from Any", func(t *testing.T) { 92 | want := A{} 93 | got := verify.Obj(want).FluentAny.Got // type embedding done properly 94 | assertEqual(t, got, want) 95 | }) 96 | } 97 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package verify contains the most useful type-safe fluent assertion functions. 2 | // 3 | // It also provides the FailureMessage type which you can use 4 | // for creating your own fluent assertions. 5 | // 6 | // At last, you may embed a Fluent* type 7 | // to extend it with additional assertion functions. 8 | // 9 | // Deprecated: avoid using assertion libraries. 10 | // Use the standard library and [github.com/google/go-cmp/cmp] instead. 11 | // Follow the official [Go Test Comments]. 12 | // 13 | // [Go Test Comments]: https://go.dev/wiki/TestComments 14 | package verify 15 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // NoError tests if the error is nil. 9 | func NoError(err error) FailureMessage { 10 | if err == nil { 11 | return "" 12 | } 13 | return "non-nil error:\n" + FailureMessage(err.Error()) 14 | } 15 | 16 | // IsError tests if the error is non-nil. 17 | func IsError(err error) FailureMessage { 18 | if err != nil { 19 | return "" 20 | } 21 | return "the error is " 22 | } 23 | 24 | // FluentError encapsulates assertions for error object. 25 | type FluentError struct { 26 | FluentAny[error] 27 | FluentString[string] 28 | } 29 | 30 | // Error is used for testing error object. 31 | func Error(got error) FluentError { 32 | res := FluentError{FluentAny: FluentAny[error]{got}} 33 | if got != nil { 34 | res.FluentString.Got = got.Error() 35 | } 36 | return res 37 | } 38 | 39 | // Is tests whether any error in err's chain matches target. 40 | func (x FluentError) Is(target error) FailureMessage { 41 | if errors.Is(x.Got, target) { 42 | return "" 43 | } 44 | return FailureMessage(fmt.Sprintf("no error in err's chain matches\ngot: %#v\ntarget: %#v", x.Got, target)) 45 | } 46 | 47 | // IsNot tests whether no error in err's chain matches target. 48 | func (x FluentError) IsNot(target error) FailureMessage { 49 | if !errors.Is(x.Got, target) { 50 | return "" 51 | } 52 | return FailureMessage(fmt.Sprintf("some error in err's chain matches\ngot: %#v\ntarget: %#v", x.Got, target)) 53 | } 54 | 55 | // As finds the first error in err's chain that matches target, and if one is found, sets 56 | // target to that error value. In such case it is a success.. 57 | func (x FluentError) As(target any) FailureMessage { 58 | if errors.As(x.Got, target) { 59 | return "" 60 | } 61 | return FailureMessage(fmt.Sprintf("no error in err's chain matches\ngot: %#v\ntarget: %T", x.Got, target)) 62 | } 63 | 64 | // AsNot finds the first error in err's chain that matches target, and if one is found, sets 65 | // target to that error value. In such case it is a failure. 66 | func (x FluentError) AsNot(target any) FailureMessage { 67 | if !errors.As(x.Got, target) { 68 | return "" 69 | } 70 | return FailureMessage(fmt.Sprintf("some error in err's chain matches\ngot: %#v\ntarget: %T", x.Got, target)) 71 | } 72 | -------------------------------------------------------------------------------- /error_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/google/go-cmp/cmp/cmpopts" 9 | 10 | "github.com/fluentassert/verify" 11 | ) 12 | 13 | func TestNoError(t *testing.T) { 14 | t.Run("Passed", func(t *testing.T) { 15 | got := verify.NoError(nil) 16 | assertPassed(t, got) 17 | }) 18 | t.Run("Failed", func(t *testing.T) { 19 | got := verify.NoError(errors.New("some error")) 20 | assertFailed(t, got, "non-nil error:\nsome error") 21 | }) 22 | } 23 | 24 | func TestIsError(t *testing.T) { 25 | t.Run("Passed", func(t *testing.T) { 26 | got := verify.IsError(errors.New("")) 27 | assertPassed(t, got) 28 | }) 29 | t.Run("Failed", func(t *testing.T) { 30 | var err error 31 | got := verify.IsError(err) 32 | assertFailed(t, got, "the error is ") 33 | }) 34 | } 35 | 36 | func TestError(t *testing.T) { 37 | err := errors.New("expected error") 38 | t.Run("Is", func(t *testing.T) { 39 | t.Run("Passed", func(t *testing.T) { 40 | got := verify.Error(fmt.Errorf("wrap: %w", err)).Is(err) 41 | assertPassed(t, got) 42 | }) 43 | t.Run("Failed", func(t *testing.T) { 44 | got := verify.Error(fmt.Errorf("wrap: %v", err)).Is(err) 45 | assertFailed(t, got, "no error in err's chain matches") 46 | }) 47 | }) 48 | t.Run("IsNot", func(t *testing.T) { 49 | t.Run("Passed", func(t *testing.T) { 50 | got := verify.Error(fmt.Errorf("wrap: %v", err)).IsNot(err) 51 | assertPassed(t, got) 52 | }) 53 | t.Run("Failed", func(t *testing.T) { 54 | got := verify.Error(fmt.Errorf("wrap: %w", err)).IsNot(err) 55 | assertFailed(t, got, "some error in err's chain matches") 56 | }) 57 | }) 58 | 59 | t.Run("As", func(t *testing.T) { 60 | t.Run("Passed", func(t *testing.T) { 61 | var wantErr *stubError 62 | got := verify.Error(fmt.Errorf("wrap: %w", &stubError{})).As(&wantErr) 63 | assertPassed(t, got) 64 | assertEqual(t, wantErr, &stubError{}) 65 | }) 66 | t.Run("Failed", func(t *testing.T) { 67 | var wantErr *stubError 68 | got := verify.Error(fmt.Errorf("wrap: %v", &stubError{})).As(&wantErr) 69 | assertFailed(t, got, "no error in err's chain matches") 70 | assertEqual(t, wantErr, nil) 71 | }) 72 | }) 73 | t.Run("AsNot", func(t *testing.T) { 74 | t.Run("Passed", func(t *testing.T) { 75 | var wantErr *stubError 76 | got := verify.Error(fmt.Errorf("wrap: %v", &stubError{})).AsNot(&wantErr) 77 | assertPassed(t, got) 78 | assertEqual(t, wantErr, nil) 79 | }) 80 | t.Run("Failed", func(t *testing.T) { 81 | var wantErr *stubError 82 | got := verify.Error(fmt.Errorf("wrap: %w", &stubError{})).AsNot(&wantErr) 83 | assertFailed(t, got, "some error in err's chain matches") 84 | assertEqual(t, wantErr, &stubError{}) 85 | }) 86 | }) 87 | 88 | t.Run("has assertions from Any", func(t *testing.T) { 89 | want := errors.New("an error") 90 | got := verify.Error(want).FluentAny.Got // type embedding done properly 91 | assertEqual(t, got, want, cmpopts.EquateErrors()) 92 | }) 93 | t.Run("has assertions from String, Ordered, Obj for string", func(t *testing.T) { 94 | want := "an error" 95 | got := verify.Error(errors.New(want)).FluentString.Got // type embedding done properly 96 | assertEqual(t, got, want) 97 | }) 98 | } 99 | 100 | type stubError struct{} 101 | 102 | func (*stubError) Error() string { return "stubError" } 103 | -------------------------------------------------------------------------------- /eventually.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Eventually executes the test function until it returns an empty FailureMessage 8 | // or timeout elapses. 9 | func Eventually(timeout, interval time.Duration, fn func() FailureMessage) FailureMessage { 10 | timer := time.NewTimer(timeout) 11 | defer timer.Stop() 12 | ticker := time.NewTicker(interval) 13 | defer ticker.Stop() 14 | return EventuallyChan(timer.C, ticker.C, fn) 15 | } 16 | 17 | // EventuallyChan executes the test function until it returns an empty FailureMessage or timeout elapses. 18 | func EventuallyChan[TTimerPayload, TTickPayload any](timeout <-chan (TTimerPayload), ticker <-chan (TTickPayload), fn func() FailureMessage) FailureMessage { 19 | var err string 20 | fail := func() FailureMessage { 21 | return FailureMessage("function never passed, last failure message:\n" + err) 22 | } 23 | 24 | for { 25 | select { 26 | case <-timeout: 27 | return fail() 28 | default: 29 | } 30 | 31 | err = string(fn()) 32 | 33 | select { 34 | case <-timeout: 35 | return fail() 36 | default: 37 | } 38 | 39 | if err == "" { 40 | return "" 41 | } 42 | 43 | select { 44 | case <-timeout: 45 | return fail() 46 | case <-ticker: 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /eventually_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/fluentassert/verify" 8 | ) 9 | 10 | func TestEventually(t *testing.T) { 11 | timeout := 100 * time.Millisecond 12 | interval := 10 * time.Millisecond 13 | 14 | t.Run("InitialPassed", func(t *testing.T) { 15 | msg := verify.Eventually(timeout, interval, func() verify.FailureMessage { 16 | return "" 17 | }) 18 | assertPassed(t, msg) 19 | }) 20 | t.Run("SecondPassed", func(t *testing.T) { 21 | shouldPass := false 22 | msg := verify.Eventually(timeout, interval, func() verify.FailureMessage { 23 | if !shouldPass { 24 | shouldPass = true // next exeucution will pass 25 | return "fail" 26 | } 27 | return "" 28 | }) 29 | assertPassed(t, msg) 30 | }) 31 | t.Run("ReturnedTooLate", func(t *testing.T) { 32 | msg := verify.Eventually(timeout, interval, func() verify.FailureMessage { 33 | time.Sleep(2 * timeout) 34 | return "" 35 | }) 36 | assertFailed(t, msg, "function never passed, last failure message:\n") 37 | }) 38 | t.Run("Failed", func(t *testing.T) { 39 | msg := verify.Eventually(timeout, interval, func() verify.FailureMessage { 40 | return "constant failure" 41 | }) 42 | assertFailed(t, msg, "function never passed, last failure message:\nconstant failure") 43 | }) 44 | } 45 | 46 | func TestEventuallyChan(t *testing.T) { 47 | timeout := 100 * time.Millisecond 48 | interval := 10 * time.Millisecond 49 | 50 | t.Run("Passed", func(t *testing.T) { 51 | timer := time.NewTimer(timeout) 52 | defer timer.Stop() 53 | ticker := time.NewTicker(interval) 54 | defer ticker.Stop() 55 | msg := verify.EventuallyChan(timer.C, ticker.C, func() verify.FailureMessage { 56 | return "" 57 | }) 58 | assertPassed(t, msg) 59 | }) 60 | t.Run("TimeoutBeforeStart", func(t *testing.T) { 61 | ch := make(chan struct{}) 62 | close(ch) 63 | msg := verify.EventuallyChan(ch, ch, func() verify.FailureMessage { 64 | return "" 65 | }) 66 | assertFailed(t, msg, "function never passed, last failure message:\n") 67 | }) 68 | t.Run("Failed", func(t *testing.T) { 69 | ch := make(chan struct{}) 70 | msg := verify.EventuallyChan(time.After(timeout), ch, func() verify.FailureMessage { 71 | return "constant failure" 72 | }) 73 | assertFailed(t, msg, "function never passed, last failure message:\nconstant failure") 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /failmsg.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | // FailureMessage encapsulates a failure message 4 | // that can by emitted using objects compatible 5 | // with the testing.TB interface. 6 | type FailureMessage string 7 | 8 | // Assert calls t.Error if the failure message is not empty. 9 | // Calling Error on *testing.T marks the the function as having failed 10 | // and continues its execution. 11 | // Returns true when the failure message is empty. 12 | func (msg FailureMessage) Assert(t interface { 13 | Error(args ...any) 14 | }, args ...any, 15 | ) bool { 16 | if msg == "" { 17 | return true 18 | } 19 | if h, ok := t.(interface{ Helper() }); ok { 20 | h.Helper() 21 | } 22 | t.Error(append(args, "\n"+string(msg))...) 23 | return false 24 | } 25 | 26 | // Require calls t.Fatal if the failure message is not empty. 27 | // Calling Fatal on *testing.T stops the test function execution. 28 | // Returns true when the failure message is empty. 29 | func (msg FailureMessage) Require(t interface { 30 | Fatal(args ...any) 31 | }, args ...any, 32 | ) bool { 33 | if msg == "" { 34 | return true 35 | } 36 | if h, ok := t.(interface{ Helper() }); ok { 37 | h.Helper() 38 | } 39 | t.Fatal(append(args, "\n"+string(msg))...) 40 | return false 41 | } 42 | 43 | // Assertf calls t.Errorf if the failure message is not empty. 44 | // Calling Errorf on *testing.T marks the the function as having failed 45 | // and continues its execution. 46 | // Returns true when the failure message is empty 47 | func (msg FailureMessage) Assertf(t interface { 48 | Errorf(format string, args ...any) 49 | }, format string, args ...any, 50 | ) bool { 51 | if msg == "" { 52 | return true 53 | } 54 | if h, ok := t.(interface{ Helper() }); ok { 55 | h.Helper() 56 | } 57 | t.Errorf(format+"%s", append(args, "\n"+string(msg))...) 58 | return false 59 | } 60 | 61 | // Requiref calls t.Fatalf if the failure message is not empty. 62 | // Calling Fatalf on *testing.T stops the test function execution. 63 | // Returns true when the failure message is empty. 64 | func (msg FailureMessage) Requiref(t interface { 65 | Fatalf(format string, args ...any) 66 | }, format string, args ...any, 67 | ) bool { 68 | if msg == "" { 69 | return true 70 | } 71 | if h, ok := t.(interface{ Helper() }); ok { 72 | h.Helper() 73 | } 74 | t.Fatalf(format+"%s", append(args, "\n"+string(msg))...) 75 | return false 76 | } 77 | 78 | // Prefix adds prefix if the failure message is not empty. 79 | func (msg FailureMessage) Prefix(s string) FailureMessage { 80 | if msg == "" { 81 | return "" 82 | } 83 | return FailureMessage(s) + msg 84 | } 85 | 86 | // Err returns the failure message as an error type, or nil if the message is empty. 87 | func (msg FailureMessage) Err() *AssertionError { 88 | if msg == "" { 89 | return nil 90 | } 91 | 92 | return &AssertionError{Message: msg} 93 | } 94 | -------------------------------------------------------------------------------- /failmsg_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestFailureMessage(t *testing.T) { 10 | t.Run("Assert", func(t *testing.T) { 11 | t.Run("Empty", func(t *testing.T) { 12 | mock := &errorMock{} 13 | got := verify.FailureMessage("").Assert(mock) 14 | assertTrue(t, got) 15 | assertEqual(t, mock, &errorMock{}) 16 | }) 17 | t.Run("NoArgs", func(t *testing.T) { 18 | mock := &errorMock{} 19 | got := verify.FailureMessage("failed").Assert(mock) 20 | assertFalse(t, got) 21 | assertEqual(t, mock, &errorMock{ 22 | HelperCalled: true, 23 | Called: true, 24 | Args: []any{"\nfailed"}, 25 | }) 26 | }) 27 | t.Run("WithArgs", func(t *testing.T) { 28 | mock := &errorMock{} 29 | got := verify.FailureMessage("failed").Assert(mock, "arg1", 2) 30 | assertFalse(t, got) 31 | assertEqual(t, mock, &errorMock{ 32 | HelperCalled: true, 33 | Called: true, 34 | Args: []any{"arg1", 2, "\nfailed"}, 35 | }) 36 | }) 37 | }) 38 | 39 | t.Run("Require", func(t *testing.T) { 40 | t.Run("Empty", func(t *testing.T) { 41 | mock := &fatalMock{} 42 | got := verify.FailureMessage("").Require(mock) 43 | assertTrue(t, got) 44 | assertEqual(t, mock, &fatalMock{}) 45 | }) 46 | t.Run("NoArgs", func(t *testing.T) { 47 | mock := &fatalMock{} 48 | got := verify.FailureMessage("failed").Require(mock) 49 | assertFalse(t, got) 50 | assertEqual(t, mock, &fatalMock{ 51 | HelperCalled: true, 52 | Called: true, 53 | Args: []any{"\nfailed"}, 54 | }) 55 | }) 56 | t.Run("WithArgs", func(t *testing.T) { 57 | mock := &fatalMock{} 58 | got := verify.FailureMessage("failed").Require(mock, "arg1", 2) 59 | assertFalse(t, got) 60 | assertEqual(t, mock, &fatalMock{ 61 | HelperCalled: true, 62 | Called: true, 63 | Args: []any{"arg1", 2, "\nfailed"}, 64 | }) 65 | }) 66 | }) 67 | 68 | t.Run("Assertf", func(t *testing.T) { 69 | t.Run("Empty", func(t *testing.T) { 70 | mock := &errorfMock{} 71 | got := verify.FailureMessage("").Assertf(mock, "should pass") 72 | assertTrue(t, got) 73 | assertEqual(t, mock, &errorfMock{}) 74 | }) 75 | t.Run("NoArgs", func(t *testing.T) { 76 | mock := &errorfMock{} 77 | got := verify.FailureMessage("failed").Assertf(mock, "should pass") 78 | assertFalse(t, got) 79 | assertEqual(t, mock, &errorfMock{ 80 | HelperCalled: true, 81 | Called: true, 82 | Format: "should pass%s", 83 | Args: []any{"\nfailed"}, 84 | }) 85 | }) 86 | t.Run("WithArgs", func(t *testing.T) { 87 | mock := &errorfMock{} 88 | got := verify.FailureMessage("failed").Assertf(mock, "should work %d", 1) 89 | assertFalse(t, got) 90 | assertEqual(t, mock, &errorfMock{ 91 | HelperCalled: true, 92 | Called: true, 93 | Format: "should work %d%s", 94 | Args: []any{1, "\nfailed"}, 95 | }) 96 | }) 97 | }) 98 | 99 | t.Run("Requiref", func(t *testing.T) { 100 | t.Run("Empty", func(t *testing.T) { 101 | mock := &fatalfMock{} 102 | got := verify.FailureMessage("").Requiref(mock, "should pass") 103 | assertTrue(t, got) 104 | assertEqual(t, mock, &fatalfMock{}) 105 | }) 106 | t.Run("NoArgs", func(t *testing.T) { 107 | mock := &fatalfMock{} 108 | got := verify.FailureMessage("failed").Requiref(mock, "should pass") 109 | assertFalse(t, got) 110 | assertEqual(t, mock, &fatalfMock{ 111 | HelperCalled: true, 112 | Called: true, 113 | Format: "should pass%s", 114 | Args: []any{"\nfailed"}, 115 | }) 116 | }) 117 | t.Run("WithArgs", func(t *testing.T) { 118 | mock := &fatalfMock{} 119 | got := verify.FailureMessage("failed").Requiref(mock, "should work %d", 1) 120 | assertFalse(t, got) 121 | assertEqual(t, mock, &fatalfMock{ 122 | HelperCalled: true, 123 | Called: true, 124 | Format: "should work %d%s", 125 | Args: []any{1, "\nfailed"}, 126 | }) 127 | }) 128 | }) 129 | 130 | t.Run("Prefix", func(t *testing.T) { 131 | t.Run("Empty", func(t *testing.T) { 132 | got := verify.FailureMessage("").Prefix("[fail]") 133 | assertEqual(t, got, "") 134 | }) 135 | t.Run("Empty", func(t *testing.T) { 136 | got := verify.FailureMessage("errored").Prefix("[fail] ") 137 | assertEqual(t, got, "[fail] errored") 138 | }) 139 | }) 140 | 141 | t.Run("AsError", func(t *testing.T) { 142 | t.Run("With Message", func(t *testing.T) { 143 | got := verify.FailureMessage("failed").Err() 144 | assertEqual(t, got.Error(), "failed") 145 | }) 146 | 147 | t.Run("Empty", func(t *testing.T) { 148 | got := verify.FailureMessage("").Err() 149 | assertEqual(t, got, nil) 150 | }) 151 | }) 152 | } 153 | 154 | type errorMock struct { 155 | Called bool 156 | Args []any 157 | HelperCalled bool 158 | } 159 | 160 | func (mock *errorMock) Error(args ...any) { 161 | mock.Called = true 162 | mock.Args = args 163 | } 164 | 165 | func (mock *errorMock) Helper() { 166 | mock.HelperCalled = true 167 | } 168 | 169 | type fatalMock struct { 170 | Called bool 171 | Args []any 172 | HelperCalled bool 173 | } 174 | 175 | func (mock *fatalMock) Fatal(args ...any) { 176 | mock.Called = true 177 | mock.Args = args 178 | } 179 | 180 | func (mock *fatalMock) Helper() { 181 | mock.HelperCalled = true 182 | } 183 | 184 | type errorfMock struct { 185 | Called bool 186 | Format string 187 | Args []any 188 | HelperCalled bool 189 | } 190 | 191 | func (mock *errorfMock) Errorf(format string, args ...any) { 192 | mock.Called = true 193 | mock.Format = format 194 | mock.Args = args 195 | } 196 | 197 | func (mock *errorfMock) Helper() { 198 | mock.HelperCalled = true 199 | } 200 | 201 | type fatalfMock struct { 202 | Called bool 203 | Format string 204 | Args []any 205 | HelperCalled bool 206 | } 207 | 208 | func (mock *fatalfMock) Fatalf(format string, args ...any) { 209 | mock.Called = true 210 | mock.Format = format 211 | mock.Args = args 212 | } 213 | 214 | func (mock *fatalfMock) Helper() { 215 | mock.HelperCalled = true 216 | } 217 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // Deprecated: avoid using assertion libraries. 2 | // Use the standard library and github.com/google/go-cmp/cmp instead. 3 | // Follow the official Go Test Comments: https://go.dev/wiki/TestComments. 4 | module github.com/fluentassert/verify 5 | 6 | go 1.18 7 | 8 | require github.com/google/go-cmp v0.6.0 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 2 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 3 | -------------------------------------------------------------------------------- /goyek.ps1: -------------------------------------------------------------------------------- 1 | Push-Location "$PSScriptRoot\build" -ErrorAction Stop 2 | & go run . $args 3 | Pop-Location 4 | exit $global:LASTEXITCODE 5 | -------------------------------------------------------------------------------- /goyek.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 5 | cd "$DIR/build" 6 | go run . $@ -------------------------------------------------------------------------------- /helpers_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/google/go-cmp/cmp" 8 | 9 | "github.com/fluentassert/verify" 10 | ) 11 | 12 | func assertEqual[T any](t *testing.T, got, want T, opts ...cmp.Option) { 13 | t.Helper() 14 | if diff := cmp.Diff(want, got, opts...); diff != "" { 15 | t.Errorf("mismatch (-want +got):\n%s", diff) 16 | } 17 | } 18 | 19 | func assertTrue(t *testing.T, got bool) { 20 | t.Helper() 21 | if !got { 22 | t.Errorf("want = true; got = false") 23 | } 24 | } 25 | 26 | func assertFalse(t *testing.T, got bool) { 27 | t.Helper() 28 | if got { 29 | t.Errorf("want = true; got = false") 30 | } 31 | } 32 | 33 | func assertPassed(t *testing.T, got verify.FailureMessage) { 34 | t.Helper() 35 | if got != "" { 36 | t.Errorf("\nSHOULD PASS; GOT:\n%s", string(got)) 37 | } 38 | } 39 | 40 | func assertFailed(t *testing.T, got verify.FailureMessage, substr string) { 41 | t.Helper() 42 | if !strings.Contains(string(got), substr) { 43 | t.Errorf("\nSHOULD FAIL AND CONTAIN:\n%s\nGOT:\n%s", substr, string(got)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | ) 8 | 9 | // FluentMap encapsulates assertions for a map. 10 | type FluentMap[K comparable, V any] struct { 11 | FluentAny[map[K]V] 12 | } 13 | 14 | // Map is used for testing a map. 15 | func Map[K comparable, V any](got map[K]V) FluentMap[K, V] { 16 | return FluentMap[K, V]{FluentAny[map[K]V]{got}} 17 | } 18 | 19 | // Empty tests if the slice is empty. 20 | func (x FluentMap[K, V]) Empty() FailureMessage { 21 | if len(x.Got) == 0 { 22 | return "" 23 | } 24 | return FailureMessage(fmt.Sprintf("not an empty map\ngot: %+v", x.Got)) 25 | } 26 | 27 | // NotEmpty tests if the slice is not empty. 28 | func (x FluentMap[K, V]) NotEmpty() FailureMessage { 29 | if len(x.Got) > 0 { 30 | return "" 31 | } 32 | return FailureMessage(fmt.Sprintf("an empty map\ngot: %+v", x.Got)) 33 | } 34 | 35 | // Contain tests if the map contains all pairs from want. 36 | func (x FluentMap[K, V]) Contain(want map[K]V, opts ...cmp.Option) FailureMessage { 37 | missing := x.miss(want, opts) 38 | if len(missing) == 0 { 39 | return "" 40 | } 41 | return FailureMessage(fmt.Sprintf("not contains all pairs\ngot: %+v\nwant: %+v\nmissing: %+v", x.Got, want, missing)) 42 | } 43 | 44 | // NotContain tests if the map does not contains all pairs from want. 45 | func (x FluentMap[K, V]) NotContain(want map[K]V, opts ...cmp.Option) FailureMessage { 46 | missing := x.miss(want, opts) 47 | if len(missing) > 0 { 48 | return "" 49 | } 50 | return FailureMessage(fmt.Sprintf("contains all pairs\ngot: %+v\nwant: %+v", x.Got, want)) 51 | } 52 | 53 | func (x FluentMap[K, V]) miss(want map[K]V, opts []cmp.Option) map[K]V { 54 | missing := map[K]V{} 55 | for k, v := range want { 56 | got, ok := x.Got[k] 57 | if !ok { 58 | missing[k] = v 59 | continue 60 | } 61 | if !cmp.Equal(v, got, opts...) { 62 | missing[k] = v 63 | continue 64 | } 65 | } 66 | return missing 67 | } 68 | 69 | // ContainPair tests if the map contains the pair. 70 | func (x FluentMap[K, V]) ContainPair(k K, v V, opts ...cmp.Option) FailureMessage { 71 | got, ok := x.Got[k] 72 | if !ok { 73 | return FailureMessage(fmt.Sprintf("has no value under key\ngot: %+v\nkey: %+v\nvalue: %+v", x.Got, k, v)) 74 | } 75 | if !cmp.Equal(v, got, opts...) { 76 | return FailureMessage(fmt.Sprintf("has different value under key\nkey: %+v\ngot: %+v\nwant: %+v", k, got, v)) 77 | } 78 | return "" 79 | } 80 | 81 | // NotContainPair tests if the map does not contain the pair. 82 | func (x FluentMap[K, V]) NotContainPair(k K, v V, opts ...cmp.Option) FailureMessage { 83 | got, ok := x.Got[k] 84 | if !ok { 85 | return "" 86 | } 87 | if !cmp.Equal(v, got, opts...) { 88 | return "" 89 | } 90 | return FailureMessage(fmt.Sprintf("contains the pair\ngot: %+v\nkey: %+v\nvalue: %+v", x.Got, k, v)) 91 | } 92 | 93 | // Any tests if any of the map's pairs meets the predicate criteria. 94 | func (x FluentMap[K, V]) Any(predicate func(K, V) bool) FailureMessage { 95 | for k, v := range x.Got { 96 | if predicate(k, v) { 97 | return "" 98 | } 99 | } 100 | return FailureMessage(fmt.Sprintf("none pair does meet the predicate criteria\ngot: %+v", x.Got)) 101 | } 102 | 103 | // All tests if all of the map's pairs meet the predicate criteria. 104 | func (x FluentMap[K, V]) All(predicate func(K, V) bool) FailureMessage { 105 | for k, v := range x.Got { 106 | if !predicate(k, v) { 107 | return FailureMessage(fmt.Sprintf("a pair does not meet the predicate criteria\ngot: %+v\npair: %+v", x.Got, v)) 108 | } 109 | } 110 | return "" 111 | } 112 | 113 | // None tests if none of the map's pairs meets the predicate criteria. 114 | func (x FluentMap[K, V]) None(predicate func(K, V) bool) FailureMessage { 115 | for k, v := range x.Got { 116 | if predicate(k, v) { 117 | return FailureMessage(fmt.Sprintf("a pair meets the predicate criteria\ngot: %+v\npair: %+v", x.Got, v)) 118 | } 119 | } 120 | return "" 121 | } 122 | 123 | // Len tests the length of the map. 124 | func (x FluentMap[K, V]) Len(want int) FailureMessage { 125 | gotLen := len(x.Got) 126 | if gotLen != want { 127 | return FailureMessage(fmt.Sprintf("has different length\ngot: %+v\nlen: %v\nwant: %v", x.Got, gotLen, want)) 128 | } 129 | return "" 130 | } 131 | -------------------------------------------------------------------------------- /map_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestMap(t *testing.T) { 10 | type A struct { 11 | Str string 12 | Bool bool 13 | Slice []int 14 | } 15 | 16 | t.Run("has assertions from Any", func(t *testing.T) { 17 | want := map[string]A{ 18 | "id": {Str: "string", Bool: true, Slice: []int{1, 2, 3}}, 19 | } 20 | got := verify.Map(want).FluentAny.Got // type embedding done properly 21 | assertEqual(t, got, want) 22 | }) 23 | 24 | dict := map[string]A{ 25 | "a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 26 | "b": {Slice: []int{9, 8, 7}}, 27 | } 28 | has := map[string]A{ 29 | "a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 30 | } 31 | notHas := map[string]A{ 32 | "a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 33 | "b": {Slice: []int{1, 4, 7}}, 34 | "c": {Slice: []int{9, 8, 7}}, 35 | } 36 | t.Run("Empty", func(t *testing.T) { 37 | t.Run("Passed", func(t *testing.T) { 38 | got := verify.Map(map[string]A{}).Empty() 39 | assertPassed(t, got) 40 | }) 41 | t.Run("Failed", func(t *testing.T) { 42 | got := verify.Map(dict).Empty() 43 | assertFailed(t, got, "not an empty map") 44 | }) 45 | }) 46 | t.Run("NotEmpty", func(t *testing.T) { 47 | t.Run("Passed", func(t *testing.T) { 48 | got := verify.Map(dict).NotEmpty() 49 | assertPassed(t, got) 50 | }) 51 | t.Run("Failed", func(t *testing.T) { 52 | got := verify.Map(map[string]A{}).NotEmpty() 53 | assertFailed(t, got, "an empty map") 54 | }) 55 | }) 56 | 57 | t.Run("Contain", func(t *testing.T) { 58 | t.Run("Passed", func(t *testing.T) { 59 | got := verify.Map(dict).Contain(has) 60 | assertPassed(t, got) 61 | }) 62 | t.Run("Failed", func(t *testing.T) { 63 | got := verify.Map(dict).Contain(notHas) 64 | assertFailed(t, got, "not contains all pairs") 65 | }) 66 | }) 67 | t.Run("NotContain", func(t *testing.T) { 68 | t.Run("Passed", func(t *testing.T) { 69 | got := verify.Map(dict).NotContain(notHas) 70 | assertPassed(t, got) 71 | }) 72 | t.Run("Failed", func(t *testing.T) { 73 | got := verify.Map(dict).NotContain(has) 74 | assertFailed(t, got, "contains all pairs") 75 | }) 76 | }) 77 | 78 | t.Run("ContainPair", func(t *testing.T) { 79 | t.Run("Has", func(t *testing.T) { 80 | got := verify.Map(dict).ContainPair("b", A{Slice: []int{9, 8, 7}}) 81 | assertPassed(t, got) 82 | }) 83 | t.Run("DiffKey", func(t *testing.T) { 84 | got := verify.Map(dict).ContainPair("z", A{Slice: []int{9, 8, 7}}) 85 | assertFailed(t, got, "has no value under key") 86 | }) 87 | t.Run("DiffValue", func(t *testing.T) { 88 | got := verify.Map(dict).ContainPair("b", A{Slice: []int{1, 1, 1}}) 89 | assertFailed(t, got, "has different value under key") 90 | }) 91 | }) 92 | t.Run("NotContainPair", func(t *testing.T) { 93 | t.Run("Has", func(t *testing.T) { 94 | got := verify.Map(dict).NotContainPair("b", A{Slice: []int{9, 8, 7}}) 95 | assertFailed(t, got, "contains the pair") 96 | }) 97 | t.Run("DiffKey", func(t *testing.T) { 98 | got := verify.Map(dict).NotContainPair("z", A{Slice: []int{9, 8, 7}}) 99 | assertPassed(t, got) 100 | }) 101 | t.Run("DiffValue", func(t *testing.T) { 102 | got := verify.Map(dict).NotContainPair("b", A{Slice: []int{1, 1, 1}}) 103 | assertPassed(t, got) 104 | }) 105 | }) 106 | 107 | t.Run("Any", func(t *testing.T) { 108 | t.Run("Passed", func(t *testing.T) { 109 | got := verify.Map(dict).Any(func(string, A) bool { return true }) 110 | assertPassed(t, got) 111 | }) 112 | t.Run("Failed", func(t *testing.T) { 113 | got := verify.Map(dict).Any(func(string, A) bool { return false }) 114 | assertFailed(t, got, "none pair does meet the predicate criteria") 115 | }) 116 | }) 117 | t.Run("All", func(t *testing.T) { 118 | t.Run("Passed", func(t *testing.T) { 119 | got := verify.Map(dict).All(func(string, A) bool { return true }) 120 | assertPassed(t, got) 121 | }) 122 | t.Run("Failed", func(t *testing.T) { 123 | got := verify.Map(dict).All(func(string, A) bool { return false }) 124 | assertFailed(t, got, "a pair does not meet the predicate criteria") 125 | }) 126 | }) 127 | t.Run("None", func(t *testing.T) { 128 | t.Run("Passed", func(t *testing.T) { 129 | got := verify.Map(dict).None(func(string, A) bool { return false }) 130 | assertPassed(t, got) 131 | }) 132 | t.Run("Failed", func(t *testing.T) { 133 | got := verify.Map(dict).None(func(string, A) bool { return true }) 134 | assertFailed(t, got, "a pair meets the predicate criteria") 135 | }) 136 | }) 137 | 138 | t.Run("Len", func(t *testing.T) { 139 | t.Run("Passed", func(t *testing.T) { 140 | got := verify.Map(dict).Len(len(dict)) 141 | assertPassed(t, got) 142 | }) 143 | t.Run("Failed", func(t *testing.T) { 144 | got := verify.Map(dict).Len(10) 145 | assertFailed(t, got, "has different length") 146 | }) 147 | }) 148 | } 149 | -------------------------------------------------------------------------------- /nil.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import "fmt" 4 | 5 | // Nil tests if provided interface value is nil. 6 | // Use it only for interfaces. 7 | // For structs and pointers use Obj(got).Zero(). 8 | func Nil(v any) FailureMessage { 9 | if v == nil { 10 | return "" 11 | } 12 | return FailureMessage(fmt.Sprintf("value is not nil\ngot: %+v", v)) 13 | } 14 | 15 | // NotNil tests if provided interface is not nil. 16 | // Use it only for interfaces. 17 | // For structs and pointers use Obj(got).NonZero(). 18 | func NotNil(v any) FailureMessage { 19 | if v != nil { 20 | return "" 21 | } 22 | return "value is " 23 | } 24 | -------------------------------------------------------------------------------- /nil_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestNil(t *testing.T) { 10 | t.Run("Passed", func(t *testing.T) { 11 | var err error 12 | msg := verify.Nil(err) 13 | assertPassed(t, msg) 14 | }) 15 | t.Run("Failed", func(t *testing.T) { 16 | msg := verify.Nil(0) 17 | assertFailed(t, msg, "value is not nil") 18 | }) 19 | } 20 | 21 | func TestNotNil(t *testing.T) { 22 | t.Run("Passed", func(t *testing.T) { 23 | msg := verify.NotNil(0) 24 | assertPassed(t, msg) 25 | }) 26 | t.Run("Failed", func(t *testing.T) { 27 | var err error 28 | msg := verify.NotNil(err) 29 | assertFailed(t, msg, "value is ") 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /number.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | // FluentNumber encapsulates assertions for numbers 9 | // that supports the operators < <= >= > + - * /. 10 | type FluentNumber[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64] struct { 11 | FluentOrdered[T] 12 | } 13 | 14 | // Number is used for testing numbers 15 | // that supports the operators < <= >= > + - * /. 16 | func Number[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64](got T) FluentNumber[T] { 17 | return FluentNumber[T]{FluentOrdered[T]{FluentObj[T]{FluentAny[T]{got}}}} 18 | } 19 | 20 | // InDelta tests that the numbers have an absolute error (distance) less or equal than delta. 21 | func (x FluentNumber[T]) InDelta(want T, delta float64) FailureMessage { 22 | distance, msg := x.calcDistance(want, delta) 23 | if msg != "" { 24 | return msg 25 | } 26 | if distance < -delta || distance > delta { 27 | return FailureMessage(fmt.Sprintf("absolute error (distance) between numbers is greater than delta\nrelative error: %v\ndelta: %g\ngot: %v\nwant: %v", distance, delta, x.Got, want)) 28 | } 29 | return "" 30 | } 31 | 32 | // NotInDelta tests that the numbers have an absolute error (distance) greater than delta. 33 | func (x FluentNumber[T]) NotInDelta(want T, delta float64) FailureMessage { 34 | distance, msg := x.calcDistance(want, delta) 35 | if msg != "" { 36 | return msg 37 | } 38 | if distance < -delta || distance > delta { 39 | return "" 40 | } 41 | return FailureMessage(fmt.Sprintf("absolute error (distance) between numbers is lesser or equal than delta\nrelative error: %v\ndelta: %g\ngot: %v\nwant: %v", distance, delta, x.Got, want)) 42 | } 43 | 44 | func (x FluentNumber[T]) calcDistance(want T, delta float64) (float64, FailureMessage) { 45 | if math.IsNaN(delta) || delta < 0 { 46 | return 0, "delta must be a non-negative number" 47 | } 48 | wantF := float64(want) 49 | gotF := float64(x.Got) 50 | if math.IsNaN(wantF) { 51 | return 0, "want is NaN" 52 | } 53 | if math.IsNaN(gotF) { 54 | return 0, "got is NaN" 55 | } 56 | return wantF - gotF, "" 57 | } 58 | 59 | // InEpsilon tests that the numbers have a relative error less or equal than epsilon. 60 | func (x FluentNumber[T]) InEpsilon(want T, epsilon float64) FailureMessage { 61 | relativeError, msg := x.calcRelativeError(want, epsilon) 62 | if msg != "" { 63 | return msg 64 | } 65 | if relativeError > epsilon { 66 | return FailureMessage(fmt.Sprintf("relative error between numbers is greater than epsilon\nrelative error: %g\nepsilon: %g\ngot: %v\nwant: %v", relativeError, epsilon, x.Got, want)) 67 | } 68 | return "" 69 | } 70 | 71 | // NotInEpsilon tests that the numbers have a relative error greater than epsilon. 72 | func (x FluentNumber[T]) NotInEpsilon(want T, epsilon float64) FailureMessage { 73 | relativeError, msg := x.calcRelativeError(want, epsilon) 74 | if msg != "" { 75 | return msg 76 | } 77 | if relativeError > epsilon { 78 | return "" 79 | } 80 | return FailureMessage(fmt.Sprintf("relative error between numbers is lesser or equal than epsilon\nrelative error: %g\nepsilon: %g\ngot: %v\nto: %v", relativeError, epsilon, x.Got, want)) 81 | } 82 | 83 | func (x FluentNumber[T]) calcRelativeError(want T, epsilon float64) (float64, FailureMessage) { 84 | if math.IsNaN(epsilon) || epsilon < 0 { 85 | return 0, "epsilon must be a non-negative number" 86 | } 87 | wantF := float64(want) 88 | gotF := float64(x.Got) 89 | if math.IsNaN(wantF) { 90 | return 0, "want is NaN" 91 | } 92 | if math.IsNaN(gotF) { 93 | return 0, "got is NaN" 94 | } 95 | if wantF == 0 { 96 | return 0, "want must have a value other than zero to calculate the relative error" 97 | } 98 | relativeError := math.Abs(wantF-gotF) / math.Abs(wantF) 99 | return relativeError, "" 100 | } 101 | -------------------------------------------------------------------------------- /number_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | 7 | "github.com/fluentassert/verify" 8 | ) 9 | 10 | func TestNumber(t *testing.T) { 11 | t.Run("InDelta", func(t *testing.T) { 12 | t.Run("Near", func(t *testing.T) { 13 | msg := verify.Number(0.0).InDelta(1, 10) 14 | assertPassed(t, msg) 15 | }) 16 | t.Run("Far", func(t *testing.T) { 17 | msg := verify.Number(0.0).InDelta(-100, 10) 18 | assertFailed(t, msg, "absolute error (distance) between numbers is greater than delta") 19 | }) 20 | }) 21 | 22 | t.Run("NotInDelta", func(t *testing.T) { 23 | t.Run("Near", func(t *testing.T) { 24 | msg := verify.Number(0.0).NotInDelta(-1.0, 10) 25 | assertFailed(t, msg, "absolute error (distance) between numbers is lesser or equal than delta") 26 | }) 27 | t.Run("Far", func(t *testing.T) { 28 | msg := verify.Number(0.0).NotInDelta(100, 10) 29 | assertPassed(t, msg) 30 | }) 31 | }) 32 | 33 | t.Run("InEpsilon", func(t *testing.T) { 34 | t.Run("Near", func(t *testing.T) { 35 | msg := verify.Number(1.0).InEpsilon(1, 2) 36 | assertPassed(t, msg) 37 | }) 38 | t.Run("Far", func(t *testing.T) { 39 | msg := verify.Number(100.0).InEpsilon(1, 2) 40 | assertFailed(t, msg, "relative error between numbers is greater than epsilon") 41 | }) 42 | }) 43 | 44 | t.Run("NotInEpsilon", func(t *testing.T) { 45 | t.Run("Near", func(t *testing.T) { 46 | msg := verify.Number(0.0).NotInEpsilon(1, 2) 47 | assertFailed(t, msg, "relative error between numbers is lesser or equal than epsilon") 48 | }) 49 | t.Run("Far", func(t *testing.T) { 50 | msg := verify.Number(100.0).NotInEpsilon(1, 2) 51 | assertPassed(t, msg) 52 | }) 53 | }) 54 | 55 | t.Run("InvalidInputs", func(t *testing.T) { 56 | for _, fn := range []func() verify.FailureMessage{ 57 | func() verify.FailureMessage { 58 | return verify.Number(math.NaN()).InDelta(1, 2) 59 | }, 60 | func() verify.FailureMessage { 61 | return verify.Number(1.0).NotInDelta(math.NaN(), 2) 62 | }, 63 | func() verify.FailureMessage { 64 | return verify.Number(1.0).InDelta(1, -2) 65 | }, 66 | func() verify.FailureMessage { 67 | return verify.Number(math.NaN()).InEpsilon(1, 2) 68 | }, 69 | func() verify.FailureMessage { 70 | return verify.Number(1.0).NotInEpsilon(math.NaN(), 2) 71 | }, 72 | func() verify.FailureMessage { 73 | return verify.Number(1.0).InEpsilon(1, -2) 74 | }, 75 | func() verify.FailureMessage { 76 | return verify.Number(1.0).InEpsilon(0.0, 2) 77 | }, 78 | } { 79 | if msg := fn(); msg == "" { 80 | t.Error("should fail but passed") 81 | } 82 | } 83 | }) 84 | } 85 | -------------------------------------------------------------------------------- /or.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | // Or accumalates failure messages if all are not empty. 4 | func Or(assertions ...FailureMessage) FailureMessage { 5 | var msg FailureMessage 6 | for _, assertion := range assertions { 7 | if assertion == "" { 8 | return "" 9 | } 10 | if msg == "" { 11 | msg = assertion 12 | continue 13 | } 14 | msg = msg + "\n\n" + assertion 15 | } 16 | return msg 17 | } 18 | -------------------------------------------------------------------------------- /or_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestOr(t *testing.T) { 10 | t.Run("Empty", func(t *testing.T) { 11 | msg := verify.Or() 12 | assertPassed(t, msg) 13 | }) 14 | t.Run("NoneFailed", func(t *testing.T) { 15 | msg := verify.Or("", "") 16 | assertPassed(t, msg) 17 | }) 18 | t.Run("OneFailed", func(t *testing.T) { 19 | msg := verify.Or("", "failure") 20 | assertPassed(t, msg) 21 | }) 22 | t.Run("TwoFailed", func(t *testing.T) { 23 | msg := verify.Or("one", "two") 24 | assertFailed(t, msg, "one\n\ntwo") 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /ordered.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // FluentOrdered encapsulates assertions for ordered object 8 | // that supports the operators < <= >= >. 9 | type FluentOrdered[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string] struct { 10 | FluentObj[T] 11 | } 12 | 13 | // Ordered is used for testing a ordered object 14 | // that supports the operators < <= >= >. 15 | func Ordered[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string](got T) FluentOrdered[T] { 16 | return FluentOrdered[T]{FluentObj[T]{FluentAny[T]{got}}} 17 | } 18 | 19 | // Lesser tests the objects using < operator. 20 | func (x FluentOrdered[T]) Lesser(than T) FailureMessage { 21 | if x.Got < than { 22 | return "" 23 | } 24 | return FailureMessage(fmt.Sprintf("the object is not lesser\ngot: %v\nthan: %v", x.Got, than)) 25 | } 26 | 27 | // LesserOrEqual tests the objects using <= operator. 28 | func (x FluentOrdered[T]) LesserOrEqual(than T) FailureMessage { 29 | if x.Got <= than { 30 | return "" 31 | } 32 | return FailureMessage(fmt.Sprintf("the object is not lesser or equal\ngot: %v\nthan: %v", x.Got, than)) 33 | } 34 | 35 | // GreaterOrEqual tests the objects using >= operator. 36 | func (x FluentOrdered[T]) GreaterOrEqual(than T) FailureMessage { 37 | if x.Got >= than { 38 | return "" 39 | } 40 | return FailureMessage(fmt.Sprintf("the object is not greater or equal\ngot: %v\nthan: %v", x.Got, than)) 41 | } 42 | 43 | // Greater tests the objects using > operator. 44 | func (x FluentOrdered[T]) Greater(than T) FailureMessage { 45 | if x.Got > than { 46 | return "" 47 | } 48 | return FailureMessage(fmt.Sprintf("the object is not greater\ngot: %v\nthan: %v", x.Got, than)) 49 | } 50 | -------------------------------------------------------------------------------- /ordered_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestOrdered(t *testing.T) { 10 | t.Run("Lesser", func(t *testing.T) { 11 | t.Run("Lesser", func(t *testing.T) { 12 | msg := verify.Ordered(0).Lesser(1) 13 | assertPassed(t, msg) 14 | }) 15 | t.Run("Equal", func(t *testing.T) { 16 | msg := verify.Ordered(0).Lesser(0) 17 | assertFailed(t, msg, "the object is not lesser") 18 | }) 19 | t.Run("Greater", func(t *testing.T) { 20 | msg := verify.Ordered(0).Lesser(-1) 21 | assertFailed(t, msg, "the object is not lesser") 22 | }) 23 | }) 24 | 25 | t.Run("LesserOrEqual", func(t *testing.T) { 26 | t.Run("Lesser", func(t *testing.T) { 27 | msg := verify.Ordered(0).LesserOrEqual(1) 28 | assertPassed(t, msg) 29 | }) 30 | t.Run("Equal", func(t *testing.T) { 31 | msg := verify.Ordered(0).LesserOrEqual(0) 32 | assertPassed(t, msg) 33 | }) 34 | t.Run("Greater", func(t *testing.T) { 35 | msg := verify.Ordered(0).LesserOrEqual(-1) 36 | assertFailed(t, msg, "the object is not lesser or equal") 37 | }) 38 | }) 39 | 40 | t.Run("GreaterOrEqual", func(t *testing.T) { 41 | t.Run("Lesser", func(t *testing.T) { 42 | msg := verify.Ordered(0).GreaterOrEqual(1) 43 | assertFailed(t, msg, "the object is not greater or equal") 44 | }) 45 | t.Run("Equal", func(t *testing.T) { 46 | msg := verify.Ordered(0).GreaterOrEqual(0) 47 | assertPassed(t, msg) 48 | }) 49 | t.Run("Greater", func(t *testing.T) { 50 | msg := verify.Ordered(0).GreaterOrEqual(-1) 51 | assertPassed(t, msg) 52 | }) 53 | }) 54 | 55 | t.Run("Greater", func(t *testing.T) { 56 | t.Run("Lesser", func(t *testing.T) { 57 | msg := verify.Ordered(0).Greater(1) 58 | assertFailed(t, msg, "the object is not greater") 59 | }) 60 | t.Run("Equal", func(t *testing.T) { 61 | msg := verify.Ordered(0).Greater(0) 62 | assertFailed(t, msg, "the object is not greater") 63 | }) 64 | t.Run("Greater", func(t *testing.T) { 65 | msg := verify.Ordered(0).Greater(-1) 66 | assertPassed(t, msg) 67 | }) 68 | }) 69 | 70 | t.Run("has assertions from Obj and Any", func(t *testing.T) { 71 | want := 123 72 | got := verify.Ordered(want).FluentObj.FluentAny.Got // type embedding done properly 73 | assertEqual(t, got, want) 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /panic.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import "fmt" 4 | 5 | // Panics tests if the function panics when executed. 6 | func Panics(fn func()) (msg FailureMessage) { 7 | defer func() { 8 | if r := recover(); r == nil { 9 | msg = "the function returned instead of panicking" 10 | } 11 | }() 12 | fn() 13 | return 14 | } 15 | 16 | // NotPanics tests if the function does not panic when executed. 17 | func NotPanics(fn func()) (msg FailureMessage) { 18 | defer func() { 19 | if r := recover(); r != nil { 20 | msg = FailureMessage(fmt.Sprintf("the function panicked\ngot: %v", r)) 21 | } 22 | }() 23 | fn() 24 | return 25 | } 26 | -------------------------------------------------------------------------------- /panic_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestPanics(t *testing.T) { 10 | t.Run("Passed", func(t *testing.T) { 11 | msg := verify.Panics(func() { panic("exception") }) 12 | assertPassed(t, msg) 13 | }) 14 | t.Run("Failed", func(t *testing.T) { 15 | msg := verify.Panics(func() {}) 16 | assertFailed(t, msg, "the function returned instead of panicking") 17 | }) 18 | } 19 | 20 | func TestNotPanics(t *testing.T) { 21 | t.Run("Passed", func(t *testing.T) { 22 | msg := verify.NotPanics(func() {}) 23 | assertPassed(t, msg) 24 | }) 25 | t.Run("Failed", func(t *testing.T) { 26 | msg := verify.NotPanics(func() { panic("exception") }) 27 | assertFailed(t, msg, "the function panicked") 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /slice.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | ) 8 | 9 | // FluentSlice encapsulates assertions for a slice. 10 | type FluentSlice[T any] struct { 11 | FluentAny[[]T] 12 | } 13 | 14 | // Slice is used for testing a slice. 15 | func Slice[T any](got []T) FluentSlice[T] { 16 | return FluentSlice[T]{FluentAny[[]T]{got}} 17 | } 18 | 19 | // Empty tests if the slice is empty. 20 | func (x FluentSlice[T]) Empty() FailureMessage { 21 | if len(x.Got) == 0 { 22 | return "" 23 | } 24 | return FailureMessage(fmt.Sprintf("not an empty slice\ngot: %+v", x.Got)) 25 | } 26 | 27 | // NotEmpty tests if the slice is not empty. 28 | func (x FluentSlice[T]) NotEmpty() FailureMessage { 29 | if len(x.Got) > 0 { 30 | return "" 31 | } 32 | return FailureMessage(fmt.Sprintf("an empty slice\ngot: %+v", x.Got)) 33 | } 34 | 35 | // Equivalent tests if the slice has the same items as want in any order. 36 | func (x FluentSlice[T]) Equivalent(want []T, opts ...cmp.Option) FailureMessage { 37 | extraGot, extraWant := x.diff(want, opts) 38 | if len(extraGot) == 0 && len(extraWant) == 0 { 39 | return "" 40 | } 41 | return FailureMessage(fmt.Sprintf("not equivalent\ngot: %+v\nwant: %+v\nextra got: %+v\nextra want: %+v", x.Got, want, extraGot, extraWant)) 42 | } 43 | 44 | // NotEquivalent tests if the slice does not have the same items as want in any order. 45 | func (x FluentSlice[T]) NotEquivalent(want []T, opts ...cmp.Option) FailureMessage { 46 | extraGot, extraWant := x.diff(want, opts) 47 | if len(extraGot) != 0 || len(extraWant) != 0 { 48 | return "" 49 | } 50 | return FailureMessage(fmt.Sprintf("equivalent\ngot: %+v", extraGot)) 51 | } 52 | 53 | func (x FluentSlice[T]) diff(want []T, opts []cmp.Option) (extraGot, extraWant []T) { 54 | aLen := len(x.Got) 55 | bLen := len(want) 56 | 57 | // Mark indexes in list that we already used 58 | visited := make([]bool, bLen) 59 | for i := 0; i < aLen; i++ { 60 | found := false 61 | for j := 0; j < bLen; j++ { 62 | if visited[j] { 63 | continue 64 | } 65 | if cmp.Equal(want[j], x.Got[i], opts...) { 66 | visited[j] = true 67 | found = true 68 | break 69 | } 70 | } 71 | if !found { 72 | extraGot = append(extraGot, x.Got[i]) 73 | } 74 | } 75 | 76 | for j := 0; j < bLen; j++ { 77 | if visited[j] { 78 | continue 79 | } 80 | extraWant = append(extraWant, want[j]) 81 | } 82 | 83 | return 84 | } 85 | 86 | // Contain tests if the slice contains the item. 87 | func (x FluentSlice[T]) Contain(item T, opts ...cmp.Option) FailureMessage { 88 | for _, v := range x.Got { 89 | if cmp.Equal(item, v, opts...) { 90 | return "" 91 | } 92 | } 93 | return FailureMessage(fmt.Sprintf("slice does not contain the item\ngot: %+v\nitem: %+v", x.Got, item)) 94 | } 95 | 96 | // NotContain tests if the slice does not contain the item. 97 | func (x FluentSlice[T]) NotContain(item T, opts ...cmp.Option) FailureMessage { 98 | for _, v := range x.Got { 99 | if cmp.Equal(item, v, opts...) { 100 | return FailureMessage(fmt.Sprintf("slice contains the item\ngot: %+v\nitem: %+v", x.Got, item)) 101 | } 102 | } 103 | return "" 104 | } 105 | 106 | // Any tests if any of the slice's items meets the predicate criteria. 107 | func (x FluentSlice[T]) Any(predicate func(T) bool) FailureMessage { 108 | for _, v := range x.Got { 109 | if predicate(v) { 110 | return "" 111 | } 112 | } 113 | return FailureMessage(fmt.Sprintf("none item does meet the predicate criteria\ngot: %+v", x.Got)) 114 | } 115 | 116 | // All tests if all of the slice's items meet the predicate criteria. 117 | func (x FluentSlice[T]) All(predicate func(T) bool) FailureMessage { 118 | for _, v := range x.Got { 119 | if !predicate(v) { 120 | return FailureMessage(fmt.Sprintf("an item does not meet the predicate criteria\ngot: %+v\nitem: %+v", x.Got, v)) 121 | } 122 | } 123 | return "" 124 | } 125 | 126 | // None tests if none of the slice's items meets the predicate criteria. 127 | func (x FluentSlice[T]) None(predicate func(T) bool) FailureMessage { 128 | for _, v := range x.Got { 129 | if predicate(v) { 130 | return FailureMessage(fmt.Sprintf("an item meets the predicate criteria\ngot: %+v\nitem: %+v", x.Got, v)) 131 | } 132 | } 133 | return "" 134 | } 135 | 136 | // Len tests the length of the slice. 137 | func (x FluentSlice[T]) Len(want int) FailureMessage { 138 | gotLen := len(x.Got) 139 | if gotLen != want { 140 | return FailureMessage(fmt.Sprintf("has different length\ngot: %+v\nlen: %v\nwant: %v", x.Got, gotLen, want)) 141 | } 142 | return "" 143 | } 144 | -------------------------------------------------------------------------------- /slice_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/fluentassert/verify" 7 | ) 8 | 9 | func TestSlice(t *testing.T) { 10 | type A struct { 11 | Str string 12 | Bool bool 13 | Slice []int 14 | } 15 | 16 | t.Run("has assertions from Any", func(t *testing.T) { 17 | want := []A{ 18 | {Str: "string", Bool: true, Slice: []int{1, 2, 3}}, 19 | } 20 | got := verify.Slice(want).FluentAny.Got // type embedding done properly 21 | assertEqual(t, got, want) 22 | }) 23 | 24 | t.Run("Empty", func(t *testing.T) { 25 | t.Run("Passed", func(t *testing.T) { 26 | got := verify.Slice([]A{}).Empty() 27 | assertPassed(t, got) 28 | }) 29 | t.Run("Failed", func(t *testing.T) { 30 | got := verify.Slice([]A{{}}).Empty() 31 | assertFailed(t, got, "not an empty slice") 32 | }) 33 | }) 34 | t.Run("NotEmpty", func(t *testing.T) { 35 | t.Run("Passed", func(t *testing.T) { 36 | got := verify.Slice([]A{{}}).NotEmpty() 37 | assertPassed(t, got) 38 | }) 39 | t.Run("Failed", func(t *testing.T) { 40 | got := verify.Slice([]A{}).NotEmpty() 41 | assertFailed(t, got, "an empty slice") 42 | }) 43 | }) 44 | 45 | list := []A{ 46 | {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 47 | {Slice: []int{9, 8, 7}}, 48 | } 49 | eq := []A{ 50 | {Slice: []int{9, 8, 7}}, 51 | {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 52 | } 53 | notEq := []A{ 54 | {Slice: []int{0, 0, 0}}, 55 | {Str: "text", Bool: true, Slice: []int{1, 2, 3}}, 56 | } 57 | t.Run("Equivalent", func(t *testing.T) { 58 | t.Run("Passed", func(t *testing.T) { 59 | got := verify.Slice(list).Equivalent(eq) 60 | assertPassed(t, got) 61 | }) 62 | t.Run("Failed", func(t *testing.T) { 63 | got := verify.Slice(list).Equivalent(notEq) 64 | assertFailed(t, got, "not equivalent") 65 | }) 66 | }) 67 | t.Run("NotEquivalent", func(t *testing.T) { 68 | t.Run("Passed", func(t *testing.T) { 69 | got := verify.Slice(list).NotEquivalent(notEq) 70 | assertPassed(t, got) 71 | }) 72 | t.Run("Failed", func(t *testing.T) { 73 | got := verify.Slice(list).NotEquivalent(eq) 74 | assertFailed(t, got, "equivalent") 75 | }) 76 | }) 77 | 78 | t.Run("Contain", func(t *testing.T) { 79 | t.Run("Passed", func(t *testing.T) { 80 | got := verify.Slice(list).Contain(A{Str: "text", Bool: true, Slice: []int{1, 2, 3}}) 81 | assertPassed(t, got) 82 | }) 83 | t.Run("Failed", func(t *testing.T) { 84 | got := verify.Slice(list).Contain(A{}) 85 | assertFailed(t, got, "slice does not contain the item") 86 | }) 87 | }) 88 | t.Run("NotContain", func(t *testing.T) { 89 | t.Run("Passed", func(t *testing.T) { 90 | got := verify.Slice(list).NotContain(A{}) 91 | assertPassed(t, got) 92 | }) 93 | t.Run("Failed", func(t *testing.T) { 94 | got := verify.Slice(list).NotContain(A{Str: "text", Bool: true, Slice: []int{1, 2, 3}}) 95 | assertFailed(t, got, "slice contains the item") 96 | }) 97 | }) 98 | 99 | t.Run("Any", func(t *testing.T) { 100 | t.Run("Passed", func(t *testing.T) { 101 | got := verify.Slice(list).Any(func(A) bool { return true }) 102 | assertPassed(t, got) 103 | }) 104 | t.Run("Failed", func(t *testing.T) { 105 | got := verify.Slice(list).Any(func(A) bool { return false }) 106 | assertFailed(t, got, "none item does meet the predicate criteria") 107 | }) 108 | }) 109 | t.Run("All", func(t *testing.T) { 110 | t.Run("Passed", func(t *testing.T) { 111 | got := verify.Slice(list).All(func(A) bool { return true }) 112 | assertPassed(t, got) 113 | }) 114 | t.Run("Failed", func(t *testing.T) { 115 | got := verify.Slice(list).All(func(A) bool { return false }) 116 | assertFailed(t, got, "an item does not meet the predicate criteria") 117 | }) 118 | }) 119 | t.Run("None", func(t *testing.T) { 120 | t.Run("Passed", func(t *testing.T) { 121 | got := verify.Slice(list).None(func(A) bool { return false }) 122 | assertPassed(t, got) 123 | }) 124 | t.Run("Failed", func(t *testing.T) { 125 | got := verify.Slice(list).None(func(A) bool { return true }) 126 | assertFailed(t, got, "an item meets the predicate criteria") 127 | }) 128 | }) 129 | 130 | t.Run("Len", func(t *testing.T) { 131 | t.Run("Passed", func(t *testing.T) { 132 | got := verify.Slice(list).Len(len(list)) 133 | assertPassed(t, got) 134 | }) 135 | t.Run("Failed", func(t *testing.T) { 136 | got := verify.Slice(list).Len(10) 137 | assertFailed(t, got, "has different length") 138 | }) 139 | }) 140 | } 141 | -------------------------------------------------------------------------------- /string.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | // FluentString encapsulates assertions for string object. 10 | type FluentString[T ~string] struct { 11 | FluentOrdered[T] 12 | } 13 | 14 | // String is used for testing a string object. 15 | func String[T ~string](got T) FluentString[T] { 16 | return FluentString[T]{FluentOrdered[T]{FluentObj[T]{FluentAny[T]{got}}}} 17 | } 18 | 19 | // Empty tests if the string is not empty. 20 | func (x FluentString[T]) Empty() FailureMessage { 21 | if x.Got == "" { 22 | return "" 23 | } 24 | return FailureMessage(fmt.Sprintf("the value was not an empty string\ngot: %q", x.Got)) 25 | } 26 | 27 | // NotEmpty tests if the string is not empty. 28 | func (x FluentString[T]) NotEmpty() FailureMessage { 29 | if x.Got != "" { 30 | return "" 31 | } 32 | return "the value was \"\"" 33 | } 34 | 35 | // Contain tests if the string contains the substring. 36 | func (x FluentString[T]) Contain(substr string) FailureMessage { 37 | if strings.Contains(string(x.Got), substr) { 38 | return "" 39 | } 40 | return FailureMessage(fmt.Sprintf("the value does not contain the substring\ngot: %q\nsubstr: %q", x.Got, substr)) 41 | } 42 | 43 | // NotContain tests if the string does not contain the substring. 44 | func (x FluentString[T]) NotContain(substr string) FailureMessage { 45 | if !strings.Contains(string(x.Got), substr) { 46 | return "" 47 | } 48 | 49 | return FailureMessage(fmt.Sprintf("the value contains the substring\ngot: %q\nsubstr: %q", x.Got, substr)) 50 | } 51 | 52 | // Prefix tests if the string starts with the prefix. 53 | func (x FluentString[T]) Prefix(prefix string) FailureMessage { 54 | if strings.HasPrefix(string(x.Got), prefix) { 55 | return "" 56 | } 57 | return FailureMessage(fmt.Sprintf("the value does not have the prefix\ngot: %q\nprefix: %q", x.Got, prefix)) 58 | } 59 | 60 | // NoPrefix tests if the string does not start with the prefix. 61 | func (x FluentString[T]) NoPrefix(prefix string) FailureMessage { 62 | if !strings.HasPrefix(string(x.Got), prefix) { 63 | return "" 64 | } 65 | return FailureMessage(fmt.Sprintf("the value has the prefix\ngot: %q\nprefix: %q", x.Got, prefix)) 66 | } 67 | 68 | // Sufix tests if the string ends with the sufix. 69 | func (x FluentString[T]) Sufix(sufix string) FailureMessage { 70 | if strings.HasSuffix(string(x.Got), sufix) { 71 | return "" 72 | } 73 | return FailureMessage(fmt.Sprintf("the value does not have the sufix\ngot: %q\nsufix: %q", x.Got, sufix)) 74 | } 75 | 76 | // NoSufix tests if the string does not end with the sufix. 77 | func (x FluentString[T]) NoSufix(sufix string) FailureMessage { 78 | if !strings.HasSuffix(string(x.Got), sufix) { 79 | return "" 80 | } 81 | return FailureMessage(fmt.Sprintf("the value has the sufix\ngot: %q\nsufix: %q", x.Got, sufix)) 82 | } 83 | 84 | // EqualFold tests if the values interpreted as UTF-8 strings, 85 | // are equal under simple Unicode case-folding, 86 | // which is a more general form of case-insensitivity. 87 | func (x FluentString[T]) EqualFold(want string) FailureMessage { 88 | if strings.EqualFold(string(x.Got), want) { 89 | return "" 90 | } 91 | return FailureMessage(fmt.Sprintf("the string values are not equal under Unicode case folding\ngot: %q\nwant: %q", x.Got, want)) 92 | } 93 | 94 | // NotEqualFold tests if the values interpreted as UTF-8 strings, 95 | // are not equal under simple Unicode case-folding, 96 | // which is a more general form of case-insensitivity. 97 | func (x FluentString[T]) NotEqualFold(want string) FailureMessage { 98 | if !strings.EqualFold(string(x.Got), want) { 99 | return "" 100 | } 101 | return FailureMessage(fmt.Sprintf("the string values are equal under Unicode case folding\ngot: %q\nwant: %q", x.Got, want)) 102 | } 103 | 104 | // MatchRegex tests if the string matches the regular expression. 105 | func (x FluentString[T]) MatchRegex(regex *regexp.Regexp) FailureMessage { 106 | if regex.MatchString(string(x.Got)) { 107 | return "" 108 | } 109 | return FailureMessage(fmt.Sprintf("the string value does not match the regular expression\ngot: %q\nregex: %s", x.Got, regex.String())) 110 | } 111 | 112 | // NotMatchRegex tests if the string does not match the regular expression. 113 | func (x FluentString[T]) NotMatchRegex(regex *regexp.Regexp) FailureMessage { 114 | if !regex.MatchString(string(x.Got)) { 115 | return "" 116 | } 117 | return FailureMessage(fmt.Sprintf("the string value matches the regular expression\ngot: %q\nregex: %s", x.Got, regex.String())) 118 | } 119 | 120 | // Len tests the length of the string. 121 | func (x FluentString[T]) Len(want int) FailureMessage { 122 | gotLen := len(x.Got) 123 | if gotLen != want { 124 | return FailureMessage(fmt.Sprintf("has different length\ngot: %+v\nlen: %v\nwant: %v", x.Got, gotLen, want)) 125 | } 126 | return "" 127 | } 128 | -------------------------------------------------------------------------------- /string_test.go: -------------------------------------------------------------------------------- 1 | package verify_test 2 | 3 | import ( 4 | "regexp" 5 | "testing" 6 | 7 | "github.com/fluentassert/verify" 8 | ) 9 | 10 | func TestString(t *testing.T) { 11 | t.Run("Empty", func(t *testing.T) { 12 | t.Run("Passed", func(t *testing.T) { 13 | msg := verify.String("").Empty() 14 | assertPassed(t, msg) 15 | }) 16 | t.Run("Failed", func(t *testing.T) { 17 | msg := verify.String("val").Empty() 18 | assertFailed(t, msg, "the value was not an empty string") 19 | }) 20 | }) 21 | 22 | t.Run("NotEmpty", func(t *testing.T) { 23 | t.Run("Passed", func(t *testing.T) { 24 | msg := verify.String("val").NotEmpty() 25 | assertPassed(t, msg) 26 | }) 27 | t.Run("Failed", func(t *testing.T) { 28 | msg := verify.String("").NotEmpty() 29 | assertFailed(t, msg, "the value was \"\"") 30 | }) 31 | }) 32 | 33 | t.Run("Contains", func(t *testing.T) { 34 | t.Run("Passed", func(t *testing.T) { 35 | msg := verify.String("text").Contain("ex") 36 | assertPassed(t, msg) 37 | }) 38 | t.Run("Failed", func(t *testing.T) { 39 | msg := verify.String("text").Contain("asd") 40 | assertFailed(t, msg, "the value does not contain the substring") 41 | }) 42 | }) 43 | 44 | t.Run("NotContains", func(t *testing.T) { 45 | t.Run("Passed", func(t *testing.T) { 46 | msg := verify.String("text").NotContain("asd") 47 | assertPassed(t, msg) 48 | }) 49 | t.Run("Failed", func(t *testing.T) { 50 | msg := verify.String("text").NotContain("ex") 51 | assertFailed(t, msg, "the value contains the substring") 52 | }) 53 | }) 54 | 55 | t.Run("Prefix", func(t *testing.T) { 56 | t.Run("Passed", func(t *testing.T) { 57 | msg := verify.String("[ok]a").Prefix("[ok]") 58 | assertPassed(t, msg) 59 | }) 60 | t.Run("Failed", func(t *testing.T) { 61 | msg := verify.String("a[ok]").Prefix("[ok]") 62 | assertFailed(t, msg, "the value does not have the prefix") 63 | }) 64 | }) 65 | 66 | t.Run("NoPrefix", func(t *testing.T) { 67 | t.Run("Passed", func(t *testing.T) { 68 | msg := verify.String("a[ok]").NoPrefix("[ok]") 69 | assertPassed(t, msg) 70 | }) 71 | t.Run("Failed", func(t *testing.T) { 72 | msg := verify.String("[ok]a").NoPrefix("[ok]") 73 | assertFailed(t, msg, "the value has the prefix") 74 | }) 75 | }) 76 | 77 | t.Run("Sufix", func(t *testing.T) { 78 | t.Run("Passed", func(t *testing.T) { 79 | msg := verify.String("a[ok]").Sufix("[ok]") 80 | assertPassed(t, msg) 81 | }) 82 | t.Run("Failed", func(t *testing.T) { 83 | msg := verify.String("[ok]a").Sufix("[ok]") 84 | assertFailed(t, msg, "the value does not have the sufix") 85 | }) 86 | }) 87 | 88 | t.Run("NoSufix", func(t *testing.T) { 89 | t.Run("Passed", func(t *testing.T) { 90 | msg := verify.String("[ok]a").NoSufix("[ok]") 91 | assertPassed(t, msg) 92 | }) 93 | t.Run("Failed", func(t *testing.T) { 94 | msg := verify.String("a[ok]").NoSufix("[ok]") 95 | assertFailed(t, msg, "the value has the sufix") 96 | }) 97 | }) 98 | 99 | t.Run("EqualFold", func(t *testing.T) { 100 | t.Run("Passed", func(t *testing.T) { 101 | msg := verify.String("aBc").EqualFold("ABC") 102 | assertPassed(t, msg) 103 | }) 104 | t.Run("Failed", func(t *testing.T) { 105 | msg := verify.String("aBc").EqualFold("aB") 106 | assertFailed(t, msg, "the string values are not equal under Unicode case folding") 107 | }) 108 | }) 109 | 110 | t.Run("NotEqualFold", func(t *testing.T) { 111 | t.Run("Passed", func(t *testing.T) { 112 | msg := verify.String("aBc").NotEqualFold("aB") 113 | assertPassed(t, msg) 114 | }) 115 | t.Run("Failed", func(t *testing.T) { 116 | msg := verify.String("aBc").NotEqualFold("ABC") 117 | assertFailed(t, msg, "the string values are equal under Unicode case folding") 118 | }) 119 | }) 120 | 121 | t.Run("MatchRegex", func(t *testing.T) { 122 | t.Run("Passed", func(t *testing.T) { 123 | msg := verify.String("3aD").MatchRegex(regexp.MustCompile("[0-9][a-z][A-Z]")) 124 | assertPassed(t, msg) 125 | }) 126 | t.Run("Failed", func(t *testing.T) { 127 | msg := verify.String("123").MatchRegex(regexp.MustCompile("[0-9][a-z][A-Z]")) 128 | assertFailed(t, msg, "the string value does not match the regular expression") 129 | }) 130 | }) 131 | 132 | t.Run("NotMatchRegex", func(t *testing.T) { 133 | t.Run("Passed", func(t *testing.T) { 134 | msg := verify.String("123").NotMatchRegex(regexp.MustCompile("[0-9][a-z][A-Z]")) 135 | assertPassed(t, msg) 136 | }) 137 | t.Run("Failed", func(t *testing.T) { 138 | msg := verify.String("3aD").NotMatchRegex(regexp.MustCompile("[0-9][a-z][A-Z]")) 139 | assertFailed(t, msg, "the string value matches the regular expression") 140 | }) 141 | }) 142 | 143 | t.Run("Len", func(t *testing.T) { 144 | t.Run("Passed", func(t *testing.T) { 145 | got := verify.String("abc").Len(3) 146 | assertPassed(t, got) 147 | }) 148 | t.Run("Failed", func(t *testing.T) { 149 | got := verify.String("abc").Len(10) 150 | assertFailed(t, got, "has different length") 151 | }) 152 | }) 153 | 154 | t.Run("has assertions from Ordered, Obj, Any", func(t *testing.T) { 155 | want := "text" 156 | got := verify.String(want).FluentOrdered.FluentObj.FluentAny.Got // type embedding done properly 157 | assertEqual(t, got, want) 158 | }) 159 | } 160 | --------------------------------------------------------------------------------