Skip to content

Commit

Permalink
initial (working) scaffold for be_struct.HavingField matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
amberpixels committed Sep 5, 2024
1 parent 0409e18 commit fce45c0
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 40 deletions.
2 changes: 1 addition & 1 deletion be_ctx/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_ctx
--
import "github.com/expectto/be/be_ctx"
import "."

Package be_ctx provides Be matchers on context.Context

Expand Down
2 changes: 1 addition & 1 deletion be_http/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_http
--
import "github.com/expectto/be/be_http"
import "."

Package be_http provides matchers for url.Request TODO: more detailed
documentation here is required
Expand Down
2 changes: 1 addition & 1 deletion be_json/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_json
--
import "github.com/expectto/be/be_json"
import "."

Package be_json provides Be matchers for expressive assertions on JSON TODO:
more detailed explanation what is considered to be JSON here
Expand Down
2 changes: 1 addition & 1 deletion be_jwt/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_jwt
--
import "github.com/expectto/be/be_jwt"
import "."

Package be_jwt provides Be matchers for handling JSON Web Tokens (JWT). It
includes matchers for transforming and validating JWT tokens. Matchers
Expand Down
2 changes: 1 addition & 1 deletion be_math/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_math
--
import "github.com/expectto/be/be_math"
import "."

Package be_math provides Be matchers for mathematical operations

Expand Down
2 changes: 1 addition & 1 deletion be_reflected/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_reflected
--
import "github.com/expectto/be/be_reflected"
import "."

Package be_reflected provides Be matchers that use reflection, enabling
expressive assertions on values' reflect kinds and types. It consists of several
Expand Down
45 changes: 14 additions & 31 deletions be_string/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# be_string
--
import "github.com/expectto/be/be_string"
import "."

Package be_string provides Be matchers for string-related assertions.

## Usage

```go
var V = psi_matchers.V
```

#### func ContainingCharacters

```go
Expand Down Expand Up @@ -58,17 +62,17 @@ SetStringFormat method).
#### func MatchTemplate

```go
func MatchTemplate(template string, vars ...*V) types.BeMatcher
func MatchTemplate(template string, values ...*psi_matchers.Value) types.BeMatcher
```
MatchTemplate succeeds if actual matches given template pattern. Provided
template must have `{{Field}}` placeholders. Each distinct placeholder from
template requires a var to be passed in list of `vars`. Var can be a raw value
or a matcher
template requires a var to be passed in list of `vars`. Value (V) can be a raw
value or a matcher
E.g.
Expect(someString).To(be_string.MatchTemplate("Hello {{Name}}. Your number is {{Number}}", be_string.Var("Name", "John"), be_string.Var("Number", 3)))
Expect(someString).To(be_string.MatchTemplate("Hello {{Name}}. Good bye, {{Name}}.", be_string.Var("Name", be_string.Titled()))
Expect(someString).To(be_string.MatchTemplate("Hello {{Name}}. Your number is {{Number}}", be_string.V("Name", "John"), be_string.V("Number", 3)))
Expect(someString).To(be_string.MatchTemplate("Hello {{Name}}. Good bye, {{Name}}.", be_string.V("Name", be_string.Titled()))
#### func MatchWildcard
Expand All @@ -92,7 +96,10 @@ string-like value (can be adjusted via SetStringFormat method).
func Only(option StringOption) types.BeMatcher
```
Only succeeds if actual is a string containing only characters described by
given options Only() defaults to empty string matching
given options Only() defaults to empty string matching Only(Alpha|Numeric)
succeeds if string contains only from alphabetic and numeric characters
Available options are: Alpha, Numeric, Whitespace, Dots, Punctuation,
SpecialCharacters TODO: special-characters are not supported yet

#### func Titled

Expand All @@ -119,27 +126,3 @@ func ValidEmail() types.BeMatcher
```
ValidEmail succeeds if actual is a valid email. Actual must be a string-like
value (can be adjusted via SetStringFormat method).

#### func ValidateStringOption

```go
func ValidateStringOption(opt StringOption, r rune) bool
```

#### type V

```go
type V struct {
Name string
Matcher types.BeMatcher
}
```


#### func Var

```go
func Var(name string, matching any) *V
```
Var creates a var used for replacing placeholders for templates in
`MatchTemplate`
20 changes: 20 additions & 0 deletions be_struct/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# be_struct
--
import "."


## Usage

#### func HavingField

```go
func HavingField[StructT any](fieldName string, expectedValue ...any) types.BeMatcher
```
HavingField succeeds if the actual value is a struct and it has a field with the
given name. If an expected value is provided, it also succeeds if the actual
value's field has the same value.

Example:

Expect(result).To(be_structs.HavingField[TestStruct]("Field1", "hello1"))
Expect(result).To(be_structs.HavingField[TestStruct]("Field2"))
13 changes: 13 additions & 0 deletions be_struct/be_structs_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package be_struct_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestBeStructs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "BeStructs Suite")
}
37 changes: 37 additions & 0 deletions be_struct/be_structs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package be_struct_test

import (
"github.com/expectto/be/be_struct"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("BeStructs", func() {
It("should match a struct field", func() {
type TestStruct struct {
Field1 string
Field2 int
}

var result = TestStruct{
Field1: "hello1",
}

Expect(result).To(
And(
be_struct.HavingField[TestStruct]("Field1", "hello1"),
be_struct.HavingField[TestStruct]("Field2"), // just ensure it exists
))

Expect(result).NotTo(
be_struct.HavingField[TestStruct]("Field3"),
)

type WrongStruct struct {
Field1 string
}
Expect(result).NotTo(
be_struct.HavingField[WrongStruct]("Field1"),
)
})
})
61 changes: 61 additions & 0 deletions be_struct/matchers_struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package be_struct

import (
"errors"
"fmt"
"reflect"

. "github.com/expectto/be/internal/psi"
"github.com/expectto/be/types"
"github.com/onsi/gomega/gcustom"
)

// HavingField succeeds if the actual value is a struct and it has a field with the given name.
// If an expected value is provided, it also succeeds if the actual value's field has the same value.
//
// Example:
//
// Expect(result).To(be_structs.HavingField[TestStruct]("Field1", "hello1"))
// Expect(result).To(be_structs.HavingField[TestStruct]("Field2"))
func HavingField[StructT any](fieldName string, expectedValue ...any) types.BeMatcher {
message := "have field " + fieldName
if len(expectedValue) > 0 {
message += fmt.Sprintf(" with value\n\t<%T>: %v", expectedValue[0], expectedValue[0])
}

structType := reflect.TypeFor[StructT]()

return Psi(gcustom.MakeMatcher(func(actual any) (bool, error) {
val := reflect.ValueOf(actual)

// Dereference if it's a pointer to a struct
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return false, errors.New("actual value is not a struct")
}
if val.Type() != structType {
// TODO: it doesn't work
message = fmt.Sprintf("be type of %s", structType.String())
return false, nil
}

// Check if the field exists
field := val.FieldByName(fieldName)
if !field.IsValid() {
return false, nil
}

// If an expected value is provided, compare the field's value with it
if len(expectedValue) > 0 {
expected := reflect.ValueOf(expectedValue[0])
if !reflect.DeepEqual(field.Interface(), expected.Interface()) {
return false, nil
}
}

// If no value to compare, return true if the field exists
return true, nil
}), message)
}
38 changes: 37 additions & 1 deletion be_time/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_time
--
import "github.com/expectto/be/be_time"
import "."

Package be_time provides Be matchers on time.Time

Expand All @@ -14,6 +14,12 @@ func Approx(compareTo time.Time, threshold time.Duration) types.BeMatcher
Approx succeeds if actual time is approximately equal to the specified time
`compareTo` within the given time duration threshold.

#### func Day

```go
func Day(v int) types.BeMatcher
```

#### func EarlierThan

```go
Expand Down Expand Up @@ -60,6 +66,12 @@ func LaterThanEqual(compareTo time.Time) types.BeMatcher
LaterThanEqual succeeds if actual time is later than or equal to the specified
time `compareTo`.

#### func Month

```go
func Month(monthCompareTo time.Month) types.BeMatcher
```

#### func SameDay

```go
Expand Down Expand Up @@ -212,3 +224,27 @@ func SameYearDay(compareTo time.Time) types.BeMatcher
SameYearDay checks if the .YearDay() component of the actual time matches the
.YearDay() component of the specified time `compareTo`. It only verifies the day
[1..365], disregarding the year.

#### func Unix

```go
func Unix(v int64) types.BeMatcher
```

#### func Weekday

```go
func Weekday(v time.Weekday) types.BeMatcher
```

#### func Year

```go
func Year(v int) types.BeMatcher
```

#### func YearDay

```go
func YearDay(v int) types.BeMatcher
```
2 changes: 1 addition & 1 deletion be_url/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be_url
--
import "github.com/expectto/be/be_url"
import "."

Package be_url provides Be matchers on url.URL

Expand Down
14 changes: 13 additions & 1 deletion core-be-matchers.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# be
--
import "github.com/expectto/be"
import "."


## Usage
Expand All @@ -15,6 +15,11 @@ var HttpRequest = be_http.Request
```
HttpRequest is an alias for be_http.Request matcher

```go
var JSON = be_json.Matcher
```
JSON is an alias for be_json.JSON matcher

```go
var JwtToken = be_jwt.Token
```
Expand Down Expand Up @@ -74,6 +79,13 @@ func DiveFirst(matcher any) types.BeMatcher
```
DiveFirst applies the given matcher to the first element of the given slice

#### func DiveNth

```go
func DiveNth(n int, matcher any) types.BeMatcher
```
DiveNth applies the given matcher to the nth element of the given slice

#### func Eq

```go
Expand Down
1 change: 1 addition & 0 deletions generate-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ godocdown be_reflected > be_reflected/README.md
godocdown be_string > be_string/README.md
godocdown be_time > be_time/README.md
godocdown be_url > be_url/README.md
godocdown be_struct > be_struct/README.md
godocdown . > core-be-matchers.md

0 comments on commit fce45c0

Please sign in to comment.