diff --git a/README.md b/README.md index f2b66e5..4427d42 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Expect(req).To(be_http.Request( )), // Matching the HTTP method - be_http.HavingMethod(http.MethodPost), + be_http.POST() // Matching request's context be_http.HavingCtx(be_ctx.Ctx( @@ -92,7 +92,7 @@ Expect(req).To(be_http.Request( be_strings.Var("jwt", be_jwt.Token( be_jwt.Valid(), - be_jwt.HavingClaims("name", "John Doe"), + be_jwt.HavingClaim("name", "John Doe"), ), ), ), @@ -109,7 +109,7 @@ Expect(req).To(be_http.Request( #### Core matchers: -`Always`, `Never`, `All`, `Any`, `Eq`, `Not`, `HaveLength` +`Always`, `Never`, `All`, `Any`, `Eq`, `Not`, `HaveLength`, `Dive`, `DiveAny`, `DiveFirst` ### be_reflected @@ -162,7 +162,11 @@ types.
[See detailed docs](be_reflected/README.md) #### Time Matchers -`LaterThan`, `LaterThanEqual`, `EarlierThan`, `EarlierThanEqual`, `Approx`, `Eq`, `SameExactSecond`, `SameExactMinute`, `SameExactHour`, `SameTimezone`, `SameOffset`, `IsDST`, `SameExactDay`, `SameExactWeekday`, `SameWeek`, `SameMonth`, `SameYear` +`LaterThan`, `LaterThanEqual`, `EarlierThan`, `EarlierThanEqual`, `Eq`, `Approx`,
+`SameExactMilli`, `SameExactSecond`, `SameExactMinute`, `SameExactHour`,
+`SameExactDay`, `SameExactWeekday`, `SameExactWeek`, `SameExactMonth`,
+`SameSecond`, `SameMinute`, `SameHour`, `SameDay`, `SameYearDay`,
+`SameWeek`, `SameMonth`, `SameYear`, `SameTimzone`, `SameOffset`, `IsDST` ### be_jwt @@ -176,7 +180,7 @@ golang [jwt implementation](https://github.com/golang-jwt/jwt/v5).
[See deta #### Matchers on JWT: -`Token`, `Valid`, `HavingClaims`, `HavingMethodAlg`, `SignedVia` +`Token`, `Valid`, `HavingClaims`, `HavingClaim`, `HavingMethodAlg`, `SignedVia` ### be_url @@ -212,7 +216,9 @@ golang [jwt implementation](https://github.com/golang-jwt/jwt/v5).
[See deta #### Matchers on HTTP: -`Request`, `HavingMethod`, `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `HavingURL`, `HavingBody`, `HavingHost`, `HavingProto`, `HavingHeader` +`Request`, `HavingMethod`,
+`GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `CONNECT`, `TRACE`,
+`HavingURL`, `HavingBody`, `HavingHost`, `HavingProto`, `HavingHeader`, `HavingHeaders` # Contributing diff --git a/be_http/README.md b/be_http/README.md index 007aec0..ea00113 100644 --- a/be_http/README.md +++ b/be_http/README.md @@ -2,26 +2,25 @@ -- import "github.com/expectto/be/be_http" -Package be_http provides matchers for url.Request todo: more detailed +Package be_http provides matchers for url.Request TODO: more detailed documentation here is required ## Usage -#### func DELETE - -```go -func DELETE() types.BeMatcher -``` -DELETE returns a matcher that succeeds if the actual *http.Request has a method -"DELETE". - -#### func GET - ```go -func GET() types.BeMatcher +var ( + GET = func() types.BeMatcher { return HavingMethod(http.MethodGet) } + HEAD = func() types.BeMatcher { return HavingMethod(http.MethodHead) } + POST = func() types.BeMatcher { return HavingMethod(http.MethodPost) } + PUT = func() types.BeMatcher { return HavingMethod(http.MethodPut) } + PATCH = func() types.BeMatcher { return HavingMethod(http.MethodPatch) } + DELETE = func() types.BeMatcher { return HavingMethod(http.MethodDelete) } + OPTIONS = func() types.BeMatcher { return HavingMethod(http.MethodOptions) } + CONNECT = func() types.BeMatcher { return HavingMethod(http.MethodConnect) } + TRACE = func() types.BeMatcher { return HavingMethod(http.MethodTrace) } +) ``` -GET returns a matcher that succeeds if the actual *http.Request has a method -"GET". +HavingMethod: Syntactic sugar #### func HavingBody @@ -37,16 +36,39 @@ after matching. ```go func HavingHeader(key string, args ...any) types.BeMatcher ``` -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]` (3) if len(args) == 1 && args[0] is not stringish, it is considered to -be matcher for header's value Examples: - HavingHeader("X-Header") matches -request with non-empty X-Header header - HavingHeader("X-Header", "X-Value") -matches request with X-Header: X-Value - HavingHeader("X-Header", -HavePrefix("Bearer ")) matchers request with header(X-Header)'s value matching -given HavePrefix matcher - todo: support multiple header values todo: fixme I'm -ugly for now +HavingHeader matches requests that have header with a given key. Key is a string +key for a header, args can be nil or len(args)==1. Note: Golang's http.Header is +`map[string][]string`, and matching is done on the FIRST value of the header in +case if you have multiple-valued header that needs to be matched, use +HavingHeaders() instead + +These are scenarios that can be handled here: (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]` (3) if +len(args) == 1 && args[0] is not stringish, it is considered to be matcher for +header's value Examples: - HavingHeader("X-Header") matches request with +non-empty X-Header header - HavingHeader("X-Header", "X-Value") matches request +with X-Header: X-Value - HavingHeader("X-Header", HavePrefix("Bearer ")) +matchers request with header(X-Header)'s value matching given HavePrefix matcher + +#### func HavingHeaders + +```go +func HavingHeaders(key string, args ...any) types.BeMatcher +``` +HavingHeaders matches requests that have header with a given key. Key is a +string key for a header, args can be nil or len(args)==1. Note: Matching is done +on the list of header values. In case if you have single-valued header that +needs to be matched, use HavingHeader() instead + +These are scenarios that can be handled here: (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]` (3) if +len(args) == 1 && args[0] is not stringish, it is considered to be matcher for +header's value Examples: - HavingHeader("X-Header") matches request with +non-empty X-Header header - HavingHeader("X-Header", "X-Value") matches request +with X-Header: X-Value - HavingHeader("X-Header", Dive(HavePrefix("Foo "))) +matchers request with multiple X-Header values, each of them having Foo prefix #### func HavingHost @@ -80,38 +102,6 @@ func HavingURL(args ...any) types.BeMatcher HavingURL succeeds if the actual value is a *http.Request and its URL matches the provided arguments. -#### func OPTIONS - -```go -func OPTIONS() types.BeMatcher -``` -OPTIONS returns a matcher that succeeds if the actual *http.Request has a method -"OPTIONS". - -#### func PATCH - -```go -func PATCH() types.BeMatcher -``` -PATCH returns a matcher that succeeds if the actual *http.Request has a method -"PATCH". - -#### func POST - -```go -func POST() types.BeMatcher -``` -POST returns a matcher that succeeds if the actual *http.Request has a method -"POST". - -#### func PUT - -```go -func PUT() types.BeMatcher -``` -PUT returns a matcher that succeeds if the actual *http.Request has a method -"PUT". - #### func Request ```go diff --git a/be_time/matchers_time.go b/be_time/matchers_time.go index 7875f37..db13782 100644 --- a/be_time/matchers_time.go +++ b/be_time/matchers_time.go @@ -99,42 +99,42 @@ func SameExactDay(compareTo time.Time) types.BeMatcher { })) } -// SameExactWeek succeeds if the actual time falls within the same ISO week as the specified time `compareTo`. -func SameExactWeek(compareTo time.Time) types.BeMatcher { +// SameExactWeekday succeeds if the weekday component of the actual time is equal to the weekday component +// of the specified time `compareTo`. +func SameExactWeekday(compareTo time.Time) types.BeMatcher { return Psi(gcustom.MakeMatcher(func(actual any) (bool, error) { if !cast.IsTime(actual) { return false, fmt.Errorf("invalid time type") } actualTime := cast.AsTime(actual) - compareToYear, compareToWeek := compareTo.ISOWeek() - actualYear, actualWeek := actualTime.ISOWeek() - return compareToYear == actualYear && compareToWeek == actualWeek, nil + return compareTo.Weekday() == actualTime.Weekday(), nil })) } -// SameExactMonth succeeds if the actual time falls within the same month as the specified time `compareTo`. -func SameExactMonth(compareTo time.Time) types.BeMatcher { +// SameExactWeek succeeds if the actual time falls within the same ISO week as the specified time `compareTo`. +func SameExactWeek(compareTo time.Time) types.BeMatcher { return Psi(gcustom.MakeMatcher(func(actual any) (bool, error) { if !cast.IsTime(actual) { return false, fmt.Errorf("invalid time type") } actualTime := cast.AsTime(actual) - return compareTo.Year() == actualTime.Year() && compareTo.Month() == actualTime.Month(), nil + compareToYear, compareToWeek := compareTo.ISOWeek() + actualYear, actualWeek := actualTime.ISOWeek() + return compareToYear == actualYear && compareToWeek == actualWeek, nil })) } -// SameExactWeekday succeeds if the weekday component of the actual time is equal to the weekday component -// of the specified time `compareTo`. -func SameExactWeekday(compareTo time.Time) types.BeMatcher { +// SameExactMonth succeeds if the actual time falls within the same month as the specified time `compareTo`. +func SameExactMonth(compareTo time.Time) types.BeMatcher { return Psi(gcustom.MakeMatcher(func(actual any) (bool, error) { if !cast.IsTime(actual) { return false, fmt.Errorf("invalid time type") } actualTime := cast.AsTime(actual) - return compareTo.Weekday() == actualTime.Weekday(), nil + return compareTo.Year() == actualTime.Year() && compareTo.Month() == actualTime.Month(), nil })) }