diff --git a/go.mod b/go.mod index 278d1cb25..1c75036aa 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/johannesboyne/gofakes3 v1.2.0 github.com/jwx-go/jwkfetch/v4 v4.0.4 github.com/lestrrat-go/httprc/v3 v3.0.6 - github.com/lestrrat-go/jwx/v4 v4.2.0 + github.com/lestrrat-go/jwx/v4 v4.4.0 github.com/magiconair/properties v1.18.11 github.com/moby/moby/api v1.55.0 github.com/peterbourgon/ff/v3 v3.4.0 @@ -48,7 +48,7 @@ require ( github.com/rodaine/table v1.3.1 github.com/sourcegraph/jsonrpc2 v0.2.2 github.com/spf13/cobra v1.10.2 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.12.0 github.com/testcontainers/testcontainers-go v0.44.0 github.com/vektra/mockery/v2 v2.53.6 github.com/vishvananda/netlink v1.3.1 @@ -136,7 +136,7 @@ require ( github.com/klauspost/compress v1.19.1 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect - github.com/lestrrat-go/dsig v1.3.0 // indirect + github.com/lestrrat-go/dsig v1.4.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/lestrrat-go/option/v3 v3.0.0-alpha1 // indirect diff --git a/go.sum b/go.sum index d11c0b445..c8a3f797a 100644 --- a/go.sum +++ b/go.sum @@ -340,12 +340,16 @@ github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9T github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/dsig v1.3.0 h1:phjMOCXvYzhuIgn7Voe2rex8z166vGfxRxmqM25P9/Q= github.com/lestrrat-go/dsig v1.3.0/go.mod h1:RD2eOaidyPvpc7IJQoO3Qq52RWdy8ZcJs8lrOnoa1Kc= +github.com/lestrrat-go/dsig v1.4.0 h1:g7LUjK8cT74A5DzBXJI5HzsJuLhoYN0Wzj4nuOMIrH8= +github.com/lestrrat-go/dsig v1.4.0/go.mod h1:I8Nddg/vN2cUl/h8N7SRRApLnNNeyZPIqLYpvpOtGGo= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.6 h1:4FpLQ18KK/ypPbVU3NLWJNRvH3kcYiqKqWfKGqNWxxI= github.com/lestrrat-go/httprc/v3 v3.0.6/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= github.com/lestrrat-go/jwx/v4 v4.2.0 h1:YpyEnRqejbDGwOSB8rIKD2EXqfAEA/2LLN2ZZkzm9xs= github.com/lestrrat-go/jwx/v4 v4.2.0/go.mod h1:1V1wOmyFnMLltrTKXZSRMZ/GWq8UeMW1JmUaBNqD3E4= +github.com/lestrrat-go/jwx/v4 v4.4.0 h1:CzoK8+u++WF7vVEmxx9fB8VaheeXWZ698F6HZbrl6SI= +github.com/lestrrat-go/jwx/v4 v4.4.0/go.mod h1:65utsGK/iSrjgGfu6iqj/TAvSfia6SSXkRpjHcKcTyg= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lestrrat-go/option/v3 v3.0.0-alpha1 h1:dvdzLwm/Ba5CJUF3jQP7w/iNYSLfy7yyh9XXNa1WjxI= @@ -509,6 +513,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0eLs7ztyaGRu75bFo5A= diff --git a/vendor/github.com/lestrrat-go/dsig/.golangci.yml b/vendor/github.com/lestrrat-go/dsig/.golangci.yml new file mode 100644 index 000000000..8cde331d8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/.golangci.yml @@ -0,0 +1,14 @@ +version: "2" + +# The linter set is golangci-lint's default. The point of this file is the +# formatters block below: without it nothing checked gofmt, and the drift that +# allowed put a closing code fence on the same line as a line of Go, which +# broke half of README.md once the doc generator started running. +formatters: + enable: + - gofmt + +issues: + # Report every unformatted file. The default caps repeats of one message at + # three, which would hide the tail of exactly this kind of sweep. + max-same-issues: 0 diff --git a/vendor/github.com/lestrrat-go/dsig/Changes b/vendor/github.com/lestrrat-go/dsig/Changes index 9e913f60b..7264f1801 100644 --- a/vendor/github.com/lestrrat-go/dsig/Changes +++ b/vendor/github.com/lestrrat-go/dsig/Changes @@ -1,6 +1,24 @@ Changes ======= +v1.4.0 20 Aug 2026 + * Add ML-DSA (FIPS 204) support: the `MLDSA44`, `MLDSA65`, and `MLDSA87` + algorithms, the `SignMLDSA()` / `VerifyMLDSA()` primitives, and a new + `MLDSAFamily` algorithm family. ML-DSA requires Go 1.27 or later, which is + when `crypto/mldsa` joins the standard library; on earlier toolchains the + constants are not declared and the algorithms are not registered. + + An ML-DSA key carries its own parameter set, so naming an algorithm that + disagrees with the key is an error on both the sign and verify paths. + `SignMLDSA()` takes a `crypto.SignerOpts` so that both signing modes stay + reachable: an `*mldsa.Options` supplies a context string, and + `crypto.MLDSAMu` signs a pre-hashed mu message representative. + `VerifyMLDSA()` takes an `*mldsa.Options` because verification has a single + mode. `SignDigest()` and `VerifyDigest()` return an error for ML-DSA, as + they already do for EdDSA. + + * The minimum Go version is now 1.25. + v1.3.0 13 Apr 2026 * Add `SignWithOpts()` and `VerifyWithOpts()`, which thread an optional `crypto.SignerOpts` through to the underlying signer. For built-in @@ -58,4 +76,4 @@ v1.1.0 2 Apr 2026 algorithm name. Use `UnregisterAlgorithm()` first if you need to replace it. v1.0.0 - 18 Aug 2025 - * Initial release \ No newline at end of file + * Initial release diff --git a/vendor/github.com/lestrrat-go/dsig/README.md b/vendor/github.com/lestrrat-go/dsig/README.md index b52b998f8..55b75963e 100644 --- a/vendor/github.com/lestrrat-go/dsig/README.md +++ b/vendor/github.com/lestrrat-go/dsig/README.md @@ -1,4 +1,4 @@ -# github.com/lestrrat-go/dsig [![CI](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml/badge.svg)](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/dsig.svg)](https://pkg.go.dev/github.com/lestrrat-go/dsig) [![codecov.io](https://codecov.io/github/lestrrat-go/dsig/coverage.svg?branch=v1)](https://codecov.io/github/lestrrat-go/dsig?branch=v1) +# github.com/lestrrat-go/dsig [![CI](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml/badge.svg)](https://github.com/lestrrat-go/dsig/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/dsig.svg)](https://pkg.go.dev/github.com/lestrrat-go/dsig) Go module providing low-level digital signature operations. @@ -9,6 +9,7 @@ While there are many standards for generating and verifying digital signatures, * RSA signatures (PKCS1v15 and PSS) * ECDSA signatures (P-256, P-384, P-521) * EdDSA signatures (Ed25519, Ed448) +* ML-DSA post-quantum signatures (ML-DSA-44, ML-DSA-65, ML-DSA-87), on Go 1.27 and later * HMAC signatures (SHA-256, SHA-384, SHA-512) * Support for crypto.Signer interface * Custom algorithm registration via `Signer`/`Verifier` interfaces @@ -143,6 +144,53 @@ source: [examples/dsig_readme_example_test.go](https://github.com/lestrrat-go/ds | `ECDSAWithP384AndSHA384` | ECDSA using P-384 and SHA-384 | *ecdsa.PrivateKey / *ecdsa.PublicKey | | `ECDSAWithP521AndSHA512` | ECDSA using P-521 and SHA-512 | *ecdsa.PrivateKey / *ecdsa.PublicKey | | `EdDSA` | EdDSA using Ed25519 or Ed448 | ed25519.PrivateKey / ed25519.PublicKey | +| `MLDSA44` | ML-DSA-44 (FIPS 204), NIST level 2 | *mldsa.PrivateKey / *mldsa.PublicKey | +| `MLDSA65` | ML-DSA-65 (FIPS 204), NIST level 3 | *mldsa.PrivateKey / *mldsa.PublicKey | +| `MLDSA87` | ML-DSA-87 (FIPS 204), NIST level 5 | *mldsa.PrivateKey / *mldsa.PublicKey | + +The three ML-DSA algorithms need Go 1.27 or later, which is when `crypto/mldsa` +joins the standard library. On earlier toolchains the constants are not declared +and the algorithms are not registered. + +Name the constant that matches the key you generated. A key knows its own +parameter set, and naming a different one is an error, so a key cannot be used +under a weaker set by accident: + +```go +sk, _ := mldsa.GenerateKey(mldsa.MLDSA65()) + +sig, _ := dsig.Sign(sk, dsig.MLDSA65, payload, nil) +err := dsig.Verify(sk.PublicKey(), dsig.MLDSA65, payload, sig) + +_, err = dsig.Sign(sk, dsig.MLDSA44, payload, nil) +// dsig.SignWithOpts: ML-DSA parameter set mismatch: key is ML-DSA-65, algorithm is ML-DSA-44 +``` + +## ML-DSA context strings + +ML-DSA can mix a caller-chosen string into the signature. Give each job a +different context and one key can sign for several of them without a signature +made for one job verifying as another, so a login token cannot be presented as +a file receipt. + +Signing and verifying must use the same context. A verifier that supplies the +wrong one, or none at all, sees an ordinary invalid signature and cannot tell +which mistake was made: + +```go +login := &mldsa.Options{Context: "my-app/login-token"} +receipt := &mldsa.Options{Context: "my-app/file-receipt"} + +sig, _ := dsig.SignWithOpts(sk, dsig.MLDSA65, payload, login, nil) + +err := dsig.VerifyWithOpts(sk.PublicKey(), dsig.MLDSA65, payload, sig, login) +// nil + +err = dsig.VerifyWithOpts(sk.PublicKey(), dsig.MLDSA65, payload, sig, receipt) +// mldsa: invalid signature +``` + +A context is at most 255 bytes, and it is empty when opts is nil. # Description @@ -160,4 +208,4 @@ Please include tests that exercise your changes. # Related Libraries -* [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) - JOSE (JWA/JWE/JWK/JWS/JWT) implementation \ No newline at end of file +* [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) - JOSE (JWA/JWE/JWK/JWS/JWT) implementation diff --git a/vendor/github.com/lestrrat-go/dsig/algorithms.go b/vendor/github.com/lestrrat-go/dsig/algorithms.go index 0895c6476..3cf93b0c7 100644 --- a/vendor/github.com/lestrrat-go/dsig/algorithms.go +++ b/vendor/github.com/lestrrat-go/dsig/algorithms.go @@ -34,4 +34,4 @@ const ( // EdDSA signature algorithms // These use Edwards-curve Digital Signature Algorithm (supports Ed25519 and Ed448) EdDSA = "EDDSA" -) \ No newline at end of file +) diff --git a/vendor/github.com/lestrrat-go/dsig/dsig.go b/vendor/github.com/lestrrat-go/dsig/dsig.go index 466797b0a..ee278311b 100644 --- a/vendor/github.com/lestrrat-go/dsig/dsig.go +++ b/vendor/github.com/lestrrat-go/dsig/dsig.go @@ -28,6 +28,12 @@ const ( ECDSA EdDSAFamily Custom + // MLDSAFamily covers the ML-DSA parameter sets. It is deliberately not + // Custom: Custom means this library knows nothing about the algorithm, + // which would be false here and misleads callers that switch on Family. + // + // It sits after Custom so the values earlier releases assigned stay put. + MLDSAFamily maxFamily ) @@ -44,6 +50,8 @@ func (f Family) String() string { return "EdDSA" case Custom: return "Custom" + case MLDSAFamily: + return "ML-DSA" default: return "InvalidFamily" } @@ -153,13 +161,17 @@ func RegisterAlgorithm(name string, info AlgorithmInfo) error { } case EdDSAFamily: // EdDSA metadata is optional for now - case Custom: + case Custom, MLDSAFamily: + // Both families carry their implementation in Meta. The other families + // put passive metadata there. For ML-DSA this is forced: crypto/mldsa + // exists only from Go 1.27, so the algorithm cannot be described by a + // value type this file could name. _, isSigner := info.Meta.(Signer) _, isSignerWithOpts := info.Meta.(SignerWithOpts) _, isVerifier := info.Meta.(Verifier) _, isVerifierWithOpts := info.Meta.(VerifierWithOpts) if !isSigner && !isSignerWithOpts && !isVerifier && !isVerifierWithOpts { - return fmt.Errorf("custom algorithm %s: Meta must implement Signer, SignerWithOpts, Verifier, or VerifierWithOpts", name) + return fmt.Errorf("%s algorithm %s: Meta must implement Signer, SignerWithOpts, Verifier, or VerifierWithOpts", info.Family, name) } default: return fmt.Errorf("unsupported algorithm family %s for algorithm %s", info.Family, name) @@ -297,4 +309,3 @@ func init() { builtinAlgorithms[name] = struct{}{} } } - diff --git a/vendor/github.com/lestrrat-go/dsig/ecdsa.go b/vendor/github.com/lestrrat-go/dsig/ecdsa.go index 570b9ae07..9da4ac244 100644 --- a/vendor/github.com/lestrrat-go/dsig/ecdsa.go +++ b/vendor/github.com/lestrrat-go/dsig/ecdsa.go @@ -12,7 +12,6 @@ import ( "github.com/lestrrat-go/dsig/internal/ecutil" ) - func ecdsaGetSignerKey(key any) (*ecdsa.PrivateKey, crypto.Signer, bool, error) { cs, isCryptoSigner := key.(crypto.Signer) if isCryptoSigner { diff --git a/vendor/github.com/lestrrat-go/dsig/mldsa.go b/vendor/github.com/lestrrat-go/dsig/mldsa.go new file mode 100644 index 000000000..218204774 --- /dev/null +++ b/vendor/github.com/lestrrat-go/dsig/mldsa.go @@ -0,0 +1,193 @@ +//go:build go1.27 + +package dsig + +import ( + "crypto" + "crypto/mldsa" + "fmt" + "io" +) + +// ML-DSA signature algorithms, the post-quantum scheme specified in FIPS 204. +// The three names identify the three parameter sets, which differ in security +// level and in key and signature sizes. +// +// These names match what crypto/mldsa's Parameters.String reports, so the +// parameter set a key carries can be compared against the algorithm name +// directly. +// +// ML-DSA is available only when dsig is built with Go 1.27 or later, which is +// when crypto/mldsa becomes part of the standard library. On earlier +// toolchains these algorithms are not registered and not declared. +const ( + MLDSA44 = "ML-DSA-44" + MLDSA65 = "ML-DSA-65" + MLDSA87 = "ML-DSA-87" +) + +func init() { + for _, params := range []mldsa.Parameters{mldsa.MLDSA44(), mldsa.MLDSA65(), mldsa.MLDSA87()} { + name := params.String() + if err := RegisterAlgorithm(name, AlgorithmInfo{ + Family: MLDSAFamily, + Meta: &mldsaAlgorithm{params: params}, + }); err != nil { + panic(fmt.Sprintf("failed to register algorithm %s: %v", name, err)) + } + builtinAlgorithms[name] = struct{}{} + } +} + +// SignMLDSA generates an ML-DSA signature for the given payload. +// +// opts may be nil, which signs payload directly with no context. Pass an +// *[mldsa.Options] to supply a domain-separation context, which [VerifyMLDSA] +// then requires to match. +// +// opts is a [crypto.SignerOpts] so that both of ML-DSA's signing modes stay +// expressible. Passing [crypto.MLDSAMu] means payload holds a pre-hashed μ +// message representative. That mode is a shortcut for callers who already have +// μ, and it produces an ordinary signature; [VerifyMLDSA] checks it against the +// original message, and the verify side needs no counterpart. +// +// crypto/mldsa rejects any other opts value, so a mistaken type cannot be +// silently downgraded to a context-free signature. +func SignMLDSA(key *mldsa.PrivateKey, payload []byte, opts crypto.SignerOpts) ([]byte, error) { + if key == nil { + return nil, fmt.Errorf(`dsig.SignMLDSA: key cannot be nil`) + } + // The io.Reader argument is ignored by crypto/mldsa; signing draws its own + // randomness. SignDeterministic is the variant that draws none. + return key.Sign(nil, payload, opts) +} + +// VerifyMLDSA verifies an ML-DSA signature for the given payload. +// +// opts may be nil. It must carry the same Context that was used to produce the +// signature, otherwise verification fails. +// +// Verification has a single mode, so opts is a concrete *[mldsa.Options]. μ is +// derived from the message, so a signature made from a pre-hashed μ verifies +// here against the original message. +func VerifyMLDSA(key *mldsa.PublicKey, payload, signature []byte, opts *mldsa.Options) error { + if key == nil { + return fmt.Errorf(`dsig.VerifyMLDSA: key cannot be nil`) + } + return mldsa.Verify(key, payload, signature, opts) +} + +// mldsaAlgorithm is the Custom-family adapter that binds one ML-DSA parameter +// set to the registry. It carries the parameter set so that every operation can +// check the caller's key against the algorithm that was asked for. +type mldsaAlgorithm struct { + params mldsa.Parameters +} + +// requireMLDSAParams reports whether a caller-supplied key belongs to the +// parameter set this algorithm was registered for. crypto/mldsa's Parameters is +// a comparable value naming one of the three FIPS 204 sets, so a plain +// comparison suffices. +// +// The check matters because the key owns the parameter set, and the call only +// names one. Without it, an ML-DSA-65 key would happily produce and verify +// ML-DSA-65 signatures while the caller believed it had selected ML-DSA-44. +// Anything that reads the algorithm name to decide a post-quantum security +// level would then be misled, so the mismatch is an error. +func (a *mldsaAlgorithm) requireMLDSAParams(got mldsa.Parameters) error { + if got != a.params { + return fmt.Errorf(`ML-DSA parameter set mismatch: key is %s, algorithm is %s`, got, a.params) + } + return nil +} + +func (a *mldsaAlgorithm) privateKey(key any) (*mldsa.PrivateKey, error) { + sk, ok := key.(*mldsa.PrivateKey) + if !ok { + return nil, fmt.Errorf(`expected *mldsa.PrivateKey, got %T`, key) + } + if err := a.requireMLDSAParams(sk.PublicKey().Parameters()); err != nil { + return nil, err + } + return sk, nil +} + +// publicKey narrows the key types the verify surface accepts. A private key is +// allowed so callers holding only one half do not have to unwrap it themselves. +func (a *mldsaAlgorithm) publicKey(key any) (*mldsa.PublicKey, error) { + var pk *mldsa.PublicKey + switch k := key.(type) { + case *mldsa.PublicKey: + pk = k + case *mldsa.PrivateKey: + pk = k.PublicKey() + default: + return nil, fmt.Errorf(`expected *mldsa.PublicKey or *mldsa.PrivateKey, got %T`, key) + } + if err := a.requireMLDSAParams(pk.Parameters()); err != nil { + return nil, err + } + return pk, nil +} + +// mldsaOptions narrows a crypto.SignerOpts to the concrete type crypto/mldsa +// accepts. A non-nil value of any other type is an error. Dropping it would let +// a caller believe their Context was in force while the operation actually ran +// with an empty context, which is a signature substitution vector for schemes +// that rely on domain separation. +func mldsaOptions(opts crypto.SignerOpts) (*mldsa.Options, error) { + if opts == nil { + return nil, nil + } + mldsaOpts, ok := opts.(*mldsa.Options) + if !ok { + return nil, fmt.Errorf(`expected *mldsa.Options, got %T`, opts) + } + return mldsaOpts, nil +} + +func (a *mldsaAlgorithm) Sign(key any, payload []byte, _ io.Reader) ([]byte, error) { + sk, err := a.privateKey(key) + if err != nil { + return nil, fmt.Errorf(`dsig.Sign: %w`, err) + } + return SignMLDSA(sk, payload, nil) +} + +// SignWithOpts implements [SignerWithOpts], forwarding an *mldsa.Options +// Context to crypto/mldsa. +func (a *mldsaAlgorithm) SignWithOpts(key any, payload []byte, opts crypto.SignerOpts, _ io.Reader) ([]byte, error) { + sk, err := a.privateKey(key) + if err != nil { + return nil, fmt.Errorf(`dsig.SignWithOpts: %w`, err) + } + // Validated but deliberately not narrowed. SignMLDSA takes a + // crypto.SignerOpts, so converting to a typed nil here would hand + // crypto/mldsa a non-nil interface holding a nil pointer. + if _, err := mldsaOptions(opts); err != nil { + return nil, fmt.Errorf(`dsig.SignWithOpts: %w`, err) + } + return SignMLDSA(sk, payload, opts) +} + +func (a *mldsaAlgorithm) Verify(key any, payload, signature []byte) error { + pk, err := a.publicKey(key) + if err != nil { + return fmt.Errorf(`dsig.Verify: %w`, err) + } + return VerifyMLDSA(pk, payload, signature, nil) +} + +// VerifyWithOpts implements [VerifierWithOpts]. See [SignerWithOpts] for the +// rationale on rejecting a foreign opts type. +func (a *mldsaAlgorithm) VerifyWithOpts(key any, payload, signature []byte, opts crypto.SignerOpts) error { + pk, err := a.publicKey(key) + if err != nil { + return fmt.Errorf(`dsig.VerifyWithOpts: %w`, err) + } + mldsaOpts, err := mldsaOptions(opts) + if err != nil { + return fmt.Errorf(`dsig.VerifyWithOpts: %w`, err) + } + return VerifyMLDSA(pk, payload, signature, mldsaOpts) +} diff --git a/vendor/github.com/lestrrat-go/dsig/sign.go b/vendor/github.com/lestrrat-go/dsig/sign.go index 6f39f77ff..7d8b9340b 100644 --- a/vendor/github.com/lestrrat-go/dsig/sign.go +++ b/vendor/github.com/lestrrat-go/dsig/sign.go @@ -53,8 +53,8 @@ func SignWithOpts(key any, alg string, payload []byte, opts crypto.SignerOpts, r return dispatchECDSASign(key, info, payload, rr) case EdDSAFamily: return dispatchEdDSASign(key, info, payload, rr) - case Custom: - return dispatchCustomSign(key, info, payload, opts, rr) + case Custom, MLDSAFamily: + return dispatchMetaSign(key, info, payload, opts, rr) default: return nil, fmt.Errorf(`dsig.SignWithOpts: unsupported signature family %q`, info.Family) } @@ -124,7 +124,7 @@ func dispatchECDSASign(key any, info AlgorithmInfo, payload []byte, rr io.Reader return SignECDSA(privkey, payload, meta.Hash, rr) } -func dispatchCustomSign(key any, info AlgorithmInfo, payload []byte, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { +func dispatchMetaSign(key any, info AlgorithmInfo, payload []byte, opts crypto.SignerOpts, rr io.Reader) ([]byte, error) { if signer, ok := info.Meta.(SignerWithOpts); ok { return signer.SignWithOpts(key, payload, opts, rr) } @@ -175,6 +175,11 @@ func SignDigest(key any, alg string, digest []byte, rr io.Reader) ([]byte, error return nil, fmt.Errorf(`dsig.SignDigest: EdDSA does not support digest-based signing`) case Custom: return nil, fmt.Errorf(`dsig.SignDigest: custom algorithms do not support digest-based signing`) + case MLDSAFamily: + // ML-DSA's pre-hashed mode takes a mu representative. That is a + // different thing from a plain digest; pass mu to Sign with + // crypto.MLDSAMu. + return nil, fmt.Errorf(`dsig.SignDigest: ML-DSA does not support digest-based signing`) default: return nil, fmt.Errorf(`dsig.SignDigest: unsupported signature family %q`, info.Family) } @@ -242,4 +247,3 @@ func dispatchECDSASignDigest(key any, info AlgorithmInfo, digest []byte, rr io.R } return PackECDSASignature(r, s, privkey.Curve.Params().BitSize) } - diff --git a/vendor/github.com/lestrrat-go/dsig/verify.go b/vendor/github.com/lestrrat-go/dsig/verify.go index 8a3ddb6db..5999e505c 100644 --- a/vendor/github.com/lestrrat-go/dsig/verify.go +++ b/vendor/github.com/lestrrat-go/dsig/verify.go @@ -47,8 +47,8 @@ func VerifyWithOpts(key any, alg string, payload, signature []byte, opts crypto. return dispatchECDSAVerify(key, info, payload, signature) case EdDSAFamily: return dispatchEdDSAVerify(key, info, payload, signature) - case Custom: - return dispatchCustomVerify(key, info, payload, signature, opts) + case Custom, MLDSAFamily: + return dispatchMetaVerify(key, info, payload, signature, opts) default: return fmt.Errorf(`dsig.VerifyWithOpts: unsupported signature family %q`, info.Family) } @@ -93,6 +93,9 @@ func VerifyDigest(key any, alg string, digest, signature []byte) error { // TODO: a DigestVerifier interface (optional, checked here) would let // custom algorithms opt in to digest-based verification. return fmt.Errorf(`dsig.VerifyDigest: custom algorithms do not support digest-based verification`) + case MLDSAFamily: + // mu is derived from the message, so there is no digest to supply here. + return fmt.Errorf(`dsig.VerifyDigest: ML-DSA does not support digest-based verification`) default: return fmt.Errorf(`dsig.VerifyDigest: unsupported signature family %q`, info.Family) } @@ -227,7 +230,7 @@ func dispatchEdDSAVerify(key any, _ AlgorithmInfo, payload, signature []byte) er return VerifyEdDSA(pubkey, payload, signature) } -func dispatchCustomVerify(key any, info AlgorithmInfo, payload, signature []byte, opts crypto.SignerOpts) error { +func dispatchMetaVerify(key any, info AlgorithmInfo, payload, signature []byte, opts crypto.SignerOpts) error { if verifier, ok := info.Meta.(VerifierWithOpts); ok { return verifier.VerifyWithOpts(key, payload, signature, opts) } diff --git a/vendor/github.com/lestrrat-go/jwx/v4/AGENTS.md b/vendor/github.com/lestrrat-go/jwx/v4/AGENTS.md index b446052fc..a1dcbf4cc 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/AGENTS.md +++ b/vendor/github.com/lestrrat-go/jwx/v4/AGENTS.md @@ -19,14 +19,18 @@ This project requires **Go 1.26.0** or later. Check `go.mod` for the exact versi ## GOEXPERIMENT -v4 depends on `encoding/json/v2` which requires `GOEXPERIMENT=jsonv2`. The Makefile exports this automatically, but any direct `go build`, `go test`, or `go run` invocation **must** set it: +v4 depends on `encoding/json/v2`, which is behind `GOEXPERIMENT=jsonv2` on Go 1.26 and part of the standard library from Go 1.27 on. The Makefile probes the toolchain and rewrites `GOEXPERIMENT` to match it, adding `jsonv2` on Go 1.26 and removing it on Go 1.27, so `make` targets work on both even when your shell already exports the variable. Experiments other than `jsonv2` are left alone. `scripts/test-companion.sh` carries the same probe. + +A direct `go build`, `go test`, or `go run` invocation on **Go 1.26** must set it: ```bash GOEXPERIMENT=jsonv2 go test ./... GOEXPERIMENT=jsonv2 go build ./... ``` -Without this, builds fail with `build constraints exclude all Go files` errors. +Without this, Go 1.26 builds fail with `build constraints exclude all Go files` errors. + +On **Go 1.27** do not set it. Naming an experiment the toolchain already ships for real rebuilds the standard library under a non-default configuration for no benefit. ## Module Path vs Physical Layout @@ -199,7 +203,12 @@ Use `github.com/stretchr/testify/require` for assertions (not `assert`). ## Build Tags -No build tags in v4. Optional features (signature algorithms, backend replacements) are provided as extension modules under [`github.com/jwx-go`](https://github.com/jwx-go). See [Extension Modules](docs/10-extensions.md) for the full list. +No feature build tags in v4. Optional features (signature algorithms, backend replacements) are provided as extension modules under [`github.com/jwx-go`](https://github.com/jwx-go). See [Extension Modules](docs/10-extensions.md) for the full list. + +Two exceptions exist, both keyed on the Go version rather than on a feature. Do not add feature build tags alongside them. + +1. A json/v2 compatibility shim. `internal/json/skipfunc_pre_go127.go` and `internal/json/skipfunc_go127.go` pick the "skip this value" sentinel, which Go 1.27 renamed from `json/v2.SkipFunc` to `errors.ErrUnsupported`. +2. Native ML-DSA. `jwa/signature_go127_gen.go` (generated from `jwa/objects.yml`), `jwk/mldsa.go`, and `jws/mldsa.go` are all `//go:build go1.27`, because `crypto/mldsa` joins the standard library in Go 1.27. On Go 1.26 the algorithms are not registered at all, so `jws.Sign` and `jws.Verify` report them as unsupported instead of failing later with a confusing key error. ML-DSA on Go 1.26 still needs [`github.com/jwx-go/mldsa/v4`](https://github.com/jwx-go/mldsa). ## Quick Reference: Common Modifications diff --git a/vendor/github.com/lestrrat-go/jwx/v4/Changes b/vendor/github.com/lestrrat-go/jwx/v4/Changes index 9cbf4da74..c1966fe07 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/Changes +++ b/vendor/github.com/lestrrat-go/jwx/v4/Changes @@ -4,6 +4,37 @@ Changes v4 has many incompatibilities with v3. To see the full list of differences between v3 and v4, please read the [Changes-v4.md file](./Changes-v4.md). Coding Agents should read [MIGRATION-v4.md](./MICRATION-v4.md) +v4.4.0 20 August 2026 + * [jwa][jwk][jws] ML-DSA (FIPS 204) is now implemented natively when jwx is + built with Go 1.27 or later, where `crypto/mldsa` is part of the standard + library. `jwa.MLDSA44()`, `jwa.MLDSA65()` and `jwa.MLDSA87()` are + registered automatically, and `*mldsa.PrivateKey` / `*mldsa.PublicKey` + values from `crypto/mldsa` work directly with `jws.Sign`, `jws.Verify`, + `jwk.Import` and `jwk.Export`. No extension module and no side-effect + import are required. + + On Go 1.26 the algorithms are not registered at all, so `jws.Sign` and + `jws.Verify` report them as unsupported instead of failing later with a + confusing key error. ML-DSA on Go 1.26 still needs + `github.com/jwx-go/mldsa/v4`. That extension remains safe to import on + Go 1.27 from its v4.0.5 release on, which detects the native + registration and bridges `filippo.io/mldsa` keys onto it. (#2309, #2310, + #2311) + +v4.3.0 18 August 2026 + * [jwe] Correct the JSON `"aad"` member so it contains only + BASE64URL of the external Additional Authenticated Data, rather than the + combined value used as the content-encryption AAD. Add + `jwe.WithAuthenticateData` for encrypting JSON JWEs with external AAD; + the value is included in the shared AEAD input for all recipients, and + compact serialization rejects non-empty external AAD. (#2275, #2277) + * Fix the build under Go 1.27. Go 1.27 removed `encoding/json/v2.SkipFunc` + and gave its role to `errors.ErrUnsupported`, which broke compilation of + `internal/json` for anyone on the new toolchain. The sentinel is now + selected by a Go-version build tag, so both Go 1.26 (with + `GOEXPERIMENT=jsonv2`) and Go 1.27 build from the same source. No public + API or behavior change. + v4.2.0 24 July 2026 * [jwk] `jwk.Parse` (and `Set.UnmarshalJSON`) no longer fails an entire JWK Set when a single entry in the "keys" array cannot be parsed. By diff --git a/vendor/github.com/lestrrat-go/jwx/v4/MIGRATION.md b/vendor/github.com/lestrrat-go/jwx/v4/MIGRATION.md index 0038294a7..f814c6fa8 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/MIGRATION.md +++ b/vendor/github.com/lestrrat-go/jwx/v4/MIGRATION.md @@ -32,7 +32,7 @@ Text output labels each finding as `(auto)` or `(manual)`, with migration notes ## Prerequisites - Go 1.26.0 or later -- Set `GOEXPERIMENT=jsonv2` in your build environment +- On Go 1.26 only: set `GOEXPERIMENT=jsonv2` in your build environment. Go 1.27 ships `encoding/json/v2` in the standard library, so leave `GOEXPERIMENT` unset there. - Update `go.mod`: change module requirement to `github.com/lestrrat-go/jwx/v4` ## Quick Reference @@ -559,10 +559,11 @@ These changes cannot be mechanically transformed and need human judgment: require github.com/lestrrat-go/jwx/v4 v4.x.x ``` -2. Set environment variable: +2. Set environment variable, **on Go 1.26 only**: ```bash export GOEXPERIMENT=jsonv2 ``` + Go 1.27 ships `encoding/json/v2` in the standard library. Leave `GOEXPERIMENT` unset there: naming an experiment the toolchain already ships rebuilds the standard library under a non-default configuration for no benefit. 3. Remove build tags from commands: ```bash diff --git a/vendor/github.com/lestrrat-go/jwx/v4/Makefile b/vendor/github.com/lestrrat-go/jwx/v4/Makefile index 3867c2458..4c433f1c1 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/Makefile +++ b/vendor/github.com/lestrrat-go/jwx/v4/Makefile @@ -1,6 +1,29 @@ -.PHONY: generate realclean cover viewcover test lint check_diffs imports tidy jwx fuzz fuzz-jwt fuzz-jws fuzz-jwe fuzz-jwk companion-test - -export GOEXPERIMENT := jsonv2 +.PHONY: generate realclean cover viewcover test lint check_diffs imports tidy jwx fuzz fuzz-jwt fuzz-jws fuzz-jwe fuzz-jwk companion-test print-goexperiment + +# encoding/json/v2 sits behind GOEXPERIMENT=jsonv2 on Go 1.26 and is part of +# the standard library from Go 1.27 on. Probe the toolchain rather than +# hardcoding a version, and do not name the experiment when the toolchain +# already ships it for real: that forces the standard library to be rebuilt +# under a non-default configuration. +# +# Both branches rewrite GOEXPERIMENT instead of only setting it, because the +# caller may have exported it. On Go 1.27 an inherited jsonv2 would otherwise +# survive and trigger the very rebuild this probe exists to avoid. Experiments +# other than jsonv2 are always preserved, and the result is idempotent, so a +# recursive $(MAKE) that inherits it lands on the same value. GOEXPERIMENT is +# cleared for the probe itself so that recursion re-probes the toolchain +# honestly instead of reading back what this file exported. +GOEXPERIMENT_COMMA := , +GOEXPERIMENT_EMPTY := +GOEXPERIMENT_SPACE := $(GOEXPERIMENT_EMPTY) $(GOEXPERIMENT_EMPTY) +GOEXPERIMENT_OTHERS := $(strip $(filter-out jsonv2,$(subst $(GOEXPERIMENT_COMMA),$(GOEXPERIMENT_SPACE),$(GOEXPERIMENT)))) +GOEXPERIMENT_REST := $(subst $(GOEXPERIMENT_SPACE),$(GOEXPERIMENT_COMMA),$(GOEXPERIMENT_OTHERS)) + +ifneq ($(shell GOEXPERIMENT= go list encoding/json/v2 >/dev/null 2>&1 || echo needed),) +export GOEXPERIMENT := $(if $(GOEXPERIMENT_REST),$(GOEXPERIMENT_REST)$(GOEXPERIMENT_COMMA))jsonv2 +else +export GOEXPERIMENT := $(GOEXPERIMENT_REST) +endif generate: @go generate @@ -40,6 +63,11 @@ lint: check_diffs: ./scripts/check-diff.sh +# Reports the GOEXPERIMENT this Makefile settled on for the current toolchain. +# CI uses it to assert that the Go 1.27 job does not name the jsonv2 experiment. +print-goexperiment: + @echo "$(GOEXPERIMENT)" + imports: goimports -w ./ diff --git a/vendor/github.com/lestrrat-go/jwx/v4/README.md b/vendor/github.com/lestrrat-go/jwx/v4/README.md index f02fbd4b0..36b1a695b 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/README.md +++ b/vendor/github.com/lestrrat-go/jwx/v4/README.md @@ -7,7 +7,9 @@ If you are using this module in your product or your company, please add your pr # Requirements * Go 1.26 or later -* `GOEXPERIMENT=jsonv2` +* `GOEXPERIMENT=jsonv2`, **on Go 1.26 only** + +v4 uses `encoding/json/v2`, which sits behind `GOEXPERIMENT=jsonv2` on Go 1.26 and is part of the standard library from Go 1.27 on. On Go 1.27 leave `GOEXPERIMENT` unset: naming an experiment the toolchain already ships rebuilds the standard library under a non-default configuration for no benefit. # Install @@ -186,7 +188,7 @@ Additionally supported via the main module or [extension modules](docs/10-extens | Specification | Support | |---------------|---------| | [FIPS 203](https://csrc.nist.gov/pubs/fips/203/final) (ML-KEM) | JWE key encapsulation via [`github.com/jwx-go/mlkem`](https://github.com/jwx-go/mlkem): ML-KEM-768, ML-KEM-1024, hybrid variants (draft-ietf-jose-pqc-kem) | -| [FIPS 204](https://csrc.nist.gov/pubs/fips/204/final) (ML-DSA) | JWS signatures via [`github.com/jwx-go/mldsa`](https://github.com/jwx-go/mldsa) | +| [FIPS 204](https://csrc.nist.gov/pubs/fips/204/final) (ML-DSA) | JWS signatures: native from Go 1.27 on, via [`github.com/jwx-go/mldsa`](https://github.com/jwx-go/mldsa) on Go 1.26 ([details](docs/10-extensions.md#which-implementation-you-get)) | ## History diff --git a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/BUILD.bazel index 0b622a39d..9a668d1b2 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/BUILD.bazel +++ b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/BUILD.bazel @@ -5,6 +5,8 @@ go_library( srcs = [ "json.go", "registry.go", + "skipfunc_go127.go", + "skipfunc_pre_go127.go", ], importpath = "github.com/lestrrat-go/jwx/v4/internal/json", visibility = ["//:__subpackages__"], diff --git a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/registry.go b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/registry.go index b8be182b6..63c2de98d 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/registry.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/registry.go @@ -70,7 +70,9 @@ func (dec *TypedDecoder[T]) Decode(data []byte) (any, error) { var useNumberUnmarshalers = jsonv2.WithUnmarshalers( jsonv2.UnmarshalFromFunc(func(dec *jsontext.Decoder, val *any) error { if dec.PeekKind() != '0' { - return jsonv2.SkipFunc + // the sentinel is spelled differently before and after go1.27; + // see skipfunc_go127.go / skipfunc_pre_go127.go + return errSkipFunc } raw, err := dec.ReadValue() if err != nil { diff --git a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_go127.go b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_go127.go new file mode 100644 index 000000000..fedd48645 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_go127.go @@ -0,0 +1,15 @@ +//go:build go1.27 + +package json + +import ( + "errors" +) + +// errSkipFunc is the sentinel a marshal/unmarshal function returns to decline +// handling a value, so that the next applicable function (or the default +// behavior) is used instead. +// +// Go 1.27 removed json/v2.SkipFunc and gave the role to errors.ErrUnsupported, +// which json/v2 now matches with errors.Is rather than by identity. +var errSkipFunc = errors.ErrUnsupported diff --git a/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_pre_go127.go b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_pre_go127.go new file mode 100644 index 000000000..1de560980 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v4/internal/json/skipfunc_pre_go127.go @@ -0,0 +1,15 @@ +//go:build !go1.27 + +package json + +import ( + jsonv2 "encoding/json/v2" +) + +// errSkipFunc is the sentinel a marshal/unmarshal function returns to decline +// handling a value, so that the next applicable function (or the default +// behavior) is used instead. +// +// Go 1.26 spells it json/v2.SkipFunc and compares it by identity +// (`err == SkipFunc`), so it has to be returned verbatim. +var errSkipFunc = jsonv2.SkipFunc diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwa/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v4/jwa/BUILD.bazel index af40a0078..5ed884ed7 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwa/BUILD.bazel +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwa/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "key_type_gen.go", "options_gen.go", "signature_gen.go", + "signature_go127_gen.go", ], importpath = "github.com/lestrrat-go/jwx/v4/jwa", visibility = ["//visibility:public"], @@ -29,8 +30,10 @@ go_test( "jwa_test.go", "key_encryption_gen_test.go", "key_type_gen_test.go", + "mldsa_test.go", "options_gen_test.go", "signature_gen_test.go", + "signature_go127_gen_test.go", ], embed = [":jwa"], deps = ["@com_github_stretchr_testify//require"], diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwa/objects.yml b/vendor/github.com/lestrrat-go/jwx/v4/jwa/objects.yml index b08d03c79..8d7c5dc0b 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwa/objects.yml +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwa/objects.yml @@ -144,6 +144,24 @@ algorithms: value: Ed25519 returnval_comment: EdDSA signature algorithm using Ed25519 (RFC 9864) comment: The function name is tentative and may change in future releases. + # ML-DSA is available only from Go 1.27, which is when crypto/mldsa joins + # the standard library. build_constraint puts these in their own file so + # earlier toolchains neither declare nor register them. + - name: MLDSA44 + value: ML-DSA-44 + build_constraint: go1.27 + returnval_comment: the ML-DSA-44 signature algorithm (FIPS 204, NIST security level 2) + comment: Available only when jwx is built with Go 1.27 or later. + - name: MLDSA65 + value: ML-DSA-65 + build_constraint: go1.27 + returnval_comment: the ML-DSA-65 signature algorithm (FIPS 204, NIST security level 3) + comment: Available only when jwx is built with Go 1.27 or later. + - name: MLDSA87 + value: ML-DSA-87 + build_constraint: go1.27 + returnval_comment: the ML-DSA-87 signature algorithm (FIPS 204, NIST security level 5) + comment: Available only when jwx is built with Go 1.27 or later. - name: PS256 value: PS256 returnval_comment: RSASSA-PSS signature algorithm using SHA-256 and MGF1-SHA256 diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwa/signature_go127_gen.go b/vendor/github.com/lestrrat-go/jwx/v4/jwa/signature_go127_gen.go new file mode 100644 index 000000000..8a2254b7c --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwa/signature_go127_gen.go @@ -0,0 +1,39 @@ +//go:build go1.27 + +// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT. + +package jwa + +import ( + "fmt" +) + +func init() { + // builtin values for SignatureAlgorithm + algorithms := make([]SignatureAlgorithm, 3) + algorithms[0] = NewSignatureAlgorithm("ML-DSA-44") + algorithms[1] = NewSignatureAlgorithm("ML-DSA-65") + algorithms[2] = NewSignatureAlgorithm("ML-DSA-87") + + if err := RegisterSignatureAlgorithm(algorithms...); err != nil { + panic(fmt.Sprintf("jwa: failed to register builtin SignatureAlgorithm: %s", err)) + } + for _, alg := range algorithms { + markBuiltin(alg.String()) + } +} + +// MLDSA44 returns an object representing the ML-DSA-44 signature algorithm (FIPS 204, NIST security level 2). Available only when jwx is built with Go 1.27 or later. +func MLDSA44() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ML-DSA-44") +} + +// MLDSA65 returns an object representing the ML-DSA-65 signature algorithm (FIPS 204, NIST security level 3). Available only when jwx is built with Go 1.27 or later. +func MLDSA65() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ML-DSA-65") +} + +// MLDSA87 returns an object representing the ML-DSA-87 signature algorithm (FIPS 204, NIST security level 5). Available only when jwx is built with Go 1.27 or later. +func MLDSA87() SignatureAlgorithm { + return lookupBuiltinSignatureAlgorithm("ML-DSA-87") +} diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwe/jwe.go b/vendor/github.com/lestrrat-go/jwx/v4/jwe/jwe.go index 3f36af240..f6f491f26 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwe/jwe.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwe/jwe.go @@ -797,13 +797,14 @@ func (dc *decryptContext) decryptContent(msg *Message, alg jwa.KeyEncryptionAlgo // encryptContext holds the state during JWE encryption, similar to JWS signContext type encryptContext struct { - calg jwa.ContentEncryptionAlgorithm - compression jwa.CompressionAlgorithm - format int - pbes2Count int - builders []*recipientBuilder - protected Headers - builderBuf [1]recipientBuilder // inline storage for common single-recipient case + calg jwa.ContentEncryptionAlgorithm + compression jwa.CompressionAlgorithm + format int + pbes2Count int + authenticatedData []byte + builders []*recipientBuilder + protected Headers + builderBuf [1]recipientBuilder // inline storage for common single-recipient case } var encryptContextPool = pool.New(allocEncryptContext, freeEncryptContext) @@ -821,6 +822,7 @@ func freeEncryptContext(ec *encryptContext) *encryptContext { ec.compression = jwa.NoCompress() ec.format = fmtCompact ec.pbes2Count = 0 + ec.authenticatedData = nil ec.builders = ec.builders[:0] ec.protected = nil ec.builderBuf[0] = recipientBuilder{} @@ -864,6 +866,8 @@ func (ec *encryptContext) ProcessOptions(options []EncryptOption) error { ec.calg = option.MustGet[jwa.ContentEncryptionAlgorithm](opt) case identCompress{}: ec.compression = option.MustGet[jwa.CompressionAlgorithm](opt) + case identAuthenticateData{}: + ec.authenticatedData = option.MustGet[[]byte](opt) case identMergeProtectedHeaders{}: mergeProtected = option.MustGet[bool](opt) case identProtectedHeaders{}: @@ -892,6 +896,10 @@ func (ec *encryptContext) ProcessOptions(options []EncryptOption) error { } } + if len(ec.authenticatedData) > 0 && ec.format == fmtCompact { + return fmt.Errorf(`cannot use compact serialization with external authenticated data (use WithJSON())`) + } + if useRawCEK { if len(ec.builders) != 1 { return fmt.Errorf(`multiple recipients for ECDH-ES/DIRECT mode are not supported`) @@ -1082,12 +1090,13 @@ func (ec *encryptContext) EncryptMessage(payload []byte, cek []byte) ([]byte, er } } - aad, err := protected.Encode() + protectedAAD, err := protected.Encode() if err != nil { return nil, fmt.Errorf(`failed to base64 encode protected headers: %w`, err) } - iv, ciphertext, tag, err := contentcrypt.Encrypt(cek, payload, aad) + contentAAD := concatAAD(protectedAAD, base64.Encode(ec.authenticatedData)) + iv, ciphertext, tag, err := contentcrypt.Encrypt(cek, payload, contentAAD) if err != nil { return nil, fmt.Errorf(`failed to encrypt payload: %w`, err) } @@ -1097,7 +1106,7 @@ func (ec *encryptContext) EncryptMessage(payload []byte, cek []byte) ([]byte, er // were copied into protected above), so we can build the compact // serialization directly from the raw parts. if ec.format == fmtCompact { - return jwebb.JoinCompact(base64.DefaultEncoder(), aad, recipients[0].EncryptedKey(), iv, ciphertext, tag), nil + return jwebb.JoinCompact(base64.DefaultEncoder(), protectedAAD, recipients[0].EncryptedKey(), iv, ciphertext, tag), nil } msg := msgPool.Get() @@ -1118,6 +1127,11 @@ func (ec *encryptContext) EncryptMessage(payload []byte, cek []byte) ([]byte, er if err := msg.Set(TagKey, tag); err != nil { return nil, fmt.Errorf(`failed to set %s: %w`, TagKey, err) } + if len(ec.authenticatedData) > 0 { + if err := msg.Set(AuthenticatedDataKey, ec.authenticatedData); err != nil { + return nil, fmt.Errorf(`failed to set %s: %w`, AuthenticatedDataKey, err) + } + } switch ec.format { case fmtJSON: diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwe/message.go b/vendor/github.com/lestrrat-go/jwx/v4/jwe/message.go index 6012b362d..ca953ec48 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwe/message.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwe/message.go @@ -228,31 +228,29 @@ func (m *Message) MarshalJSON() ([]byte, error) { fields = append(fields, jsonKV{Key: InitializationVectorKey, Value: v}) } - var encodedProtectedHeaders []byte if h := m.ProtectedHeaders(); h != nil { v, err := h.Encode() if err != nil { return nil, fmt.Errorf(`failed to encode protected headers: %w`, err) } - encodedProtectedHeaders = v - if len(encodedProtectedHeaders) <= 2 { // '{}' - encodedProtectedHeaders = nil - } else { + if len(v) > 2 { // '{}' fields = append(fields, jsonKV{ Key: ProtectedHeadersKey, - Value: fmt.Sprintf("%q", encodedProtectedHeaders), + Value: fmt.Sprintf("%q", v), }) } } if aad := m.AuthenticatedData(); len(aad) > 0 { - aad = base64.Encode(aad) - if encodedProtectedHeaders != nil { - aad = concatAAD(encodedProtectedHeaders, aad) - } - - v, err := marshalField(aad) + // RFC 7516 §7.2.1: the "aad" member is BASE64URL(JWE AAD) — the + // external Additional Authenticated Data on its own. The protected + // header is prepended to the AAD only when building the AEAD input + // (concatAAD, in the encrypt/decrypt paths), never in the serialized + // member. Encode to a base64url string like the ciphertext/iv/tag + // members above so marshalField does not base64-encode the raw bytes + // a second time (which also used the padded std alphabet). + v, err := marshalField(base64.EncodeToString(aad)) if err != nil { return nil, fmt.Errorf(`failed to encode %s field: %w`, AuthenticatedDataKey, err) } diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.go b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.go index c2575926b..89e6c89d5 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.go @@ -1,6 +1,8 @@ package jwe import ( + "bytes" + "github.com/lestrrat-go/jwx/v4/jwa" "github.com/lestrrat-go/jwx/v4/jwk" "github.com/lestrrat-go/option/v3" @@ -81,6 +83,16 @@ func WithProtectedHeaders(h Headers) EncryptOption { return &encryptOption{option.New(identProtectedHeaders{}, cloned)} } +// WithAuthenticateData specifies the external Additional Authenticated Data +// to use when encrypting a JSON JWE. +// +// The data is copied before it is stored in the option. External Additional +// Authenticated Data is not supported by compact serialization; pass +// WithJSON() to select JSON serialization. +func WithAuthenticateData(aad []byte) EncryptOption { + return &encryptOption{option.New(identAuthenticateData{}, bytes.Clone(aad))} +} + type withKey struct { alg jwa.KeyAlgorithm key any diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.yaml b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.yaml index 655e528a9..4099522f7 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.yaml +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options.yaml @@ -55,6 +55,13 @@ options: skip_option: true - ident: ProtectedHeaders skip_option: true + - ident: AuthenticateData + skip_option: true + interface: EncryptOption + argument_type: '[]byte' + comment: | + WithAuthenticateData specifies the external Additional Authenticated Data + to use when encrypting a JSON JWE. - ident: PerRecipientHeaders skip_option: true - ident: KeyProvider diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options_gen.go b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options_gen.go index 527483672..b52b248fa 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwe/options_gen.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwe/options_gen.go @@ -156,6 +156,7 @@ type withKeySetSuboption struct { func (*withKeySetSuboption) withKeySetSuboption() {} +type identAuthenticateData struct{} type identCBCBufferSize struct{} type identCEK struct{} type identCompress struct{} @@ -178,6 +179,10 @@ type identProtectedHeaders struct{} type identRequireKid struct{} type identSerialization struct{} +func (identAuthenticateData) String() string { + return "WithAuthenticateData" +} + func (identCBCBufferSize) String() string { return "WithCBCBufferSize" } diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwk/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v4/jwk/BUILD.bazel index c3f41347c..35a2dc533 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwk/BUILD.bazel +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwk/BUILD.bazel @@ -17,6 +17,7 @@ go_library( "io_gen.go", "jwk.go", "key_ops.go", + "mldsa.go", "okp.go", "okp_gen.go", "options.go", @@ -58,6 +59,7 @@ go_test( "headers_test.go", "jwk_test.go", "jwk_zero_on_error_test.go", + "mldsa_test.go", "options_gen_test.go", "probe_bench_test.go", "set_test.go", diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwk/mldsa.go b/vendor/github.com/lestrrat-go/jwx/v4/jwk/mldsa.go new file mode 100644 index 000000000..57e564f44 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwk/mldsa.go @@ -0,0 +1,137 @@ +//go:build go1.27 + +package jwk + +import ( + "bytes" + "crypto/mldsa" + "fmt" + + "github.com/lestrrat-go/jwx/v4/jwa" +) + +// ML-DSA (FIPS 204) keys are carried in the AKP key type defined by RFC 9802. +// The AKP container itself is toolchain-independent and lives in akp.go; only +// the conversion to and from crypto/mldsa's key types is gated on Go 1.27, +// because that is when crypto/mldsa joins the standard library. +func init() { + if err := RegisterKeyImporter(KeyImportFunc[*mldsa.PrivateKey](importMLDSAPrivateKey)); err != nil { + panic(fmt.Sprintf("jwk: failed to register ML-DSA private key importer: %s", err)) + } + if err := RegisterKeyImporter(KeyImportFunc[*mldsa.PublicKey](importMLDSAPublicKey)); err != nil { + panic(fmt.Sprintf("jwk: failed to register ML-DSA public key importer: %s", err)) + } + + // AKP keys report a KeyKind of "AKP:", so the exporter is registered + // once per parameter set. The bare "AKP" kind is left alone: it is shared + // with other AKP algorithms such as ML-KEM, which jwx does not implement. + for _, params := range mldsaParameterSets() { + kind := KeyKind(jwa.AKP().String() + ":" + params.String()) + if err := RegisterKeyExporter(kind, KeyExportFunc(exportMLDSAKey)); err != nil { + panic(fmt.Sprintf("jwk: failed to register ML-DSA key exporter for %s: %s", params, err)) + } + } +} + +// mldsaParameterSets returns the three parameter sets defined in FIPS 204. +func mldsaParameterSets() []mldsa.Parameters { + return []mldsa.Parameters{mldsa.MLDSA44(), mldsa.MLDSA65(), mldsa.MLDSA87()} +} + +// mldsaParamsForAlg maps a JWS "alg" value to its ML-DSA parameter set. +// The boolean is false for any algorithm that is not an ML-DSA variant. +func mldsaParamsForAlg(alg string) (mldsa.Parameters, bool) { + for _, params := range mldsaParameterSets() { + if params.String() == alg { + return params, true + } + } + return mldsa.Parameters{}, false +} + +// importMLDSAPrivateKey converts a *mldsa.PrivateKey to a jwk.Key. +func importMLDSAPrivateKey(raw *mldsa.PrivateKey) (Key, error) { + if raw == nil { + return nil, fmt.Errorf(`jwk: cannot import nil *mldsa.PrivateKey`) + } + pub := raw.PublicKey() + + key := newAKPPrivateKey() + if err := key.Set(AlgorithmKey, pub.Parameters().String()); err != nil { + return nil, fmt.Errorf(`jwk: failed to set "alg" on ML-DSA private key: %w`, err) + } + if err := key.Set(AKPPubKey, pub.Bytes()); err != nil { + return nil, fmt.Errorf(`jwk: failed to set "pub" on ML-DSA private key: %w`, err) + } + if err := key.Set(AKPPrivKey, raw.Bytes()); err != nil { + return nil, fmt.Errorf(`jwk: failed to set "priv" on ML-DSA private key: %w`, err) + } + return key, nil +} + +// importMLDSAPublicKey converts a *mldsa.PublicKey to a jwk.Key. +func importMLDSAPublicKey(raw *mldsa.PublicKey) (Key, error) { + if raw == nil { + return nil, fmt.Errorf(`jwk: cannot import nil *mldsa.PublicKey`) + } + + key := newAKPPublicKey() + if err := key.Set(AlgorithmKey, raw.Parameters().String()); err != nil { + return nil, fmt.Errorf(`jwk: failed to set "alg" on ML-DSA public key: %w`, err) + } + if err := key.Set(AKPPubKey, raw.Bytes()); err != nil { + return nil, fmt.Errorf(`jwk: failed to set "pub" on ML-DSA public key: %w`, err) + } + return key, nil +} + +// exportMLDSAKey converts an AKP jwk.Key to a raw crypto/mldsa key. +func exportMLDSAKey(key Key, _ any) (any, error) { + algV, ok := key.Algorithm() + if !ok { + return nil, fmt.Errorf(`jwk: AKP key is missing the required "alg" field`) + } + + params, ok := mldsaParamsForAlg(algV.String()) + if !ok { + // Some other AKP algorithm. Let the next exporter in the chain try. + return nil, ContinueError() + } + + pubV, ok := key.Field(AKPPubKey) + if !ok { + return nil, fmt.Errorf(`jwk: AKP key is missing the required "pub" field`) + } + pubBytes, ok := pubV.([]byte) + if !ok { + return nil, fmt.Errorf(`jwk: AKP key "pub" field is %T, expected []byte`, pubV) + } + + privV, hasPriv := key.Field(AKPPrivKey) + if !hasPriv { + pk, err := mldsa.NewPublicKey(params, pubBytes) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to construct ML-DSA public key: %w`, err) + } + return pk, nil + } + + privBytes, ok := privV.([]byte) + if !ok { + return nil, fmt.Errorf(`jwk: AKP key "priv" field is %T, expected []byte`, privV) + } + + sk, err := mldsa.NewPrivateKey(params, privBytes) + if err != nil { + return nil, fmt.Errorf(`jwk: failed to construct ML-DSA private key: %w`, err) + } + + // "priv" is the seed the whole key pair is derived from, so a "pub" that + // disagrees with it means the JWK is inconsistent. Returning the derived + // key regardless would silently ignore the attacker-supplied half of a + // tampered JWK. + if derived := sk.PublicKey().Bytes(); !bytes.Equal(derived, pubBytes) { + return nil, fmt.Errorf(`jwk: AKP key "pub" does not match the public key derived from "priv"`) + } + return sk, nil +} diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/BUILD.bazel b/vendor/github.com/lestrrat-go/jwx/v4/jws/BUILD.bazel index 44f22f453..0942e2ba9 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jws/BUILD.bazel +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "jws.go", "key_provider.go", "message.go", + "mldsa.go", "options.go", "options_gen.go", "sign_context.go", @@ -52,6 +53,8 @@ go_test( "jws_crit_test.go", "jws_test.go", "message_test.go", + "mldsa_fuzz_test.go", + "mldsa_test.go", "options_gen_test.go", "signer_test.go", "streaming_detached_test.go", diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/sign.go b/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/sign.go index f6027d0b2..515b8c604 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/sign.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/sign.go @@ -66,7 +66,7 @@ func SignWithOpts(key any, alg string, payload []byte, opts crypto.SignerOpts, r return dispatchECDSASign(key, dsigAlg, payload, rr) case dsig.EdDSAFamily: return dispatchEdDSASign(key, alg, dsigAlg, payload, rr) - case dsig.Custom: + case dsig.Custom, dsig.MLDSAFamily: return dsig.SignWithOpts(key, dsigAlg, payload, opts, rr) default: return nil, fmt.Errorf(`jwsbb.SignWithOpts: unsupported dsig algorithm family %q`, dsigInfo.Family) diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/verify.go b/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/verify.go index 0ce02097e..da353b2d8 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/verify.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/jwsbb/verify.go @@ -52,7 +52,7 @@ func VerifyWithOpts(key any, alg string, payload, signature []byte, opts crypto. return dispatchECDSAVerify(key, dsigAlg, payload, signature) case dsig.EdDSAFamily: return dispatchEdDSAVerify(key, alg, dsigAlg, payload, signature) - case dsig.Custom: + case dsig.Custom, dsig.MLDSAFamily: return dsig.VerifyWithOpts(key, dsigAlg, payload, signature, opts) default: return fmt.Errorf(`jwsbb.VerifyWithOpts: unsupported dsig algorithm family %q`, dsigInfo.Family) diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/mldsa.go b/vendor/github.com/lestrrat-go/jwx/v4/jws/mldsa.go new file mode 100644 index 000000000..4df32ffb0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/mldsa.go @@ -0,0 +1,190 @@ +//go:build go1.27 + +package jws + +import ( + "bytes" + "crypto/mldsa" + "fmt" + + "github.com/lestrrat-go/jwx/v4/jwa" + "github.com/lestrrat-go/jwx/v4/jwk" + "github.com/lestrrat-go/jwx/v4/jws/jwsbb" +) + +// ML-DSA (FIPS 204) signing and verification. This file is gated on Go 1.27 +// because that is when crypto/mldsa joins the standard library; on Go 1.26 the +// algorithms are not registered at all, so jws.Sign and jws.Verify report them +// as unsupported, instead of the confusing key error that would surface +// later. +func init() { + for _, entry := range []struct { + alg jwa.SignatureAlgorithm + params mldsa.Parameters + }{ + {jwa.MLDSA44(), mldsa.MLDSA44()}, + {jwa.MLDSA65(), mldsa.MLDSA65()}, + {jwa.MLDSA87(), mldsa.MLDSA87()}, + } { + name := entry.params.String() + + // dsig owns the algorithm itself from v1.4.0 on, including the + // parameter-set check. It uses the same names as JOSE, so jwsbb's + // fallback resolves them with no mapping registered here. + if err := RegisterSigner(entry.alg, &mldsaSigner{algName: name, params: entry.params}); err != nil { + panic(fmt.Sprintf("jws: failed to register signer for %s: %s", name, err)) + } + if err := RegisterVerifier(entry.alg, &mldsaVerifier{algName: name, params: entry.params}); err != nil { + panic(fmt.Sprintf("jws: failed to register verifier for %s: %s", name, err)) + } + if err := RegisterAlgorithmForKeyType(jwa.AKP(), entry.alg); err != nil { + panic(fmt.Sprintf("jws: failed to associate %s with the AKP key type: %s", name, err)) + } + } +} + +// requireMLDSAParamsMatch reports whether a caller-supplied key belongs to the +// parameter set the algorithm was registered for. crypto/mldsa's Parameters is +// a comparable value describing one of the three FIPS 204 sets, so a plain +// comparison is enough. A mismatch means the "alg" header and the key disagree, +// which is the shape an algorithm-confusion attempt takes. +func requireMLDSAParamsMatch(got, want mldsa.Parameters) error { + if got != want { + return fmt.Errorf(`ML-DSA parameter set mismatch: key is %s, algorithm is %s`, got, want) + } + return nil +} + +// mldsaParamsForAlg maps a JWS "alg" value to its ML-DSA parameter set. +func mldsaParamsForAlg(alg string) (mldsa.Parameters, error) { + for _, params := range []mldsa.Parameters{mldsa.MLDSA44(), mldsa.MLDSA65(), mldsa.MLDSA87()} { + if params.String() == alg { + return params, nil + } + } + return mldsa.Parameters{}, fmt.Errorf(`unknown ML-DSA algorithm %q`, alg) +} + +type mldsaSigner struct { + algName string + params mldsa.Parameters +} + +func (s *mldsaSigner) Sign(key any, payload []byte) ([]byte, error) { + sk, err := mldsaPrivateKeyFrom(key, s.params) + if err != nil { + return nil, fmt.Errorf(`mldsa.Sign: %w`, err) + } + return jwsbb.Sign(sk, s.algName, payload, nil) +} + +type mldsaVerifier struct { + algName string + params mldsa.Parameters +} + +func (v *mldsaVerifier) Verify(key any, payload, signature []byte) error { + pk, err := mldsaPublicKeyFrom(key, v.params) + if err != nil { + return fmt.Errorf(`mldsa.Verify: %w`, err) + } + return jwsbb.Verify(pk, v.algName, payload, signature) +} + +// mldsaAKPFields pulls the parameter set and the "pub" bytes out of an AKP +// jwk.Key, rejecting keys whose "alg" does not name the expected ML-DSA +// parameter set. +func mldsaAKPFields(k jwk.Key, params mldsa.Parameters) ([]byte, error) { + if k.KeyType() != jwa.AKP() { + return nil, fmt.Errorf(`expected AKP key type, got %s`, k.KeyType()) + } + alg, ok := k.Algorithm() + if !ok { + return nil, fmt.Errorf(`AKP key is missing the required "alg" field`) + } + keyParams, err := mldsaParamsForAlg(alg.String()) + if err != nil { + return nil, fmt.Errorf(`AKP key "alg" is not an ML-DSA variant: %w`, err) + } + if err := requireMLDSAParamsMatch(keyParams, params); err != nil { + return nil, err + } + + pubV, ok := k.Field(jwk.AKPPubKey) + if !ok { + return nil, fmt.Errorf(`AKP key does not contain the "pub" field`) + } + pubBytes, ok := pubV.([]byte) + if !ok { + return nil, fmt.Errorf(`AKP key "pub" field is %T, expected []byte`, pubV) + } + return pubBytes, nil +} + +// mldsaPrivateKeyFrom accepts either a raw crypto/mldsa private key or an AKP +// jwk.Key holding one, and returns the private key for the expected parameter +// set. +func mldsaPrivateKeyFrom(key any, params mldsa.Parameters) (*mldsa.PrivateKey, error) { + switch k := key.(type) { + case *mldsa.PrivateKey: + if err := requireMLDSAParamsMatch(k.PublicKey().Parameters(), params); err != nil { + return nil, err + } + return k, nil + case jwk.Key: + pubBytes, err := mldsaAKPFields(k, params) + if err != nil { + return nil, err + } + + privV, ok := k.Field(jwk.AKPPrivKey) + if !ok { + return nil, fmt.Errorf(`AKP key does not contain the "priv" field`) + } + privBytes, ok := privV.([]byte) + if !ok { + return nil, fmt.Errorf(`AKP key "priv" field is %T, expected []byte`, privV) + } + + sk, err := mldsa.NewPrivateKey(params, privBytes) + if err != nil { + return nil, fmt.Errorf(`failed to construct ML-DSA private key: %w`, err) + } + if !bytes.Equal(sk.PublicKey().Bytes(), pubBytes) { + return nil, fmt.Errorf(`AKP key "pub" does not match the public key derived from "priv"`) + } + return sk, nil + default: + return nil, fmt.Errorf(`unsupported key type %T for ML-DSA signing`, key) + } +} + +// mldsaPublicKeyFrom accepts a raw crypto/mldsa key of either kind or an AKP +// jwk.Key, and returns the public key for the expected parameter set. +func mldsaPublicKeyFrom(key any, params mldsa.Parameters) (*mldsa.PublicKey, error) { + switch k := key.(type) { + case *mldsa.PublicKey: + if err := requireMLDSAParamsMatch(k.Parameters(), params); err != nil { + return nil, err + } + return k, nil + case *mldsa.PrivateKey: + pk := k.PublicKey() + if err := requireMLDSAParamsMatch(pk.Parameters(), params); err != nil { + return nil, err + } + return pk, nil + case jwk.Key: + pubBytes, err := mldsaAKPFields(k, params) + if err != nil { + return nil, err + } + pk, err := mldsa.NewPublicKey(params, pubBytes) + if err != nil { + return nil, fmt.Errorf(`failed to construct ML-DSA public key: %w`, err) + } + return pk, nil + default: + return nil, fmt.Errorf(`unsupported key type %T for ML-DSA verification`, key) + } +} diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/signer.go b/vendor/github.com/lestrrat-go/jwx/v4/jws/signer.go index 6123245e7..3c0f55d1d 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jws/signer.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/signer.go @@ -34,6 +34,15 @@ func init() { continue } + // Give the algorithm a default only if nothing has claimed it yet. + // Another file in this package may have registered a purpose-built + // signer already — ML-DSA does on Go 1.27 — and Go orders init() + // across files by filename, which is not something a registration + // should depend on. + if _, ok := signerDB.Load(alg); ok { + continue + } + if err := RegisterSigner(alg, defaultSigner{alg: alg}); err != nil { panic(fmt.Sprintf("RegisterSigner failed: %v", err)) } diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jws/streaming_detached.go b/vendor/github.com/lestrrat-go/jwx/v4/jws/streaming_detached.go index f4c57d827..952144c05 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jws/streaming_detached.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jws/streaming_detached.go @@ -377,6 +377,8 @@ func resolveStreamingAlgorithm(alg jwa.SignatureAlgorithm) (streamingAlgorithmIn switch info.Family { case dsig.EdDSAFamily: return streamingAlgorithmInfo{}, fmt.Errorf(`algorithm %q is incompatible with streaming detached payloads: RFC 8032 EdDSA signs the full message, not a pre-computed digest, so the payload cannot be streamed; use jws.WithDetachedPayload() if the payload fits in memory, or a digest-based algorithm such as HS256, RS256, or ES256`, alg) + case dsig.MLDSAFamily: + return streamingAlgorithmInfo{}, fmt.Errorf(`algorithm %q is incompatible with streaming detached payloads: ML-DSA signs the full message, not a pre-computed digest, so the payload cannot be streamed; use jws.WithDetachedPayload() if the payload fits in memory, or a digest-based algorithm such as HS256, RS256, or ES256`, alg) case dsig.Custom: return streamingAlgorithmInfo{}, fmt.Errorf(`algorithm %q is a custom-family algorithm and does not support streaming because the library cannot know whether the algorithm pre-hashes the payload; use jws.WithDetachedPayload() if the payload fits in memory`, alg) } diff --git a/vendor/github.com/lestrrat-go/jwx/v4/jwx.go b/vendor/github.com/lestrrat-go/jwx/v4/jwx.go index 8cf37ae82..01c0288b3 100644 --- a/vendor/github.com/lestrrat-go/jwx/v4/jwx.go +++ b/vendor/github.com/lestrrat-go/jwx/v4/jwx.go @@ -14,15 +14,18 @@ // // # Requirements // -// v4 uses the experimental encoding/json/v2 API, so consumers must build -// with: +// v4 requires Go 1.26.0 or later (see go.mod for the exact minimum) and uses +// the encoding/json/v2 API. Whether that needs extra build configuration +// depends on the toolchain: // -// - Go 1.26.0 or later (see go.mod for the exact minimum) -// - GOEXPERIMENT=jsonv2 set in the environment for every `go build`, -// `go test`, `go run`, and `go generate` invocation -// -// Without GOEXPERIMENT=jsonv2 the Go toolchain reports -// `build constraints exclude all Go files` and the module will not build. +// - Go 1.27 and later ship encoding/json/v2 in the standard library. Build +// normally and leave GOEXPERIMENT unset. Naming an experiment the +// toolchain already ships rebuilds the standard library under a +// non-default configuration for no benefit. +// - Go 1.26 keeps encoding/json/v2 behind GOEXPERIMENT=jsonv2, which must be +// set for every `go build`, `go test`, `go run`, and `go generate` +// invocation. Without it the toolchain reports `build constraints exclude +// all Go files` and the module will not build. // // Examples are stored in a separate Go module (to avoid adding // dependencies to this module), and thus does not appear in the diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index c592f6ad5..a19a89279 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -84,7 +84,7 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -124,7 +124,7 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Errorf(t, err, "error message %s", "formatted") @@ -144,8 +144,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") @@ -190,10 +190,10 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick // time.Sleep(8*time.Second) // externalValue = true // }() -// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { +// assert.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -552,7 +552,7 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool return NoDirExists(t, path, append([]interface{}{msg}, args...)...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoErrorf(t, err, "error message %s", "formatted") { @@ -849,7 +849,19 @@ func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// assert.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 58db92845..cd2a86061 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -146,7 +146,7 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs return Equal(a.t, expected, actual, msgAndArgs...) } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -158,7 +158,7 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... return EqualError(a.t, theError, errString, msgAndArgs...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -240,7 +240,7 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string return Equalf(a.t, expected, actual, msg, args...) } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) @@ -269,8 +269,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. return ErrorAsf(a.t, err, target, msg, args...) } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) @@ -281,8 +281,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . return ErrorContains(a.t, theError, contains, msgAndArgs...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") @@ -311,7 +311,7 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter return ErrorIsf(a.t, err, target, msg, args...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") @@ -372,10 +372,10 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor // time.Sleep(8*time.Second) // externalValue = true // }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1096,7 +1096,7 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) return NoDirExistsf(a.t, path, msg, args...) } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoError(err) { @@ -1109,7 +1109,7 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { return NoError(a.t, err, msgAndArgs...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoErrorf(err, "error message %s", "formatted") { @@ -1690,7 +1690,19 @@ func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Ti return WithinRangef(a.t, actual, start, end, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1698,7 +1710,19 @@ func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interf return YAMLEq(a.t, expected, actual, msgAndArgs...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 2fdf80fdd..a44b40ed3 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -9,7 +9,7 @@ import ( func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { objKind := reflect.TypeOf(object).Kind() if objKind != reflect.Slice && objKind != reflect.Array { - return false + return Fail(t, fmt.Sprintf("object %T is not an ordered collection", object), msgAndArgs...) } objValue := reflect.ValueOf(object) @@ -50,6 +50,9 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareR // assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } @@ -59,6 +62,9 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } @@ -68,6 +74,9 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } @@ -77,5 +86,8 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index de8de0cb6..1419e4776 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -17,11 +17,10 @@ import ( "unicode" "unicode/utf8" - "github.com/davecgh/go-spew/spew" - "github.com/pmezard/go-difflib/difflib" - // Wrapper around gopkg.in/yaml.v3 "github.com/stretchr/testify/assert/yaml" + "github.com/stretchr/testify/internal/difflib" + "github.com/stretchr/testify/internal/spew" ) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" @@ -33,19 +32,19 @@ type TestingT interface { // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. -type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool +type ComparisonAssertionFunc = func(TestingT, interface{}, interface{}, ...interface{}) bool // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. -type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool +type ValueAssertionFunc = func(TestingT, interface{}, ...interface{}) bool // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool +type BoolAssertionFunc = func(TestingT, bool, ...interface{}) bool // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool +type ErrorAssertionFunc = func(TestingT, error, ...interface{}) bool // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful // for table driven tests. @@ -325,13 +324,15 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) - for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { - // no need to align first line because it starts at the correct location (after the label) - if i != 0 { - // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab - outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") + scanner := bufio.NewScanner(strings.NewReader(message)) + for firstLine := true; scanner.Scan(); firstLine = false { + if !firstLine { + fmt.Fprint(outBuf, "\n\t"+strings.Repeat(" ", longestLabelLen+1)+"\t") } - outBuf.WriteString(scanner.Text()) + fmt.Fprint(outBuf, scanner.Text()) + } + if err := scanner.Err(); err != nil { + return fmt.Sprintf("cannot display message: %s", err) } return outBuf.String() @@ -544,9 +545,8 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b if !same { // both are pointers but not the same type & pointing to the same address return Fail(t, fmt.Sprintf("Not same: \n"+ - "expected: %p %#[1]v\n"+ - "actual : %p %#[2]v", - expected, actual), msgAndArgs...) + "expected: %[2]s (%[1]T)(%[1]p)\n"+ + "actual : %[4]s (%[3]T)(%[3]p)", expected, truncatingFormat("%#v", expected), actual, truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -571,8 +571,8 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} if same { return Fail(t, fmt.Sprintf( - "Expected and actual point to the same object: %p %#[1]v", - expected), msgAndArgs...) + "Expected and actual point to the same object: %p %s", + expected, truncatingFormat("%#v", expected)), msgAndArgs...) } return true } @@ -604,25 +604,26 @@ func samePointers(first, second interface{}) (same bool, ok bool) { // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { - return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), - fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) + return fmt.Sprintf("%T(%s)", expected, truncatingFormat("%#v", expected)), + fmt.Sprintf("%T(%s)", actual, truncatingFormat("%#v", actual)) } switch expected.(type) { case time.Duration: return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) } - return truncatingFormat(expected), truncatingFormat(actual) + return truncatingFormat("%#v", expected), truncatingFormat("%#v", actual) } // truncatingFormat formats the data and truncates it if it's too long. // // This helps keep formatted error messages lines from exceeding the // bufio.MaxScanTokenSize max line length that the go testing framework imposes. -func truncatingFormat(data interface{}) string { - value := fmt.Sprintf("%#v", data) - max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. - if len(value) > max { - value = value[0:max] + "<... truncated>" +func truncatingFormat(format string, data interface{}) string { + value := fmt.Sprintf(format, data) + // Give us space for two truncated objects and the surrounding sentence. + maxMessageSize := bufio.MaxScanTokenSize/2 - 100 + if len(value) > maxMessageSize { + value = value[0:maxMessageSize] + "<... truncated>" } return value } @@ -743,7 +744,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("Expected nil, but got: %s", truncatingFormat("%#v", object)), msgAndArgs...) } // isEmpty gets whether the specified object is considered empty or not. @@ -793,7 +794,7 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) + Fail(t, fmt.Sprintf("Should be empty, but was %s", truncatingFormat("%v", object)), msgAndArgs...) } return pass @@ -836,11 +837,11 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) } l, ok := getLen(object) if !ok { - return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", truncatingFormat("%v", object)), msgAndArgs...) } if l != length { - return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + return Fail(t, fmt.Sprintf("%q should have %d item(s), but has %d", truncatingFormat("%v", object), length, l), msgAndArgs...) } return true } @@ -889,7 +890,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ } if ObjectsAreEqual(expected, actual) { - return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -904,7 +905,7 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte } if ObjectsAreEqualValues(expected, actual) { - return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -964,10 +965,10 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true @@ -986,10 +987,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if found { - return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s should not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true @@ -1031,10 +1032,10 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok av := actualMap.MapIndex(k) if !av.IsValid() { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } if !ObjectsAreEqual(ev.Interface(), av.Interface()) { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } } @@ -1056,7 +1057,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...) } } @@ -1082,12 +1083,12 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) listKind := reflect.TypeOf(list).Kind() if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", list, listKind), msgAndArgs...) } subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", subset, subsetKind), msgAndArgs...) } if subsetKind == reflect.Map && listKind == reflect.Map { @@ -1106,7 +1107,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) } } - return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...) } subsetList := reflect.ValueOf(subset) @@ -1121,14 +1122,14 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { - return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { return true } } - return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...) } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified @@ -1343,9 +1344,15 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs . if !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } - panicErr, ok := panicValue.(error) - if !ok || panicErr.Error() != errString { - return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) + panicErr, isError := panicValue.(error) + if !isError || panicErr.Error() != errString { + msg := fmt.Sprintf("func %#v should panic with error message:\t%#v\n", f, errString) + if isError { + msg += fmt.Sprintf("\tError message:\t%#v\n", panicErr.Error()) + } + msg += fmt.Sprintf("\tPanic value:\t%#v\n", panicValue) + msg += fmt.Sprintf("\tPanic stack:\t%s\n", panickedStack) + return Fail(t, msg, msgAndArgs...) } return true @@ -1624,7 +1631,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m Errors */ -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoError(t, err) { @@ -1635,13 +1642,13 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + return Fail(t, fmt.Sprintf("Received unexpected error:\n%s", truncatingFormat("%+v", err)), msgAndArgs...) } return true } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Error(t, err) @@ -1656,7 +1663,7 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { return true } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -1674,13 +1681,13 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte if expected != actual { return Fail(t, fmt.Sprintf("Error message not equal:\n"+ "expected: %q\n"+ - "actual : %q", expected, actual), msgAndArgs...) + "actual : %s", expected, truncatingFormat("%q", actual)), msgAndArgs...) } return true } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContains(t, err, expectedErrorSubString) @@ -1694,7 +1701,7 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in actual := theError.Error() if !strings.Contains(actual, contains) { - return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("Error %s does not contain %#v", truncatingFormat("%#v", actual), contains), msgAndArgs...) } return true @@ -1760,7 +1767,7 @@ func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { h.Helper() } if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { - return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should be zero, but was %s", truncatingFormat("%v", i)), msgAndArgs...) } return true } @@ -1874,7 +1881,19 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// assert.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -2188,8 +2207,8 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ - "expected: %q\n"+ - "in chain: %s", expectedText, chain, + "expected: %s\n"+ + "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2211,8 +2230,8 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ - "found: %q\n"+ - "in chain: %s", expectedText, chain, + "found: %s\n"+ + "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2236,7 +2255,7 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{ return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ "expected: %s\n"+ - "in chain: %s", expectedType, chain, + "in chain: %s", expectedType, truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2254,7 +2273,7 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ "found: %s\n"+ - "in chain: %s", reflect.TypeOf(target).Elem().String(), chain, + "in chain: %s", reflect.TypeOf(target).Elem().String(), truncatingFormat("%s", chain), ), msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go index a0b953aa5..c111589c7 100644 --- a/vendor/github.com/stretchr/testify/assert/doc.go +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -40,8 +40,8 @@ // // # Assertions // -// Assertions allow you to easily write test code, and are global funcs in the `assert` package. -// All assertion functions take, as the first argument, the `*testing.T` object provided by the +// Assertions allow you to easily write test code, and are global funcs in the assert package. +// All assertion functions take, as the first argument, the [*testing.T] object provided by the // testing framework. This allows the assertion funcs to write the failings and other details to // the correct place. // diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/stretchr/testify/internal/difflib/LICENSE similarity index 95% rename from vendor/github.com/pmezard/go-difflib/LICENSE rename to vendor/github.com/stretchr/testify/internal/difflib/LICENSE index c67dad612..485be13c6 100644 --- a/vendor/github.com/pmezard/go-difflib/LICENSE +++ b/vendor/github.com/stretchr/testify/internal/difflib/LICENSE @@ -24,4 +24,4 @@ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/stretchr/testify/internal/difflib/difflib.go similarity index 77% rename from vendor/github.com/pmezard/go-difflib/difflib/difflib.go rename to vendor/github.com/stretchr/testify/internal/difflib/difflib.go index 003e99fad..9984599b4 100644 --- a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go +++ b/vendor/github.com/stretchr/testify/internal/difflib/difflib.go @@ -8,11 +8,14 @@ // // - unified_diff // -// - context_diff -// // Getting unified diffs was the main goal of the port. Keep in mind this code // is mostly suitable to output text differences in a human friendly way, there // are no guarantees generated diffs are consumable by patch(1). +// +// This package was adopted from [github.com/pmezard/go-difflib] which +// is no longer maintained. +// +// [github.com/pmezard/go-difflib]: https://github.com/pmezard/go-difflib package difflib import ( @@ -37,13 +40,6 @@ func max(a, b int) int { return b } -func calculateRatio(matches, length int) float64 { - if length > 0 { - return 2.0 * float64(matches) / float64(length) - } - return 1.0 -} - type Match struct { A int B int @@ -103,14 +99,6 @@ func NewMatcher(a, b []string) *SequenceMatcher { return &m } -func NewMatcherWithJunk(a, b []string, autoJunk bool, - isJunk func(string) bool) *SequenceMatcher { - - m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk} - m.SetSeqs(a, b) - return &m -} - // Set two sequences to be compared. func (m *SequenceMatcher) SetSeqs(a, b []string) { m.SetSeq1(a) @@ -199,12 +187,15 @@ func (m *SequenceMatcher) isBJunk(s string) bool { // If IsJunk is not defined: // // Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where -// alo <= i <= i+k <= ahi -// blo <= j <= j+k <= bhi +// +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// // and for all (i',j',k') meeting those conditions, -// k >= k' -// i <= i' -// and if i == i', j <= j' +// +// k >= k' +// i <= i' +// and if i == i', j <= j' // // In other words, of all maximal matching blocks, return one that // starts earliest in a, and of all those maximal matching blocks that @@ -451,66 +442,6 @@ func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { return groups } -// Return a measure of the sequences' similarity (float in [0,1]). -// -// Where T is the total number of elements in both sequences, and -// M is the number of matches, this is 2.0*M / T. -// Note that this is 1 if the sequences are identical, and 0 if -// they have nothing in common. -// -// .Ratio() is expensive to compute if you haven't already computed -// .GetMatchingBlocks() or .GetOpCodes(), in which case you may -// want to try .QuickRatio() or .RealQuickRation() first to get an -// upper bound. -func (m *SequenceMatcher) Ratio() float64 { - matches := 0 - for _, m := range m.GetMatchingBlocks() { - matches += m.Size - } - return calculateRatio(matches, len(m.a)+len(m.b)) -} - -// Return an upper bound on ratio() relatively quickly. -// -// This isn't defined beyond that it is an upper bound on .Ratio(), and -// is faster to compute. -func (m *SequenceMatcher) QuickRatio() float64 { - // viewing a and b as multisets, set matches to the cardinality - // of their intersection; this counts the number of matches - // without regard to order, so is clearly an upper bound - if m.fullBCount == nil { - m.fullBCount = map[string]int{} - for _, s := range m.b { - m.fullBCount[s] = m.fullBCount[s] + 1 - } - } - - // avail[x] is the number of times x appears in 'b' less the - // number of times we've seen it in 'a' so far ... kinda - avail := map[string]int{} - matches := 0 - for _, s := range m.a { - n, ok := avail[s] - if !ok { - n = m.fullBCount[s] - } - avail[s] = n - 1 - if n > 0 { - matches += 1 - } - } - return calculateRatio(matches, len(m.a)+len(m.b)) -} - -// Return an upper bound on ratio() very quickly. -// -// This isn't defined beyond that it is an upper bound on .Ratio(), and -// is faster to compute than either .Ratio() or .QuickRatio(). -func (m *SequenceMatcher) RealQuickRatio() float64 { - la, lb := len(m.a), len(m.b) - return calculateRatio(min(la, lb), la+lb) -} - // Convert range to the "ed" format func formatRangeUnified(start, stop int) string { // Per the diff spec at http://www.unix.org/single_unix_specification/ @@ -652,117 +583,6 @@ func formatRangeContext(start, stop int) string { return fmt.Sprintf("%d,%d", beginning, beginning+length-1) } -type ContextDiff UnifiedDiff - -// Compare two sequences of lines; generate the delta as a context diff. -// -// Context diffs are a compact way of showing line changes and a few -// lines of context. The number of context lines is set by diff.Context -// which defaults to three. -// -// By default, the diff control lines (those with *** or ---) are -// created with a trailing newline. -// -// For inputs that do not have trailing newlines, set the diff.Eol -// argument to "" so that the output will be uniformly newline free. -// -// The context diff format normally has a header for filenames and -// modification times. Any or all of these may be specified using -// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate. -// The modification times are normally expressed in the ISO 8601 format. -// If not specified, the strings default to blanks. -func WriteContextDiff(writer io.Writer, diff ContextDiff) error { - buf := bufio.NewWriter(writer) - defer buf.Flush() - var diffErr error - wf := func(format string, args ...interface{}) { - _, err := buf.WriteString(fmt.Sprintf(format, args...)) - if diffErr == nil && err != nil { - diffErr = err - } - } - ws := func(s string) { - _, err := buf.WriteString(s) - if diffErr == nil && err != nil { - diffErr = err - } - } - - if len(diff.Eol) == 0 { - diff.Eol = "\n" - } - - prefix := map[byte]string{ - 'i': "+ ", - 'd': "- ", - 'r': "! ", - 'e': " ", - } - - started := false - m := NewMatcher(diff.A, diff.B) - for _, g := range m.GetGroupedOpCodes(diff.Context) { - if !started { - started = true - fromDate := "" - if len(diff.FromDate) > 0 { - fromDate = "\t" + diff.FromDate - } - toDate := "" - if len(diff.ToDate) > 0 { - toDate = "\t" + diff.ToDate - } - if diff.FromFile != "" || diff.ToFile != "" { - wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) - wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) - } - } - - first, last := g[0], g[len(g)-1] - ws("***************" + diff.Eol) - - range1 := formatRangeContext(first.I1, last.I2) - wf("*** %s ****%s", range1, diff.Eol) - for _, c := range g { - if c.Tag == 'r' || c.Tag == 'd' { - for _, cc := range g { - if cc.Tag == 'i' { - continue - } - for _, line := range diff.A[cc.I1:cc.I2] { - ws(prefix[cc.Tag] + line) - } - } - break - } - } - - range2 := formatRangeContext(first.J1, last.J2) - wf("--- %s ----%s", range2, diff.Eol) - for _, c := range g { - if c.Tag == 'r' || c.Tag == 'i' { - for _, cc := range g { - if cc.Tag == 'd' { - continue - } - for _, line := range diff.B[cc.J1:cc.J2] { - ws(prefix[cc.Tag] + line) - } - } - break - } - } - } - return diffErr -} - -// Like WriteContextDiff but returns the diff a string. -func GetContextDiffString(diff ContextDiff) (string, error) { - w := &bytes.Buffer{} - err := WriteContextDiff(w, diff) - return string(w.Bytes()), err -} - // Split a string on "\n" while preserving them. The output can be used // as input for UnifiedDiff and ContextDiff structures. func SplitLines(s string) []string { diff --git a/vendor/github.com/stretchr/testify/internal/spew/LICENSE b/vendor/github.com/stretchr/testify/internal/spew/LICENSE new file mode 100644 index 000000000..bc52e96f2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/stretchr/testify/internal/spew/README.md b/vendor/github.com/stretchr/testify/internal/spew/README.md new file mode 100644 index 000000000..51a909e2e --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/README.md @@ -0,0 +1,12 @@ +go-spew +======= + +[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) + +Go-spew implements a deep pretty printer for Go data structures to aid in +debugging. A comprehensive suite of tests with 100% test coverage is provided +to ensure proper functionality. + +## License + +Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/vendor/github.com/stretchr/testify/internal/spew/bypass.go b/vendor/github.com/stretchr/testify/internal/spew/bypass.go new file mode 100644 index 000000000..70ddeaad3 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/bypass.go @@ -0,0 +1,146 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// Go versions prior to 1.4 are disabled because they use a different layout +// for interfaces which make the implementation of unsafeReflectValue more complex. +//go:build !js && !appengine && !safe && !disableunsafe && go1.4 +// +build !js,!appengine,!safe,!disableunsafe,go1.4 + +package spew + +import ( + "reflect" + "unsafe" +) + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = false + + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +type flag uintptr + +var ( + // flagRO indicates whether the value field of a reflect.Value + // is read-only. + flagRO flag + + // flagAddr indicates whether the address of the reflect.Value's + // value may be taken. + flagAddr flag +) + +// flagKindMask holds the bits that make up the kind +// part of the flags field. In all the supported versions, +// it is in the lower 5 bits. +const flagKindMask = flag(0x1f) + +// Different versions of Go have used different +// bit layouts for the flags type. This table +// records the known combinations. +var okFlags = []struct { + ro, addr flag +}{{ + // From Go 1.4 to 1.5 + ro: 1 << 5, + addr: 1 << 7, +}, { + // Up to Go tip. + ro: 1<<5 | 1<<6, + addr: 1 << 8, +}} + +var flagValOffset = func() uintptr { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + return field.Offset +}() + +// flagField returns a pointer to the flag field of a reflect.Value. +func flagField(v *reflect.Value) *flag { + return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) reflect.Value { + if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { + return v + } + flagFieldPtr := flagField(&v) + *flagFieldPtr &^= flagRO + *flagFieldPtr |= flagAddr + return v +} + +// Sanity checks against future reflect package changes +// to the type or semantics of the Value.flag field. +func init() { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { + panic("reflect.Value flag field has changed kind") + } + type t0 int + var t struct { + A t0 + // t0 will have flagEmbedRO set. + t0 + // a will have flagStickyRO set + a t0 + } + vA := reflect.ValueOf(t).FieldByName("A") + va := reflect.ValueOf(t).FieldByName("a") + vt0 := reflect.ValueOf(t).FieldByName("t0") + + // Infer flagRO from the difference between the flags + // for the (otherwise identical) fields in t. + flagPublic := *flagField(&vA) + flagWithRO := *flagField(&va) | *flagField(&vt0) + flagRO = flagPublic ^ flagWithRO + + // Infer flagAddr from the difference between a value + // taken from a pointer and not. + vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") + flagNoPtr := *flagField(&vA) + flagPtr := *flagField(&vPtrA) + flagAddr = flagNoPtr ^ flagPtr + + // Check that the inferred flags tally with one of the known versions. + for _, f := range okFlags { + if flagRO == f.ro && flagAddr == f.addr { + return + } + } + panic("reflect.Value read-only flag has changed semantics") +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go b/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go new file mode 100644 index 000000000..5e2d890d6 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go @@ -0,0 +1,39 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is running on Google App Engine, compiled by GopherJS, or +// "-tags safe" is added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +//go:build js || appengine || safe || disableunsafe || !go1.4 +// +build js appengine safe disableunsafe !go1.4 + +package spew + +import "reflect" + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = true +) + +// unsafeReflectValue typically converts the passed reflect.Value into a one +// that bypasses the typical safety restrictions preventing access to +// unaddressable and unexported data. However, doing this relies on access to +// the unsafe package. This is a stub version which simply returns the passed +// reflect.Value when the unsafe package is not available. +func unsafeReflectValue(v reflect.Value) reflect.Value { + return v +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/common.go b/vendor/github.com/stretchr/testify/internal/spew/common.go new file mode 100644 index 000000000..1be8ce945 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/common.go @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "reflect" + "sort" + "strconv" +) + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe, when it's available, + // to bypass these restrictions since this package does not mutate the + // values. + if !v.CanInterface() { + if UnsafeDisabled { + return false + } + + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { + v = unsafeReflectValue(v) + } + if v.CanAddr() { + v = v.Addr() + } + + // Is it an error or Stringer? + switch iface := v.Interface().(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } +} + +// valueSortLess returns whether the first value should sort before the second +// value. It is used by valueSorter.Less as part of the sort.Interface +// implementation. +func valueSortLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Bool: + return !a.Bool() && b.Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return a.Int() < b.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return a.Uint() < b.Uint() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.String: + return a.String() < b.String() + case reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Array: + // Compare the contents of both arrays. + l := a.Len() + for i := 0; i < l; i++ { + av := a.Index(i) + bv := b.Index(i) + if av.Interface() == bv.Interface() { + continue + } + return valueSortLess(av, bv) + } + } + return a.String() < b.String() +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] +} + +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { + if len(values) == 0 { + return + } + sort.Sort(newValuesSorter(values, cs)) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/config.go b/vendor/github.com/stretchr/testify/internal/spew/config.go new file mode 100644 index 000000000..161895fc6 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/config.go @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. As a result, this option relies on + // access to the unsafe package, so it will not have any effect when + // running in environments without access to the unsafe package such as + // Google App Engine or with the "safe" build tag specified. + DisablePointerMethods bool + + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) and types + // that support the error or Stringer interfaces (if methods are + // enabled) are supported, with other types sorted according to the + // reflect.Value.String() output which guarantees display stability. + SortKeys bool + + // SpewKeys specifies that, as a last resort attempt, map keys should + // be spewed to strings and sorted by those strings. This is only + // considered if SortKeys is true. + SpewKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/doc.go b/vendor/github.com/stretchr/testify/internal/spew/doc.go new file mode 100644 index 000000000..722e9aa79 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/doc.go @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + - Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + - A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +# Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +# Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + + - Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + - MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + - DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + - DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + - DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + - DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + + - ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + - SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. + + - SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +# Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +# Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +# Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +# Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +# Sample Formatter Output + +Double pointer to a uint8: + + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +# Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/vendor/github.com/stretchr/testify/internal/spew/dump.go b/vendor/github.com/stretchr/testify/internal/spew/dump.go new file mode 100644 index 000000000..8323041a4 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/dump.go @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound: + d.w.Write(nilAngleBytes) + + case cycleFound: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type + // to a byte slice. However, the reflect package won't + // give us an interface on certain things like + // unexported struct fields in order to enforce + // visibility rules. We use unsafe, when available, to + // bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + if !UnsafeDisabled { + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be + // type asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if !d.cs.DisableCapacities && valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys, d.cs) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/format.go b/vendor/github.com/stretchr/testify/internal/spew/format.go new file mode 100644 index 000000000..b04edb7d7 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/format.go @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound: + f.fs.Write(nilAngleBytes) + + case cycleFound: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys, f.cs) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/spew.go b/vendor/github.com/stretchr/testify/internal/spew/spew.go new file mode 100644 index 000000000..32c0e3388 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/spew.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go index efc89deff..7f4d28d5e 100644 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -11,11 +11,11 @@ import ( "sync" "time" - "github.com/davecgh/go-spew/spew" - "github.com/pmezard/go-difflib/difflib" "github.com/stretchr/objx" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/internal/difflib" + "github.com/stretchr/testify/internal/spew" ) // regex for GCCGO functions @@ -470,7 +470,7 @@ func callString(method string, arguments Arguments, includeArgumentValues bool) // Called tells the mock object that a method has been called, and gets an array // of arguments to return. Panics if the call is unexpected (i.e. not preceded by -// appropriate .On .Return() calls) +// appropriate [Mock.On] calls) // If Call.WaitFor is set, blocks until the channel is closed or receives a message. func (m *Mock) Called(arguments ...interface{}) Arguments { // get the calling function's name @@ -493,7 +493,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { // MethodCalled tells the mock object that the given method has been called, and gets // an array of arguments to return. Panics if the call is unexpected (i.e. not preceded -// by appropriate .On .Return() calls) +// by appropriate [Mock.On] calls) // If Call.WaitFor is set, blocks until the channel is closed or receives a message. func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { m.mutex.Lock() @@ -510,8 +510,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen // as the return arguments. This is because: // // a) this is a totally unexpected call to this method, - // b) the arguments are not what was expected, or - // c) the developer has forgotten to add an accompanying On...Return pair. + // b) the arguments are not what was expected closestCall, mismatch := m.findClosestCall(methodName, arguments...) m.mutex.Unlock() @@ -595,7 +594,7 @@ type assertExpectationiser interface { AssertExpectations(TestingT) bool } -// AssertExpectationsForObjects asserts that everything specified with On and Return +// AssertExpectationsForObjects asserts that everything specified with [Mock.On] // of the specified objects was in fact called as expected. // // Calls may have occurred in any order. @@ -604,11 +603,12 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { h.Helper() } for _, obj := range testObjects { - if m, ok := obj.(*Mock); ok { - t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") - obj = m + m, ok := obj.(assertExpectationiser) + if !ok { + t.Errorf("Invalid test object type %T. Expected reference to a mock.Mock, eg: 'AssertExpectationsForObjects(t, myMock)' or 'AssertExpectationsForObjects(t, &myMock.Mock)'", obj) + continue + } - m := obj.(assertExpectationiser) if !m.AssertExpectations(t) { t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) return false @@ -617,7 +617,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { return true } -// AssertExpectations asserts that everything specified with On and Return was +// AssertExpectations asserts that everything specified with [Mock.On] was // in fact called as expected. Calls may have occurred in any order. func (m *Mock) AssertExpectations(t TestingT) bool { if s, ok := t.(interface{ Skipped() bool }); ok && s.Skipped() { @@ -712,8 +712,8 @@ func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...inter return true } -// IsMethodCallable checking that the method can be called -// If the method was called more than `Repeatability` return false +// IsMethodCallable returns true if given methodName and arguments have an +// unsatisfied expected call registered in the Mock. func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -833,6 +833,10 @@ type IsTypeArgument struct { // For example: // // args.Assert(t, IsType(""), IsType(0)) +// +// Mock cannot match interface types because the contained type will be passed +// to both IsType and Mock.Called, for the zero value of all interfaces this +// will be type. func IsType(t interface{}) *IsTypeArgument { return &IsTypeArgument{t: reflect.TypeOf(t)} } @@ -1012,7 +1016,7 @@ func (args Arguments) Diff(objects []interface{}) (string, int) { actualT := reflect.TypeOf(actual) if actualT != expected.t { differences++ - output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt) + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, safeTypeName(expected.t), safeTypeName(actualT), actualFmt) } case *FunctionalOptionsArgument: var name string @@ -1141,6 +1145,15 @@ func (args Arguments) Bool(index int) bool { return s } +// safeTypeName returns the reflect.Type's name without causing a panic. +// If the provided reflect.Type is nil, it returns the placeholder string "" +func safeTypeName(t reflect.Type) string { + if t == nil { + return "" + } + return t.Name() +} + func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { t := reflect.TypeOf(v) k := t.Kind() diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go index c8e3f94a8..ee84cc479 100644 --- a/vendor/github.com/stretchr/testify/require/doc.go +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -1,4 +1,4 @@ -// Package require implements the same assertions as the `assert` package but +// Package require implements the same assertions as the assert package but // stops test execution when a test fails. // // # Example Usage @@ -21,8 +21,8 @@ // // # Assertions // -// The `require` package have same global functions as in the `assert` package, -// but instead of returning a boolean result they call `t.FailNow()`. +// The require package have same global functions as in the assert package, +// but instead of returning a boolean result they call [testing.T.FailNow]. // A consequence of this is that it must be called from the goroutine running // the test function, not from other goroutines created during the test. // diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index 2d02f9bce..652871f2e 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -180,7 +180,7 @@ func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...i t.FailNow() } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -195,7 +195,7 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte t.FailNow() } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -295,7 +295,7 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar t.FailNow() } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Error(t, err) @@ -333,8 +333,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int t.FailNow() } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContains(t, err, expectedErrorSubString) @@ -348,8 +348,8 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in t.FailNow() } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") @@ -387,7 +387,7 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface t.FailNow() } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Errorf(t, err, "error message %s", "formatted") @@ -429,7 +429,7 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t // time.Sleep(8*time.Second) // externalValue = true // }() -// require.EventuallyWithT(t, func(c *require.CollectT) { +// require.EventuallyWithT(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") @@ -457,10 +457,10 @@ func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitF // time.Sleep(8*time.Second) // externalValue = true // }() -// require.EventuallyWithTf(t, func(c *require.CollectT, "error message %s", "formatted") { +// require.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -671,8 +671,6 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // body that contains a string. // // require.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -687,8 +685,6 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s // body that contains a string. // // require.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -703,8 +699,6 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // body that does not contain a string. // // require.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -719,8 +713,6 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur // body that does not contain a string. // // require.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -734,8 +726,6 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPError asserts that a specified handler returns an error status code. // // require.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -749,8 +739,6 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPErrorf asserts that a specified handler returns an error status code. // // require.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -764,8 +752,6 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirect asserts that a specified handler returns a redirect status code. // // require.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -779,8 +765,6 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // require.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -794,8 +778,6 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCode asserts that a specified handler returns a specified status code. // // require.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) -// -// Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -809,8 +791,6 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url str // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // require.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -824,8 +804,6 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccess asserts that a specified handler returns a success status code. // // require.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -839,8 +817,6 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string // HTTPSuccessf asserts that a specified handler returns a success status code. // // require.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1385,12 +1361,11 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { t.FailNow() } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if require.NoError(t, err) { -// require.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// require.NoError(t, err) +// require.Equal(t, expectedObj, actualObj) func NoError(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1401,12 +1376,11 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) { t.FailNow() } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if require.NoErrorf(t, err, "error message %s", "formatted") { -// require.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// require.NoErrorf(t, err, "error message %s", "formatted") +// require.Equal(t, expectedObj, actualObj) func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1515,9 +1489,8 @@ func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg str // NotEmpty asserts that the specified object is NOT [Empty]. // -// if require.NotEmpty(t, obj) { -// require.Equal(t, "two", obj[1]) -// } +// require.NotEmpty(t, obj) +// require.Equal(t, "two", obj[1]) func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1530,9 +1503,8 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT [Empty]. // -// if require.NotEmptyf(t, obj, "error message %s", "formatted") { -// require.Equal(t, "two", obj[1]) -// } +// require.NotEmptyf(t, obj, "error message %s", "formatted") +// require.Equal(t, "two", obj[1]) func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -2135,7 +2107,19 @@ func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, t.FailNow() } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// require.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -2146,7 +2130,19 @@ func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ t.FailNow() } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// require.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl index 8b3283685..6a975501e 100644 --- a/vendor/github.com/stretchr/testify/require/require.go.tmpl +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -1,4 +1,4 @@ -{{ replace .Comment "assert." "require."}} +{{.CommentRequire}} func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index e6f7e9446..edac147ef 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -147,7 +147,7 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs Equal(a.t, expected, actual, msgAndArgs...) } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -159,7 +159,7 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... EqualError(a.t, theError, errString, msgAndArgs...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -241,7 +241,7 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string Equalf(a.t, expected, actual, msg, args...) } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) @@ -270,8 +270,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. ErrorAsf(a.t, err, target, msg, args...) } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) @@ -282,8 +282,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . ErrorContains(a.t, theError, contains, msgAndArgs...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") @@ -312,7 +312,7 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter ErrorIsf(a.t, err, target, msg, args...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") @@ -373,10 +373,10 @@ func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), w // time.Sleep(8*time.Second) // externalValue = true // }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -539,8 +539,6 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // body that contains a string. // // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -552,8 +550,6 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // body that contains a string. // // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -565,8 +561,6 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // body that does not contain a string. // // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -578,8 +572,6 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // body that does not contain a string. // // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -590,8 +582,6 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -602,8 +592,6 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -614,8 +602,6 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -626,8 +612,6 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -638,8 +622,6 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // // a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -650,8 +632,6 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -662,8 +642,6 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -674,8 +652,6 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // // a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1097,12 +1073,11 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) NoDirExistsf(a.t, path, msg, args...) } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// a.NoError(err) +// a.Equal(expectedObj, actualObj) func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1110,12 +1085,11 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { NoError(a.t, err, msgAndArgs...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// a.NoErrorf(err, "error message %s", "formatted") +// a.Equal(expectedObj, actualObj) func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1203,9 +1177,8 @@ func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg // NotEmpty asserts that the specified object is NOT [Empty]. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// a.NotEmpty(obj) +// a.Equal("two", obj[1]) func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1215,9 +1188,8 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT [Empty]. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// a.NotEmptyf(obj, "error message %s", "formatted") +// a.Equal("two", obj[1]) func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1691,7 +1663,19 @@ func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Ti WithinRangef(a.t, actual, start, end, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1699,7 +1683,19 @@ func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interf YAMLEq(a.t, expected, actual, msgAndArgs...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl index 54124df1d..b3b751de4 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -1,4 +1,4 @@ -{{.CommentWithoutT "a"}} +{{.CommentRequireWithoutT "a"}} func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { if h, ok := a.t.(tHelper); ok { h.Helper() } {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go index 6b7ce929e..375adb0a6 100644 --- a/vendor/github.com/stretchr/testify/require/requirements.go +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -12,18 +12,18 @@ type tHelper = interface { // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. -type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) +type ComparisonAssertionFunc = func(TestingT, interface{}, interface{}, ...interface{}) // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. -type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) +type ValueAssertionFunc = func(TestingT, interface{}, ...interface{}) // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...interface{}) +type BoolAssertionFunc = func(TestingT, bool, ...interface{}) // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...interface{}) +type ErrorAssertionFunc = func(TestingT, error, ...interface{}) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/modules.txt b/vendor/modules.txt index a049ce69a..b7301f1da 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -556,8 +556,8 @@ github.com/klauspost/cpuid/v2 # github.com/lestrrat-go/blackmagic v1.0.4 ## explicit; go 1.23 github.com/lestrrat-go/blackmagic -# github.com/lestrrat-go/dsig v1.3.0 -## explicit; go 1.23.0 +# github.com/lestrrat-go/dsig v1.4.0 +## explicit; go 1.25.0 github.com/lestrrat-go/dsig github.com/lestrrat-go/dsig/internal/ecutil # github.com/lestrrat-go/httpcc v1.0.1 @@ -569,7 +569,7 @@ github.com/lestrrat-go/httprc/v3 github.com/lestrrat-go/httprc/v3/errsink github.com/lestrrat-go/httprc/v3/proxysink github.com/lestrrat-go/httprc/v3/tracesink -# github.com/lestrrat-go/jwx/v4 v4.2.0 +# github.com/lestrrat-go/jwx/v4 v4.4.0 ## explicit; go 1.26.0 github.com/lestrrat-go/jwx/v4 github.com/lestrrat-go/jwx/v4/cert @@ -740,7 +740,6 @@ github.com/planetscale/vtprotobuf/types/known/timestamppb github.com/planetscale/vtprotobuf/types/known/wrapperspb # github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 ## explicit -github.com/pmezard/go-difflib/difflib # github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 ## explicit; go 1.14 github.com/power-devops/perfstat @@ -895,10 +894,12 @@ github.com/spf13/viper/internal/features # github.com/stretchr/objx v0.5.3 ## explicit; go 1.20 github.com/stretchr/objx -# github.com/stretchr/testify v1.11.1 +# github.com/stretchr/testify v1.12.0 ## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/assert/yaml +github.com/stretchr/testify/internal/difflib +github.com/stretchr/testify/internal/spew github.com/stretchr/testify/mock github.com/stretchr/testify/require # github.com/subosito/gotenv v1.6.0