or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cmp-core.mdcmp-options.mdcmp-path.mdcmpopts.mdindex.md
tile.json

cmpopts.mddocs/

Common Options (cmpopts)

The cmpopts package provides common pre-built options for the cmp package, covering typical comparison scenarios like approximate equality, sorting, and selective ignoring.

Import

import (
    "github.com/google/go-cmp/cmp"
    "github.com/google/go-cmp/cmp/cmpopts"
)

Equality Options

EquateEmpty

func EquateEmpty() cmp.Option

EquateEmpty returns a cmp.Comparer option that determines all maps and slices with a length of zero to be equal, regardless of whether they are nil.

Returns:

  • cmp.Option - Configuration option

Example:

var nilSlice []int
emptySlice := []int{}

cmp.Equal(nilSlice, emptySlice)                    // false (different)
cmp.Equal(nilSlice, emptySlice, cmpopts.EquateEmpty()) // true (both empty)

var nilMap map[string]int
emptyMap := map[string]int{}

cmp.Equal(nilMap, emptyMap)                    // false (different)
cmp.Equal(nilMap, emptyMap, cmpopts.EquateEmpty()) // true (both empty)

EquateApprox

func EquateApprox(fraction, margin float64) cmp.Option

EquateApprox returns a cmp.Comparer option that determines float32 or float64 values to be equal if they are within a relative fraction or absolute margin. Not used when either x or y is NaN or infinite.

Parameters:

  • fraction float64 - Relative fraction tolerance (use 0 for none). Must be non-negative.
  • margin float64 - Absolute margin tolerance (use 0 for none). Must be non-negative.

Returns:

  • cmp.Option - Configuration option

Formula: |x-y| ≤ max(fraction*min(|x|, |y|), margin)

Note: Can be used in conjunction with EquateNaNs.

Example:

// Within 5% or 0.1 absolute difference
approx := cmpopts.EquateApprox(0.05, 0.1)

cmp.Equal(1.0, 1.03, approx)   // true (within 5%)
cmp.Equal(0.0, 0.05, approx)   // true (within 0.1 margin)
cmp.Equal(1.0, 1.2, approx)    // false (exceeds both)

// Only absolute margin
absoluteOnly := cmpopts.EquateApprox(0, 0.01)
cmp.Equal(1.001, 1.002, absoluteOnly) // true

// Only relative fraction
relativeOnly := cmpopts.EquateApprox(0.01, 0)
cmp.Equal(100.0, 100.5, relativeOnly) // true (within 1%)

EquateApproxTime

func EquateApproxTime(margin time.Duration) cmp.Option

EquateApproxTime returns a cmp.Comparer option that determines two non-zero time.Time values to be equal if they are within some margin of one another. If both times have a monotonic clock reading, uses the monotonic time difference.

Parameters:

  • margin time.Duration - Time margin. Must be non-negative.

Returns:

  • cmp.Option - Configuration option

Example:

import "time"

now := time.Now()
slightlyLater := now.Add(100 * time.Millisecond)

// Within 1 second
timeTolerance := cmpopts.EquateApproxTime(time.Second)

cmp.Equal(now, slightlyLater, timeTolerance) // true
cmp.Equal(now, now.Add(2*time.Second), timeTolerance) // false

EquateNaNs

func EquateNaNs() cmp.Option

EquateNaNs returns a cmp.Comparer option that determines float32 and float64 NaN values to be equal.

Returns:

  • cmp.Option - Configuration option

Note: Can be used in conjunction with EquateApprox.

Example:

import "math"

nan1 := math.NaN()
nan2 := math.NaN()

cmp.Equal(nan1, nan2)                      // false (NaN != NaN in Go)
cmp.Equal(nan1, nan2, cmpopts.EquateNaNs())    // true

EquateComparable

func EquateComparable(typs ...interface{}) cmp.Option

EquateComparable returns a cmp.Option that determines equality of comparable types by directly comparing them using the == operator in Go. The types to compare are specified by passing a value of that type.

Parameters:

  • typs ...interface{} - Types to compare (specified by passing value of each type)

Returns:

  • cmp.Option - Configuration option

Note: Only use on types documented as safe for direct == comparison. For example, net/netip.Addr is safe, while time.Time discourages use of ==.

Example:

import "net/netip"

addr1 := netip.MustParseAddr("192.168.1.1")
addr2 := netip.MustParseAddr("192.168.1.1")

// netip.Addr is documented as safe for == comparison
cmp.Equal(addr1, addr2, cmpopts.EquateComparable(netip.Addr{})) // true

EquateErrors

func EquateErrors() cmp.Option

EquateErrors returns a cmp.Comparer option that determines errors to be equal if errors.Is reports them to match. The AnyError error can be used to match any non-nil error.

Returns:

  • cmp.Option - Configuration option

Example:

import (
    "errors"
    "io"
)

err1 := io.EOF
err2 := io.EOF
wrappedEOF := fmt.Errorf("wrapped: %w", io.EOF)

cmp.Equal(err1, err2, cmpopts.EquateErrors())          // true
cmp.Equal(err1, wrappedEOF, cmpopts.EquateErrors())    // true (errors.Is matches)

// Using AnyError
type Response struct {
    Data string
    Err  error
}

r1 := Response{Data: "test", Err: errors.New("failed")}
r2 := Response{Data: "test", Err: errors.New("other error")}

// Match any non-nil error
cmp.Equal(r1, r2, cmp.Comparer(func(x, y error) bool {
    if x == cmpopts.AnyError || y == cmpopts.AnyError {
        return x != nil && y != nil
    }
    return errors.Is(x, y) || errors.Is(y, x)
}))

AnyError Variable

var AnyError anyError

AnyError is an error that matches any non-nil error. Used with EquateErrors and custom error comparisons.

Ignoring Options

IgnoreUnexported

func IgnoreUnexported(typs ...interface{}) cmp.Option

IgnoreUnexported returns a cmp.Option that ignores the immediate unexported fields of a struct, including anonymous fields of unexported types. Unexported fields within exported fields of struct types are not ignored unless their type is also passed.

Parameters:

  • typs ...interface{} - Struct types whose unexported fields should be ignored

Returns:

  • cmp.Option - Configuration option

Warning: Avoid ignoring unexported fields of types you don't control (e.g., from another repository), as implementation changes may affect behavior. Prefer custom cmp.Comparer instead.

Example:

type Person struct {
    Name string
    age  int // unexported
}

p1 := Person{Name: "Alice", age: 30}
p2 := Person{Name: "Alice", age: 35}

// Would panic without option
cmp.Equal(p1, p2, cmpopts.IgnoreUnexported(Person{})) // true (age ignored)

IgnoreFields

func IgnoreFields(typ interface{}, names ...string) cmp.Option

IgnoreFields returns a cmp.Option that ignores fields of the given names on a single struct type. Respects names of exported fields forwarded due to struct embedding.

Parameters:

  • typ interface{} - Struct type (specified by passing value of that type)
  • names ...string - Field names to ignore. May be dot-delimited for nested fields (e.g., "Foo.Bar")

Returns:

  • cmp.Option - Configuration option

Example:

type User struct {
    ID       int
    Name     string
    Password string
    Email    string
}

u1 := User{ID: 1, Name: "Alice", Password: "secret1", Email: "alice@example.com"}
u2 := User{ID: 1, Name: "Alice", Password: "secret2", Email: "alice@example.com"}

// Ignore Password field
cmp.Equal(u1, u2, cmpopts.IgnoreFields(User{}, "Password")) // true

Example with nested fields:

type Address struct {
    Street string
    City   string
}

type Employee struct {
    Name    string
    Address Address
}

e1 := Employee{Name: "Bob", Address: Address{Street: "1st St", City: "NYC"}}
e2 := Employee{Name: "Bob", Address: Address{Street: "2nd St", City: "NYC"}}

// Ignore nested Street field
cmp.Equal(e1, e2, cmpopts.IgnoreFields(Employee{}, "Address.Street")) // true

IgnoreTypes

func IgnoreTypes(typs ...interface{}) cmp.Option

IgnoreTypes returns a cmp.Option that ignores all values assignable to certain types.

Parameters:

  • typs ...interface{} - Types to ignore (specified by passing value of each type)

Returns:

  • cmp.Option - Configuration option

Example:

import "time"

type Event struct {
    Name      string
    Timestamp time.Time
    Details   string
}

e1 := Event{Name: "login", Timestamp: time.Now(), Details: "User logged in"}
e2 := Event{Name: "login", Timestamp: time.Now().Add(time.Hour), Details: "User logged in"}

// Ignore all time.Time values
cmp.Equal(e1, e2, cmpopts.IgnoreTypes(time.Time{})) // true

IgnoreInterfaces

func IgnoreInterfaces(ifaces interface{}) cmp.Option

IgnoreInterfaces returns a cmp.Option that ignores all values or references of values assignable to certain interface types. Interfaces specified by passing anonymous struct with interface types embedded.

Parameters:

  • ifaces interface{} - Anonymous struct with embedded interface types (e.g., struct{sync.Locker}{})

Returns:

  • cmp.Option - Configuration option

Example:

import (
    "io"
    "sync"
)

type Config struct {
    Name   string
    Lock   sync.Locker
    Reader io.Reader
}

c1 := Config{Name: "cfg", Lock: &sync.Mutex{}, Reader: nil}
c2 := Config{Name: "cfg", Lock: &sync.RWMutex{}, Reader: nil}

// Ignore sync.Locker interface
cmp.Equal(c1, c2, cmpopts.IgnoreInterfaces(struct{ sync.Locker }{})) // true

IgnoreSliceElements

func IgnoreSliceElements(discardFunc interface{}) cmp.Option

IgnoreSliceElements returns a cmp.Option that ignores elements of []V. Elements are ignored if the function reports true.

Parameters:

  • discardFunc interface{} - Must be function func(T) bool for slice elements V assignable to T

Returns:

  • cmp.Option - Configuration option

Example:

numbers := []int{1, 2, 0, 3, 0, 4}
filtered := []int{1, 2, 3, 4}

// Ignore zero elements
ignoreZeros := cmpopts.IgnoreSliceElements(func(x int) bool {
    return x == 0
})

cmp.Equal(numbers, filtered, ignoreZeros) // true (zeros ignored)

IgnoreMapEntries

func IgnoreMapEntries(discardFunc interface{}) cmp.Option

IgnoreMapEntries returns a cmp.Option that ignores entries of map[K]V. Entries are ignored if the function reports true.

Parameters:

  • discardFunc interface{} - Must be function func(T, R) bool for map keys K assignable to T and values V assignable to R

Returns:

  • cmp.Option - Configuration option

Example:

m1 := map[string]int{"a": 1, "b": 2, "temp": 99}
m2 := map[string]int{"a": 1, "b": 2}

// Ignore entries with keys starting with "temp"
ignoreTempKeys := cmpopts.IgnoreMapEntries(func(k string, v int) bool {
    return strings.HasPrefix(k, "temp")
})

cmp.Equal(m1, m2, ignoreTempKeys) // true (temp entry ignored)

Sorting Options

SortSlices

func SortSlices(lessOrCompareFunc interface{}) cmp.Option

SortSlices returns a cmp.Transformer option that sorts all []V slices before comparison.

Parameters:

  • lessOrCompareFunc interface{} - Either:
    • Less function: func(T, T) bool for slice elements V assignable to T
    • Compare function: func(T, T) int for slice elements V assignable to T

Returns:

  • cmp.Option - Configuration option

Less function requirements:

  • Deterministic: less(x, y) == less(x, y)
  • Irreflexive: !less(x, x)
  • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)

Compare function requirements:

  • Deterministic: compare(x, y) == compare(x, y)
  • Irreflexive: compare(x, x) == 0
  • Transitive: if compare(x, y) < 0 and compare(y, z) < 0, then compare(x, z) < 0

Note: Does not need to be "total" - relative order maintained if inequality not reported. Can be used with EquateEmpty.

Example:

a := []int{3, 1, 2}
b := []int{1, 2, 3}

sortInts := cmpopts.SortSlices(func(x, y int) bool {
    return x < y
})

cmp.Equal(a, b, sortInts) // true (sorted before comparison)

Example with structs:

type Person struct {
    Name string
    Age  int
}

people1 := []Person{{Name: "Bob", Age: 30}, {Name: "Alice", Age: 25}}
people2 := []Person{{Name: "Alice", Age: 25}, {Name: "Bob", Age: 30}}

sortByName := cmpopts.SortSlices(func(x, y Person) bool {
    return x.Name < y.Name
})

cmp.Equal(people1, people2, sortByName) // true

SortMaps

func SortMaps(lessOrCompareFunc interface{}) cmp.Option

SortMaps returns a cmp.Transformer option that flattens map[K]V types to sorted []struct{K, V}. Allows cmp.Comparer options to be used on map keys or using K.Equal method if it exists.

Parameters:

  • lessOrCompareFunc interface{} - Either:
    • Less function: func(T, T) bool for map keys K assignable to T
    • Compare function: func(T, T) int for map keys K assignable to T

Returns:

  • cmp.Option - Configuration option

Less function requirements:

  • Deterministic: less(x, y) == less(x, y)
  • Irreflexive: !less(x, x)
  • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
  • Total: if x != y, then either less(x, y) or less(y, x)

Compare function requirements:

  • Deterministic: compare(x, y) == compare(x, y)
  • Irreflexive: compare(x, x) == 0
  • Transitive: if compare(x, y) < 0 and compare(y, z) < 0, then compare(x, z) < 0
  • Total: if x != y, then compare(x, y) != 0

Note: Can be used with EquateEmpty.

Example:

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

sortMapKeys := cmpopts.SortMaps(func(x, y string) bool {
    return x < y
})

cmp.Equal(m1, m2, sortMapKeys) // true (order doesn't matter)

Transformer Options

AcyclicTransformer

func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option

AcyclicTransformer returns a cmp.Transformer with a filter applied that ensures the transformer cannot be recursively applied upon its own output.

Parameters:

  • name string - Name for the transformer
  • xformFunc interface{} - Transformation function

Returns:

  • cmp.Option - Configuration option

Use Case: Prevents infinite cycles when transformer input and output types are the same or when output could be transformed again.

Example:

// Split string by lines - would cause infinite cycle with regular Transformer
splitLines := cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
    return strings.Split(s, "\n")
})

text1 := "line1\nline2\nline3"
text2 := "line1\nline2\nline3"

cmp.Equal(text1, text2, splitLines) // Compares as []string without cycles