Skip to content

Commit

Permalink
Minor updates: small fixes + more comments for documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
expectto committed Jan 21, 2024
1 parent 837eafe commit 10ee84b
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 75 deletions.
13 changes: 10 additions & 3 deletions be_ctx/matchers_ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,30 @@ import (
"github.com/expectto/be/types"
)

// Ctx succeeds if the actual value is a context.Context.
// If no arguments are provided, it matches any context.Context.
// Otherwise, it uses the Psi matcher to match the provided arguments against the actual context's values.
func Ctx(args ...any) types.BeMatcher {
if len(args) == 0 {
return psi_matchers.NewCtxMatcher()
}

// not sure about this:
// todo: weak solution, fixme
return psi.Psi(args...)
}

func CtxWithValue(key string, vArg ...any) types.BeMatcher {
return psi_matchers.NewCtxValueMatcher(key, vArg...)
// CtxWithValue succeeds if the actual value is a context.Context and contains a key-value pair
// where the key matches the provided key and the value matches the provided arguments using any other matchers.
func CtxWithValue(key any, vs ...any) types.BeMatcher {
return psi_matchers.NewCtxValueMatcher(key, vs...)
}

// CtxWithDeadline succeeds if the actual value is a context.Context and its deadline matches the provided deadline.
func CtxWithDeadline(deadline any) types.BeMatcher {
return psi_matchers.NewCtxDeadlineMatcher(deadline)
}

// CtxWithError succeeds if the actual value is a context.Context and its error matches the provided error value.
func CtxWithError(err any) types.BeMatcher {
return psi_matchers.NewCtxErrMatcher(err)
}
9 changes: 5 additions & 4 deletions be_ctx/matchers_ctx_examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ var _ = Describe("MatchersCtx", func() {
})

It("should match a ctx with a value", func() {
ctx := context.WithValue(ctx, "foo", "bar")
type CtxKey string
ctx := context.WithValue(ctx, CtxKey("foo"), "bar")
// just by key
Expect(ctx).To(be_ctx.CtxWithValue("foo"))
Expect(ctx).To(be_ctx.CtxWithValue(CtxKey("foo")))
// key + value directly
Expect(ctx).To(be_ctx.CtxWithValue("foo", "bar"))
Expect(ctx).To(be_ctx.CtxWithValue(CtxKey("foo"), "bar"))
// key + value via matcher
Expect(ctx).To(be_ctx.CtxWithValue("foo", HavePrefix("ba")))
Expect(ctx).To(be_ctx.CtxWithValue(CtxKey("foo"), HavePrefix("ba")))
})

It("should not match when a string given instead of ctx", func() {
Expand Down
58 changes: 46 additions & 12 deletions be_http/matchers_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import (
"net/http"
)

// Request matches an actual value to be a valid *http.Request corresponding to given inputs.
// Possible inputs:
// 1. Nil args -> so actual value MUST be any valid *http.Request.
// 2. Single arg <string>. Actual value MUST be a *http.Request, whose .URL.String() is compared against args[0].
// 3. List of Omega/Gomock/Psi matchers, that are applied to *http.Request object.
// - Supports matching http.Request properties like method, URL, body, host, proto, and headers.
// - Additional arguments can be used for matching specific headers, e.g., WithHeader("Content-Type", "application/json").
func Request(args ...any) types.BeMatcher {
if len(args) == 0 {
return psi_matchers.NewReqPropertyMatcher("", "", nil)
Expand All @@ -29,6 +36,7 @@ func Request(args ...any) types.BeMatcher {
return Psi(args...)
}

// HavingMethod succeeds if the actual value is a *http.Request and its HTTP method matches the provided arguments.
func HavingMethod(args ...any) types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingMethod", "method",
Expand All @@ -37,23 +45,37 @@ func HavingMethod(args ...any) types.BeMatcher {
)
}

// GET returns a matcher that succeeds if the actual *http.Request has a method "GET".
func GET() types.BeMatcher {
return HavingMethod(http.MethodGet)
}

// POST returns a matcher that succeeds if the actual *http.Request has a method "POST".
func POST() types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingMethod", "method",
func(req *http.Request) any { return req.Method },
"POST",
)
return HavingMethod(http.MethodPost)
}
func GET() types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingMethod", "method",
func(req *http.Request) any { return req.Method },
"GET",
)

// PUT returns a matcher that succeeds if the actual *http.Request has a method "PUT".
func PUT() types.BeMatcher {
return HavingMethod(http.MethodPut)
}

// PATCH returns a matcher that succeeds if the actual *http.Request has a method "PATCH".
func PATCH() types.BeMatcher {
return HavingMethod(http.MethodPatch)
}

// todo syntax sugar for specific http methods
// DELETE returns a matcher that succeeds if the actual *http.Request has a method "DELETE".
func DELETE() types.BeMatcher {
return HavingMethod(http.MethodDelete)
}

// OPTIONS returns a matcher that succeeds if the actual *http.Request has a method "OPTIONS".
func OPTIONS() types.BeMatcher {
return HavingMethod(http.MethodOptions)
}

// HavingURL succeeds if the actual value is a *http.Request and its URL matches the provided arguments.
func HavingURL(args ...any) types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingURL", "url",
Expand All @@ -62,6 +84,8 @@ func HavingURL(args ...any) types.BeMatcher {
)
}

// HavingBody succeeds if the actual value is a *http.Request and its body matches the provided arguments.
// Note: The body is not re-streamed, so it's not available after matching.
func HavingBody(args ...any) types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingBody", "body",
Expand All @@ -71,6 +95,7 @@ func HavingBody(args ...any) types.BeMatcher {
)
}

// HavingHost succeeds if the actual value is a *http.Request and its Host matches the provided arguments.
func HavingHost(args ...any) types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingHost", "host",
Expand All @@ -79,6 +104,15 @@ func HavingHost(args ...any) types.BeMatcher {
)
}

// HavingProto succeeds if the actual value is a *http.Request and its Proto matches the provided arguments.
func HavingProto(args ...any) types.BeMatcher {
return psi_matchers.NewReqPropertyMatcher(
"HavingProto", "proto",
func(req *http.Request) any { return req.Proto },
args...,
)
}

// HavingHeader matches requests that have header with a given key.
// (1) If no args are given, it simply matches a request with existed header by key.
// (2) If len(args) == 1 && args[0] is a stringish, it matches a request with header `Key: Args[0]`
Expand Down
20 changes: 12 additions & 8 deletions be_jwt/matchers_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func Token(args ...any) types.BeMatcher {
return Psi(args...)
}

// Valid checks if the jwt.Token is valid.
// Valid succeeds if the actual value is a JWT token and it's valid
func Valid() types.BeMatcher {
return psi_matchers.NewJwtTokenMatcher(
"Valid",
Expand All @@ -83,7 +83,7 @@ func Valid() types.BeMatcher {
)
}

// HavingClaims checks if the jwt.Token matches given claims.
// HavingClaims succeeds if the actual value is a JWT token and its claims match the provided value or matchers.
func HavingClaims(args ...any) types.BeMatcher {
return psi_matchers.NewJwtTokenMatcher(
"Claims",
Expand All @@ -92,7 +92,7 @@ func HavingClaims(args ...any) types.BeMatcher {
)
}

// HavingMethodAlg checks if the jwt.Token has a method and algorithm matching given arguments.
// HavingMethodAlg succeeds if the actual value is a JWT token and its method algorithm match the provided value or matchers.
func HavingMethodAlg(args ...any) types.BeMatcher {
return psi_matchers.NewJwtTokenMatcher(
"Method.Alg()",
Expand All @@ -101,11 +101,15 @@ func HavingMethodAlg(args ...any) types.BeMatcher {
)
}

// SignedVia matches a valid & signed token (with a given secret).
// Token(TransformSignedJwtFromString(secret), Valid()) is the same as
// Token(TransformJwtFromString, SignedVia(secret)).
// It's useful when you already have matching against a secret-less token,
// and need the secret only for one specific matching.
// SignedVia succeeds if the actual value is a valid and signed JWT token,
// verified using the specified secret key.
// It's intended for matching against a secret-less token
// and applying the secret only for this specific matching.
//
// Example:
//
// Token(TransformJwtFromString, SignedVia(secret)) // works similar to:
// Token(TransformSignedJwtFromString(secret), Valid())
func SignedVia(secret string) types.BeMatcher {
return psi_matchers.NewJwtTokenMatcher(
"Method.Verify()",
Expand Down
11 changes: 4 additions & 7 deletions be_math/matchers_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ func LessThanEqual(arg any) types.BeMatcher {
return Psi(gomega.BeNumerically("<=", arg))
}

// ApproxEqual succeeds if actual is numerically approximately equal to the passed-in value within the specified threshold.
func ApproxEqual(compareTo, threshold any) types.BeMatcher {
// Approx succeeds if actual is numerically approximately equal to the passed-in value within the specified threshold.
func Approx(compareTo, threshold any) types.BeMatcher {
return Psi(gomega.BeNumerically("~", compareTo, threshold))
}

// InRange succeeds if actual is numerically within the specified range.
// The range is defined by the 'from' and 'until' values, and inclusivity is determined
// by the 'fromInclusive' and 'untilInclusive' flags.
func InRange(from any, fromInclusive bool, until any, untilInclusive bool) types.BeMatcher {
group := make([]types.BeMatcher, 2, 2)
group := make([]types.BeMatcher, 2)
if fromInclusive {
group[0] = Gte(from)
} else {
Expand Down Expand Up @@ -82,7 +82,7 @@ func Positive() types.BeMatcher { return GreaterThan(0.0) }

// Zero succeeds if actual is numerically approximately equal to zero.
// Any type of int/float will work for comparison.
func Zero() types.BeMatcher { return ApproxEqual(0, 0) }
func Zero() types.BeMatcher { return Approx(0, 0) }

// Integral succeeds if actual is an integral float, meaning it has zero decimal places.
// This matcher checks if the numeric value has no fractional component.
Expand Down Expand Up @@ -113,6 +113,3 @@ func Lt(arg any) types.BeMatcher { return LessThan(arg) }

// Lte is an alias for LessThanEqual, succeeding if actual is numerically less than or equal to the passed-in value.
func Lte(arg any) types.BeMatcher { return LessThanEqual(arg) }

// Approx is an alias for ApproxEqual, succeeding if actual is numerically approximately equal to the passed-in value within the specified threshold.
func Approx(c, t any) types.BeMatcher { return ApproxEqual(c, t) }
Loading

0 comments on commit 10ee84b

Please sign in to comment.