or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

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

types.mddocs/

types Package

The types package defines the core type definitions and interfaces for Gomega. It provides the foundational contracts that enable Gomega's matcher system and assertion DSL.

Overview

The types package contains:

  • Core interfaces for matchers and assertions
  • The main Gomega interface
  • Handler and testing integration types
  • All the building blocks for Gomega's extensibility

Understanding these types is essential for:

  • Creating custom matchers
  • Integrating Gomega with custom test frameworks
  • Understanding Gomega's architecture
  • Building advanced testing utilities

Core Interfaces

GomegaMatcher

{ .api }

type GomegaMatcher interface {
    Match(actual any) (success bool, err error)
    FailureMessage(actual any) (message string)
    NegatedFailureMessage(actual any) (message string)
}

The fundamental interface that all Gomega matchers must implement.

Methods:

  • Match(actual any) (success bool, err error)

    • Performs the actual matching logic
    • actual - The value to match against
    • Returns success - true if match succeeds, false otherwise
    • Returns err - Optional error for unexpected conditions (type mismatches, etc.)
  • FailureMessage(actual any) string

    • Generates the failure message when the match fails
    • Called when Expect(x).To(matcher) fails
    • Should return a human-readable explanation of why the match failed
  • NegatedFailureMessage(actual any) string

    • Generates the failure message when the negated match fails
    • Called when Expect(x).NotTo(matcher) fails
    • Should return a human-readable explanation of why the negated match failed

Example Implementation:

type evenMatcher struct{}

func (m *evenMatcher) Match(actual any) (bool, error) {
    num, ok := actual.(int)
    if !ok {
        return false, fmt.Errorf("EvenMatcher expects an int, got %T", actual)
    }
    return num%2 == 0, nil
}

func (m *evenMatcher) FailureMessage(actual any) string {
    return fmt.Sprintf("Expected %v to be even", actual)
}

func (m *evenMatcher) NegatedFailureMessage(actual any) string {
    return fmt.Sprintf("Expected %v not to be even", actual)
}

// Usage
func BeEven() types.GomegaMatcher {
    return &evenMatcher{}
}

Expect(4).To(BeEven())
Expect(7).NotTo(BeEven())

Assertion

{ .api }

type Assertion interface {
    Should(matcher GomegaMatcher, optionalDescription ...any) bool
    ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool
    To(matcher GomegaMatcher, optionalDescription ...any) bool
    ToNot(matcher GomegaMatcher, optionalDescription ...any) bool
    NotTo(matcher GomegaMatcher, optionalDescription ...any) bool
}

Interface for synchronous assertions returned by Expect().

Methods:

All methods perform an assertion and trigger the fail handler on failure:

  • Should(matcher GomegaMatcher, optionalDescription ...any) bool

    • Asserts that the actual value matches the matcher
    • Returns true if successful, false if not (in intercepted mode)
  • ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool

    • Asserts that the actual value does NOT match the matcher
    • Returns true if successful, false if not
  • To(matcher GomegaMatcher, optionalDescription ...any) bool

    • Alias for Should - more readable in some contexts
    • Functionally identical to Should
  • ToNot(matcher GomegaMatcher, optionalDescription ...any) bool

    • Alias for ShouldNot
    • Functionally identical to NotTo
  • NotTo(matcher GomegaMatcher, optionalDescription ...any) bool

    • Alias for ShouldNot
    • Preferred over ToNot by convention

Parameters:

  • matcher - The matcher to apply
  • optionalDescription - Optional description for the assertion (format string + args)

Example Usage:

assertion := Expect(42)

// All of these work
assertion.Should(Equal(42))
assertion.To(Equal(42))         // Same as Should
assertion.ShouldNot(Equal(0))
assertion.NotTo(Equal(0))       // Same as ShouldNot
assertion.ToNot(Equal(0))       // Less common, but valid

// With optional description
Expect(value).To(Equal(100), "checking initial value")
Expect(count).To(BeNumerically(">", 0), "count should be positive: %d", count)

AsyncAssertion

{ .api }

type AsyncAssertion interface {
    Should(matcher GomegaMatcher, optionalDescription ...any) bool
    ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool

    Within(timeout time.Duration) AsyncAssertion
    WithTimeout(timeout time.Duration) AsyncAssertion
    WithPolling(interval time.Duration) AsyncAssertion
    WithContext(ctx context.Context) AsyncAssertion
    WithArguments(args ...any) AsyncAssertion

    MustPassRepeatedly(count int) AsyncAssertion
    ProbeEvery(interval time.Duration) AsyncAssertion
}

Interface for asynchronous assertions returned by Eventually() and Consistently().

Assertion Methods:

  • Should(matcher GomegaMatcher, optionalDescription ...any) bool

    • Polls until matcher succeeds or timeout
    • For Eventually: succeeds when matcher passes once
    • For Consistently: fails if matcher ever fails
  • ShouldNot(matcher GomegaMatcher, optionalDescription ...any) bool

    • Polls until negated matcher succeeds or timeout
    • For Eventually: succeeds when matcher fails once
    • For Consistently: fails if matcher ever passes

Configuration Methods:

All configuration methods return the AsyncAssertion for chaining.

  • Within(timeout time.Duration) AsyncAssertion

    • Sets the timeout duration
    • Alias for WithTimeout
  • WithTimeout(timeout time.Duration) AsyncAssertion

    • Sets the timeout duration
    • For Eventually: maximum time to wait for success
    • For Consistently: duration to maintain consistency
  • WithPolling(interval time.Duration) AsyncAssertion

    • Sets the polling interval
    • How often to check the assertion
    • Alias for ProbeEvery
  • WithContext(ctx context.Context) AsyncAssertion

    • Sets a context for cancellation
    • Assertion stops when context is cancelled
  • WithArguments(args ...any) AsyncAssertion

    • Passes arguments to the polled function
    • Function signature becomes func(args...) T
  • MustPassRepeatedly(count int) AsyncAssertion

    • For Eventually: matcher must pass count times in a row
    • Prevents flaky successes
  • ProbeEvery(interval time.Duration) AsyncAssertion

    • Sets the polling interval
    • Alias for WithPolling

Example Usage:

// Basic Eventually
Eventually(func() int { return counter }).Should(Equal(10))

// With timeout and polling
Eventually(func() bool {
    return server.IsReady()
}, "30s", "1s").Should(BeTrue())

// Fluent configuration
Eventually(getStatus).
    WithTimeout(30 * time.Second).
    WithPolling(500 * time.Millisecond).
    Should(Equal("ready"))

// With context
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

Eventually(checkHealth).
    WithContext(ctx).
    Should(Succeed())

// Must pass repeatedly (prevent flakes)
Eventually(func() bool {
    return service.Check()
}).
    WithTimeout(10 * time.Second).
    MustPassRepeatedly(3).
    Should(BeTrue())

// Consistently - must remain true
Consistently(func() int {
    return activeConnections
}, "5s", "500ms").Should(BeNumerically("<=", 100))

Gomega

{ .api }

type Gomega interface {
    Ω(actual any, extra ...any) Assertion
    Expect(actual any, extra ...any) Assertion
    ExpectWithOffset(offset int, actual any, extra ...any) Assertion

    Eventually(actualOrCtx any, args ...any) AsyncAssertion
    EventuallyWithOffset(offset int, actualOrCtx any, args ...any) AsyncAssertion
    Consistently(actualOrCtx any, args ...any) AsyncAssertion
    ConsistentlyWithOffset(offset int, actualOrCtx any, args ...any) AsyncAssertion

    SetDefaultEventuallyTimeout(time.Duration)
    SetDefaultEventuallyPollingInterval(time.Duration)
    SetDefaultConsistentlyDuration(time.Duration)
    SetDefaultConsistentlyPollingInterval(time.Duration)
}

The main Gomega interface that defines the complete assertion DSL.

Synchronous Assertion Methods:

  • Ω(actual any, extra ...any) Assertion

    • Creates a synchronous assertion (identical to Expect)
    • Unicode omega symbol for brevity
  • Expect(actual any, extra ...any) Assertion

    • Creates a synchronous assertion
    • Primary method for most assertions
  • ExpectWithOffset(offset int, actual any, extra ...any) Assertion

    • Like Expect but adjusts call stack offset for error reporting
    • Useful when wrapping assertions in helper functions

Asynchronous Assertion Methods:

  • Eventually(actualOrCtx any, args ...any) AsyncAssertion

    • Polls until assertion succeeds or timeout
    • Can accept a context.Context as first argument
  • EventuallyWithOffset(offset int, actualOrCtx any, args ...any) AsyncAssertion

    • Like Eventually with custom stack offset
  • Consistently(actualOrCtx any, args ...any) AsyncAssertion

    • Polls and requires assertion to consistently pass
  • ConsistentlyWithOffset(offset int, actualOrCtx any, args ...any) AsyncAssertion

    • Like Consistently with custom stack offset

Configuration Methods:

  • SetDefaultEventuallyTimeout(time.Duration)

    • Sets default timeout for all Eventually calls
  • SetDefaultEventuallyPollingInterval(time.Duration)

    • Sets default polling interval for Eventually
  • SetDefaultConsistentlyDuration(time.Duration)

    • Sets default duration for Consistently
  • SetDefaultConsistentlyPollingInterval(time.Duration)

    • Sets default polling interval for Consistently

Example Usage:

// Creating custom Gomega instance
gomega := NewGomega(func(message string, callerSkip ...int) {
    // Custom fail handler
    fmt.Printf("Test failed: %s\n", message)
})

// Using the instance
gomega.Expect(42).To(Equal(42))
gomega.Eventually(func() int { return counter }).Should(Equal(10))

// Configure defaults
gomega.SetDefaultEventuallyTimeout(30 * time.Second)
gomega.SetDefaultEventuallyPollingInterval(500 * time.Millisecond)

Handler and Testing Types

GomegaFailHandler

{ .api }

type GomegaFailHandler func(message string, callerSkip ...int)

Function type for handling test failures. This is the bridge between Gomega and your test framework.

Parameters:

  • message - The failure message to report
  • callerSkip - Optional call stack skip count for proper error location reporting

Example Implementations:

// For Ginkgo
func GinkgoFailHandler(message string, callerSkip ...int) {
    Fail(message, callerSkip...)
}

// For testing.T
func TestingTFailHandler(t *testing.T) GomegaFailHandler {
    return func(message string, callerSkip ...int) {
        t.Helper()
        t.Fatalf("\n%s", message)
    }
}

// Custom handler
func CustomFailHandler(message string, callerSkip ...int) {
    log.Printf("Assertion failed: %s", message)
    os.Exit(1)
}

// Usage
RegisterFailHandler(GinkgoFailHandler)
// or
gomega := NewGomega(TestingTFailHandler(t))

GomegaTestingT

{ .api }

type GomegaTestingT interface {
    Helper()
    Fatalf(format string, args ...any)
}

Interface compatible with *testing.T for integration with Go's standard testing package.

Methods:

  • Helper()

    • Marks the calling function as a test helper
    • Improves error location reporting
  • Fatalf(format string, args ...any)

    • Formats and reports a fatal test error
    • Equivalent to Printf followed by FailNow

Example Usage:

func TestMyFunction(t *testing.T) {
    // NewWithT creates a Gomega instance bound to testing.T
    g := NewWithT(t)

    result := MyFunction()
    g.Expect(result).To(Equal(42))

    // Can also use package-level with RegisterTestingT
    RegisterTestingT(t)
    Expect(result).To(Equal(42))
}

Complete Examples

Implementing a Custom Matcher

package custommatchers

import (
    "fmt"
    "github.com/onsi/gomega/types"
)

// CustomMatcher implementation
type stringLengthMatcher struct {
    minLength int
    maxLength int
}

func (m *stringLengthMatcher) Match(actual any) (bool, error) {
    str, ok := actual.(string)
    if !ok {
        return false, fmt.Errorf("StringLengthMatcher expects a string, got %T", actual)
    }

    length := len(str)
    return length >= m.minLength && length <= m.maxLength, nil
}

func (m *stringLengthMatcher) FailureMessage(actual any) string {
    str := actual.(string)
    return fmt.Sprintf(
        "Expected string '%s' (length %d) to have length between %d and %d",
        str, len(str), m.minLength, m.maxLength,
    )
}

func (m *stringLengthMatcher) NegatedFailureMessage(actual any) string {
    str := actual.(string)
    return fmt.Sprintf(
        "Expected string '%s' (length %d) not to have length between %d and %d",
        str, len(str), m.minLength, m.maxLength,
    )
}

// Matcher factory function
func HaveStringLength(min, max int) types.GomegaMatcher {
    return &stringLengthMatcher{
        minLength: min,
        maxLength: max,
    }
}

// Usage
var _ = Describe("Custom Matcher", func() {
    It("validates string length", func() {
        Expect("hello").To(HaveStringLength(3, 10))
        Expect("hi").NotTo(HaveStringLength(5, 10))
    })
})

Creating a Custom Gomega Instance

package mytest

import (
    "testing"
    "github.com/onsi/gomega"
    "github.com/onsi/gomega/types"
)

func TestWithCustomGomega(t *testing.T) {
    // Create custom fail handler
    failures := []string{}
    customHandler := func(message string, callerSkip ...int) {
        failures = append(failures, message)
    }

    // Create Gomega instance with custom handler
    g := gomega.NewGomega(customHandler)

    // Use the instance
    g.Expect(1).To(gomega.Equal(2)) // Captures failure instead of failing
    g.Expect(3).To(gomega.Equal(4)) // Captures another failure

    // Check captured failures
    if len(failures) != 2 {
        t.Fatalf("Expected 2 failures, got %d", len(failures))
    }
}

Integration with testing.T

package mypackage_test

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

func TestWithTestingT(t *testing.T) {
    // Method 1: NewWithT (recommended)
    g := NewWithT(t)

    result := processData("input")
    g.Expect(result).To(Equal("expected"))
    g.Eventually(func() bool {
        return isReady()
    }).Should(BeTrue())

    // Method 2: Package-level (legacy)
    RegisterTestingT(t)
    Expect(result).To(Equal("expected"))
}

func TestTableDriven(t *testing.T) {
    tests := []struct {
        name     string
        input    string
        expected string
    }{
        {"case1", "input1", "output1"},
        {"case2", "input2", "output2"},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            g := NewWithT(t)
            result := processData(tt.input)
            g.Expect(result).To(Equal(tt.expected))
        })
    }
}

Wrapper Functions with Offset

package helpers

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

// Helper function that wraps Expect
func ExpectValid(obj interface{}) types.Assertion {
    // Use offset of 1 so errors point to the caller
    return ExpectWithOffset(1, obj)
}

func ExpectStatusOK(response *http.Response) {
    // Offset ensures error points to test code, not this helper
    ExpectWithOffset(1, response.StatusCode).To(Equal(200))
}

// Usage in tests
var _ = Describe("Using Helpers", func() {
    It("uses helper functions", func() {
        obj := CreateObject()
        ExpectValid(obj).To(BeTrue()) // Error points here, not to helper

        resp := MakeRequest()
        ExpectStatusOK(resp) // Error points here
    })
})

Composite Matcher

package matchers

import (
    "fmt"
    "github.com/onsi/gomega/types"
)

// Matcher that combines multiple matchers
type allOfMatcher struct {
    matchers []types.GomegaMatcher
}

func (m *allOfMatcher) Match(actual any) (bool, error) {
    for _, matcher := range m.matchers {
        success, err := matcher.Match(actual)
        if err != nil {
            return false, err
        }
        if !success {
            return false, nil
        }
    }
    return true, nil
}

func (m *allOfMatcher) FailureMessage(actual any) string {
    messages := []string{}
    for _, matcher := range m.matchers {
        success, _ := matcher.Match(actual)
        if !success {
            messages = append(messages, matcher.FailureMessage(actual))
        }
    }
    return fmt.Sprintf("Expected all matchers to pass:\n%s", strings.Join(messages, "\n"))
}

func (m *allOfMatcher) NegatedFailureMessage(actual any) string {
    return fmt.Sprintf("Expected at least one matcher to fail")
}

func AllOf(matchers ...types.GomegaMatcher) types.GomegaMatcher {
    return &allOfMatcher{matchers: matchers}
}

// Usage
Expect(value).To(AllOf(
    BeNumerically(">", 0),
    BeNumerically("<", 100),
    Not(Equal(50)),
))

Async Matcher with State

type eventuallyTrueMatcher struct {
    checks int
}

func (m *eventuallyTrueMatcher) Match(actual any) (bool, error) {
    m.checks++

    fn, ok := actual.(func() bool)
    if !ok {
        return false, fmt.Errorf("Expected a func() bool, got %T", actual)
    }

    return fn(), nil
}

func (m *eventuallyTrueMatcher) FailureMessage(actual any) string {
    return fmt.Sprintf("Expected function to return true (checked %d times)", m.checks)
}

func (m *eventuallyTrueMatcher) NegatedFailureMessage(actual any) string {
    return fmt.Sprintf("Expected function not to return true")
}

func EventuallyTrue() types.GomegaMatcher {
    return &eventuallyTrueMatcher{}
}

// Usage
counter := 0
Eventually(func() bool {
    counter++
    return counter > 5
}).Should(EventuallyTrue())

Advanced Error Matcher

type errorChainMatcher struct {
    target error
}

func (m *errorChainMatcher) Match(actual any) (bool, error) {
    err, ok := actual.(error)
    if !ok {
        return false, fmt.Errorf("Expected an error, got %T", actual)
    }

    if err == nil {
        return false, nil
    }

    // Check if target is in error chain
    return errors.Is(err, m.target), nil
}

func (m *errorChainMatcher) FailureMessage(actual any) string {
    if actual == nil {
        return fmt.Sprintf("Expected error chain to contain %v, but got nil", m.target)
    }
    return fmt.Sprintf("Expected error chain %v to contain %v", actual, m.target)
}

func (m *errorChainMatcher) NegatedFailureMessage(actual any) string {
    return fmt.Sprintf("Expected error chain %v not to contain %v", actual, m.target)
}

func ContainError(target error) types.GomegaMatcher {
    return &errorChainMatcher{target: target}
}

// Usage
var ErrNotFound = errors.New("not found")

err := someFunction()
Expect(err).To(ContainError(ErrNotFound))

Best Practices

1. Prefer Built-in Matchers

Use built-in matchers when possible:

// Good: Use built-in
Expect(slice).To(ContainElement("item"))

// Unnecessary: Custom matcher for standard case
// (Unless you have specific requirements)

2. Type Safety in Matchers

Handle type mismatches gracefully:

func (m *myMatcher) Match(actual any) (bool, error) {
    value, ok := actual.(MyType)
    if !ok {
        return false, fmt.Errorf("Expected MyType, got %T", actual)
    }
    // ... matching logic
}

3. Clear Failure Messages

Provide informative failure messages:

func (m *myMatcher) FailureMessage(actual any) string {
    // Good: Specific and actionable
    return fmt.Sprintf(
        "Expected value %v to be in range [%d, %d], but it was outside",
        actual, m.min, m.max,
    )

    // Avoid: Vague
    // return "Match failed"
}

4. Use ExpectWithOffset in Helpers

Maintain correct error locations:

func ExpectHTTPSuccess(resp *http.Response) {
    // Offset 1: error reports at caller
    ExpectWithOffset(1, resp.StatusCode).To(BeNumerically("<", 400))
}

5. Thread-Safe Matchers

Ensure matchers are safe for concurrent use:

// Good: No shared mutable state
type safeMatcher struct {
    expected int // immutable after creation
}

// Avoid: Mutable state
type unsafeMatcher struct {
    counter int // modified during Match
}

6. Proper Error Handling

Return errors for truly exceptional conditions:

func (m *myMatcher) Match(actual any) (bool, error) {
    // Type mismatch: return error
    if _, ok := actual.(string); !ok {
        return false, fmt.Errorf("wrong type")
    }

    // Match failure: return false, nil
    if !condition {
        return false, nil
    }

    return true, nil
}

Interface Relationships

GomegaMatcher (implemented by all matchers)
    ├─ Match() - performs matching
    ├─ FailureMessage() - formats failure
    └─ NegatedFailureMessage() - formats negated failure

Assertion (returned by Expect)
    ├─ Should() / To()
    ├─ ShouldNot() / NotTo()
    └─ Uses GomegaMatcher

AsyncAssertion (returned by Eventually/Consistently)
    ├─ Should() / ShouldNot()
    ├─ Configuration methods
    └─ Uses GomegaMatcher

Gomega (main interface)
    ├─ Expect() → Assertion
    ├─ Eventually() → AsyncAssertion
    ├─ Consistently() → AsyncAssertion
    └─ Configuration methods

GomegaFailHandler (fail handler function)
    └─ Called when assertions fail

GomegaTestingT (testing.T interface)
    └─ Enables integration with testing package

Type Aliases

Gomega also provides type aliases in the main package:

type Gomega = types.Gomega
type Assertion = types.Assertion
type AsyncAssertion = types.AsyncAssertion
type GomegaMatcher = types.GomegaMatcher
type GomegaFailHandler = types.GomegaFailHandler
type GomegaTestingT = types.GomegaTestingT

This allows importing from either package:

import "github.com/onsi/gomega/types"

var matcher types.GomegaMatcher

// Or
import "github.com/onsi/gomega"

var matcher gomega.GomegaMatcher