or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-assertions.mdformat.mdgbytes.mdgcustom.mdgexec.mdghttp.mdgleak.mdgmeasure.mdgstruct.mdindex.mdmatchers.mdtypes-interfaces.md
tile.json

gstruct.mddocs/

GStruct Package

Import: github.com/onsi/gomega/gstruct

The gstruct package provides matchers for structural matching of complex Go types including structs, slices, arrays, and maps. These matchers allow you to specify precise validation rules for nested data structures with flexible options for handling extras, missing values, and duplicates.

Struct Matchers

MatchAllFields

func MatchAllFields(fields Fields) types.GomegaMatcher

Matches all struct fields strictly. Every field in the struct must have a corresponding matcher in the Fields map, and every matcher must match. No extra fields are allowed.

Example:

import (
    . "github.com/onsi/gomega"
    . "github.com/onsi/gomega/gstruct"
)

actual := struct{
    A int
    B []bool
    C string
}{
    A: 5,
    B: []bool{true, false},
    C: "foo",
}

Expect(actual).To(MatchAllFields(Fields{
    "A": Equal(5),
    "B": ConsistOf(true, false),
    "C": Equal("foo"),
}))

MatchFields

func MatchFields(options Options, fields Fields) types.GomegaMatcher

Matches struct fields with flexible options. Can ignore extra fields, missing fields, or unexported extra fields based on the provided Options.

Example:

actual := struct{
    A int
    B []bool
    C string
}{
    A: 5,
    B: []bool{true, false},
    C: "foo",
}

// Ignore extra fields (C is not validated)
Expect(actual).To(MatchFields(IgnoreExtras, Fields{
    "A": Equal(5),
    "B": ConsistOf(true, false),
}))

// Ignore missing fields (D doesn't exist in actual)
Expect(actual).To(MatchFields(IgnoreMissing, Fields{
    "A": Equal(5),
    "B": ConsistOf(true, false),
    "C": Equal("foo"),
    "D": Equal("extra"),
}))

// Combine options with bitwise OR
Expect(actual).To(MatchFields(IgnoreExtras|IgnoreMissing, Fields{
    "A": Equal(5),
}))

Fields Type

type Fields map[string]types.GomegaMatcher

Maps struct field names to matchers. Each key is the name of a struct field, and each value is a matcher that validates that field.

Slice/Array Matchers

MatchAllElements

func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher

Matches all slice or array elements strictly. Uses an Identifier function to map each element to a string key, then validates each element against the matcher associated with that key. Every element must match, and every matcher must be matched.

Example:

idFn := func(element any) string {
    return fmt.Sprintf("%v", element)
}

Expect([]string{"a", "b"}).To(MatchAllElements(idFn, Elements{
    "a": Equal("a"),
    "b": Equal("b"),
}))

MatchAllElementsWithIndex

func MatchAllElementsWithIndex(identifier IdentifierWithIndex, elements Elements) types.GomegaMatcher

Like MatchAllElements but the identifier function receives both the index and the element.

Example:

idFn := func(index int, element any) string {
    return strconv.Itoa(index)
}

Expect([]string{"a", "b"}).To(MatchAllElementsWithIndex(idFn, Elements{
    "0": Equal("a"),
    "1": Equal("b"),
}))

MatchElements

func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher

Matches slice or array elements with flexible options. Can ignore extra elements and/or missing elements.

Example:

idFn := func(element any) string {
    return fmt.Sprintf("%v", element)
}

// Ignore extra elements
Expect([]string{"a", "b", "c"}).To(MatchElements(idFn, IgnoreExtras, Elements{
    "a": Equal("a"),
    "b": Equal("b"),
}))

// Ignore missing elements
Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing, Elements{
    "a": Equal("a"),
    "b": Equal("b"),
    "c": Equal("c"),
    "d": Equal("d"),
}))

// Allow duplicate identifiers
nonUniqueID := func(element any) string {
    return element.(string)[0:1]  // Use first character as ID
}

Expect([]string{"a123", "a456", "b789"}).To(
    MatchElements(nonUniqueID, AllowDuplicates, Elements{
        "a": ContainSubstring("a"),
        "b": ContainSubstring("b"),
    }))

MatchElementsWithIndex

func MatchElementsWithIndex(identifier IdentifierWithIndex, options Options, elements Elements) types.GomegaMatcher

Like MatchElements but the identifier function receives both the index and the element.

Example:

idFn := func(index int, element any) string {
    return strconv.Itoa(index)
}

Expect([]string{"a", "b", "c"}).To(MatchElementsWithIndex(idFn, IgnoreExtras, Elements{
    "0": Equal("a"),
    "1": Equal("b"),
}))

Elements Type

type Elements map[string]types.GomegaMatcher

Maps element identifier keys to matchers. The keys are strings returned by the Identifier function, and values are matchers that validate elements with those keys.

Identifier Types

type Identifier func(element any) string

Function that maps a slice/array element to a string key used for matching.

type IdentifierWithIndex func(index int, element any) string

Function that maps a slice/array element and its index to a string key used for matching.

IndexIdentity Helper

func IndexIdentity(index int, _ any) string

Helper identifier function that uses the array/slice index as the element key. Converts the index to a string.

Example:

Expect([]string{"a", "b", "c"}).To(
    MatchAllElementsWithIndex(IndexIdentity, Elements{
        "0": Equal("a"),
        "1": Equal("b"),
        "2": Equal("c"),
    }))

Map Matchers

MatchAllKeys

func MatchAllKeys(keys Keys) types.GomegaMatcher

Matches all map keys strictly. Every key in the map must have a corresponding matcher in the Keys map, and every matcher must match. No extra keys are allowed.

Example:

actualMap := map[string]int{
    "a": 1,
    "b": 2,
}

Expect(actualMap).To(MatchAllKeys(Keys{
    "a": Equal(1),
    "b": Equal(2),
}))

MatchKeys

func MatchKeys(options Options, keys Keys) types.GomegaMatcher

Matches map keys with flexible options. Can ignore extra keys and/or missing keys.

Example:

actualMap := map[string]int{
    "a": 1,
    "b": 2,
    "c": 3,
}

// Ignore extra keys
Expect(actualMap).To(MatchKeys(IgnoreExtras, Keys{
    "a": Equal(1),
    "b": Equal(2),
}))

// Ignore missing keys
Expect(actualMap).To(MatchKeys(IgnoreMissing, Keys{
    "a": Equal(1),
    "b": Equal(2),
    "c": Equal(3),
    "d": Equal(4),
}))

Keys Type

type Keys map[any]types.GomegaMatcher

Maps map keys to matchers for their values. Keys can be of any type (matching the map's key type), and values are matchers that validate the corresponding map values.

Pointer Matchers

PointTo

func PointTo(matcher types.GomegaMatcher) types.GomegaMatcher

Dereferences a pointer and applies the given matcher to the pointed-to value. Fails if the pointer is nil.

Example:

actual := 5
Expect(&actual).To(PointTo(Equal(5)))

str := "hello"
Expect(&str).To(PointTo(ContainSubstring("ell")))

// Fails with nil pointer
var ptr *int
Expect(ptr).NotTo(PointTo(Equal(5)))

Utility Matchers

Ignore

func Ignore() types.GomegaMatcher

Matcher that always succeeds, ignoring the actual value. Used to match fields/elements/keys without validating their values.

Example:

// Always succeeds
Expect(nil).To(Ignore())
Expect(true).To(Ignore())
Expect(42).To(Ignore())

// Useful for ignoring specific struct fields
Expect(actual).To(MatchAllFields(Fields{
    "A": Equal(5),
    "B": Ignore(),  // Don't care about B's value
    "C": Ignore(),  // Don't care about C's value
}))

Reject

func Reject() types.GomegaMatcher

Matcher that always fails, ignoring the actual value. Can be used with IgnoreMissing to catch problematic elements, or to verify tests are running.

Example:

// Always fails
Expect(nil).NotTo(Reject())
Expect(true).NotTo(Reject())
Expect(42).NotTo(Reject())

// Can be used to ensure a field should never be present
Expect(actual).To(MatchFields(IgnoreMissing, Fields{
    "A": Equal(5),
    "BadField": Reject(),  // Fail if this field exists
}))

Options

Options Type

type Options int

Bitmask options for controlling matcher behavior. Multiple options can be combined using bitwise OR (|).

Option Constants

const IgnoreExtras Options

Tells the matcher to ignore extra fields/elements/keys not specified in the matcher, rather than triggering a failure.

const IgnoreMissing Options

Tells the matcher to ignore missing fields/elements/keys from the matcher, rather than triggering a failure.

const AllowDuplicates Options

Tells the matcher to permit multiple members of a slice to produce the same ID when processed by the identifier function. All members that map to a given key must still match successfully with the matcher provided for that key.

const IgnoreUnexportedExtras Options

Tells the matcher to ignore extra unexported struct fields, rather than triggering a failure. Since unexported fields cannot be checked for values, this option is only useful when you want to check every exported field but don't care about extra unexported fields.

Example:

// Single option
MatchFields(IgnoreExtras, Fields{...})

// Multiple options combined
MatchFields(IgnoreExtras|IgnoreMissing, Fields{...})
MatchElements(idFn, IgnoreExtras|AllowDuplicates, Elements{...})

Error Handling Utilities

The errors sub-package (github.com/onsi/gomega/gstruct/errors) provides utilities for handling and nesting errors in structural matchers.

Nest

func Nest(path string, err error) error

Wraps an error with a field path to provide better context in failure messages. This is used internally by structural matchers to indicate which field or element caused a match failure.

Parameters:

  • path - The field path or element identifier (e.g., "User.Name", "[2]")
  • err - The error to wrap

Behavior:

  • If err is already a NestedError, prepends the path to it
  • If err is an AggregateError, recursively nests each error in the aggregate
  • Otherwise, creates a new NestedError with the given path

Usage Example:

import (
    "errors"
    "github.com/onsi/gomega/gstruct/errors"
)

// Wrap an error with field path context
err := errors.New("value mismatch")
nestedErr := gstructErrors.Nest("User.Email", err)
// Error message becomes: "User.Email: value mismatch"

// Nest multiple levels
err1 := errors.New("invalid format")
err2 := gstructErrors.Nest("Email", err1)
err3 := gstructErrors.Nest("User", err2)
// Error message becomes: "User.Email: invalid format"

This function is typically used when implementing custom structural matchers to provide clear error messages that indicate exactly where in a nested structure a match failed.

Complete Example

package mytest

import (
    "fmt"
    "testing"

    . "github.com/onsi/gomega"
    . "github.com/onsi/gomega/gstruct"
)

type Person struct {
    Name    string
    Age     int
    Email   string
    private string
}

func TestStructMatching(t *testing.T) {
    RegisterTestingT(t)

    person := Person{
        Name:    "Alice",
        Age:     30,
        Email:   "alice@example.com",
        private: "secret",
    }

    // Match all exported fields, ignore unexported extras
    Expect(person).To(MatchFields(IgnoreUnexportedExtras, Fields{
        "Name":  Equal("Alice"),
        "Age":   BeNumerically(">", 18),
        "Email": ContainSubstring("@example.com"),
    }))

    // Match with some fields ignored
    Expect(person).To(MatchAllFields(Fields{
        "Name":    Equal("Alice"),
        "Age":     BeNumerically(">=", 30),
        "Email":   Ignore(),
        "private": Ignore(),
    }))
}

func TestSliceMatching(t *testing.T) {
    RegisterTestingT(t)

    people := []Person{
        {Name: "Alice", Age: 30, Email: "alice@example.com"},
        {Name: "Bob", Age: 25, Email: "bob@example.com"},
    }

    // Use name as identifier
    byName := func(element any) string {
        return element.(Person).Name
    }

    Expect(people).To(MatchAllElements(byName, Elements{
        "Alice": MatchFields(IgnoreExtras, Fields{
            "Age": Equal(30),
        }),
        "Bob": MatchFields(IgnoreExtras, Fields{
            "Age": Equal(25),
        }),
    }))

    // Use index as identifier
    Expect(people).To(MatchAllElementsWithIndex(IndexIdentity, Elements{
        "0": MatchFields(IgnoreExtras, Fields{"Name": Equal("Alice")}),
        "1": MatchFields(IgnoreExtras, Fields{"Name": Equal("Bob")}),
    }))
}

func TestMapMatching(t *testing.T) {
    RegisterTestingT(t)

    scores := map[string]int{
        "Alice": 95,
        "Bob":   87,
        "Carol": 92,
    }

    // Match all keys
    Expect(scores).To(MatchAllKeys(Keys{
        "Alice": BeNumerically(">=", 90),
        "Bob":   BeNumerically(">", 80),
        "Carol": BeNumerically(">=", 90),
    }))

    // Ignore extra keys
    Expect(scores).To(MatchKeys(IgnoreExtras, Keys{
        "Alice": BeNumerically(">=", 90),
        "Bob":   BeNumerically(">", 80),
    }))
}

func TestPointerMatching(t *testing.T) {
    RegisterTestingT(t)

    value := 42
    ptr := &value

    Expect(ptr).To(PointTo(Equal(42)))
    Expect(ptr).To(PointTo(BeNumerically(">", 40)))

    // Nested pointer matching
    personPtr := &Person{Name: "Alice", Age: 30}
    Expect(personPtr).To(PointTo(MatchFields(IgnoreExtras, Fields{
        "Name": Equal("Alice"),
        "Age":  Equal(30),
    })))
}