go-testdeep: github.com/maxatome/go-testdeep Index | Examples | Files | Directories

package testdeep

import "github.com/maxatome/go-testdeep"

Package testdeep allows extremely flexible deep comparison, built for testing.

It is a go rewrite and adaptation of wonderful Test::Deep perl module (see https://metacpan.org/pod/Test::Deep).

In golang, comparing data structure is usually done using reflect.DeepEqual or using a package that uses this function behind the scene.

This function works very well, but it is not flexible. Both compared structures must match exactly.

The purpose of testdeep package is to do its best to introduce this missing flexibility using "operators" when the expected value (or one of its component) cannot be matched exactly.

Imagine a function returning a struct containing a newly created database record. The Id and the CreatedAt fields are set by the database layer. In this case we have to do something like that to check the record contents:

import (
  "testing"
)

type Record struct {
  Id        uint64
  Name      string
  Age       int
  CreatedAt time.Time
}

func CreateRecord(name string, age int) (*Record, error) {
  ...
}

func TestCreateRecord(t *testing.T) {
  before := time.Now()
  record, err := CreateRecord()

  if err != nil {
    t.Errorf("An error occurred: %s", err)
  } else {
    expected := Record{Name: "Bob", Age: 23}

    if record.Id == 0 {
      t.Error("Id probably not initialized")
    }
    if before.After(record.CreatedAt) ||
      time.Now().Before(record.CreatedAt) {
      t.Errorf("CreatedAt field not expected: %s", record.CreatedAt)
    }
    if record.Name != expected.Name {
      t.Errorf("Name field differ, got=%s, expected=%s",
        record.Name, expected.Name)
    }
    if record.Age != expected.Age {
      t.Errorf("Age field differ, got=%s, expected=%s",
        record.Age, expected.Age)
    }
  }
}

With testdeep, it is a way simple, thanks to CmpDeeply and CmpNoError functions:

import (
  "testing"
  td "github.com/maxatome/go-testdeep"
)

...

func TestCreateRecord(t *testing.T) {
  before := time.Now()
  record, err := CreateRecord()

  if td.CmpNoError(t, err) {
    td.CmpDeeply(t, record,
      Struct(
        &Record{
          Name: "Bob",
          Age:  23,
        },
        td.StructFields{
          "Id":        td.NotZero(),
          "CreatedAt": td.Between(before, time.Now()),
        }),
      "Newly created record")
  }
}

Of course not only structs can be compared. A lot of operators can be found below to cover most (all?) needed tests. See https://godoc.org/github.com/maxatome/go-testdeep#TestDeep

The CmpDeeply function is the keystone of this package, but to make the writing of tests even easier, the family of Cmp* functions are provided and act as shortcuts. Using CmpStruct function, the previous example can be written as:

import (
  "testing"
  td "github.com/maxatome/go-testdeep"
)

...

func TestCreateRecord(t *testing.T) {
  before := time.Now()
  record, err := CreateRecord()

  if td.CmpNoError(t, err) {
    td.CmpStruct(t, record,
      &Record{
        Name: "Bob",
        Age:  23,
      },
      td.StructFields{
        "Id":        td.NotZero(),
        "CreatedAt": td.Between(before, time.Now()),
      },
      "Newly created record")
  }
}

Last, testing.T can be encapsulated in testdeep T type, simplifying again the test:

import (
  "testing"
  td "github.com/maxatome/go-testdeep"
)

...

func TestCreateRecord(tt *testing.T) {
  t := td.NewT(tt)

  before := time.Now()
  record, err := CreateRecord()

  if t.CmpNoError(err) {
    t.RootName("RECORD").Struct(record,
      &Record{
        Name: "Bob",
        Age:  23,
      },
      td.StructFields{
        "Id":        td.NotZero(),
        "CreatedAt": td.Between(before, time.Now()),
      },
      "Newly created record")
  }
}

Code:

t := &testing.T{}

dateToTime := func(str string) time.Time {
    t, err := time.Parse(time.RFC3339, str)
    if err != nil {
        panic(err)
    }
    return t
}

type PetFamily uint8

const (
    Canidae PetFamily = 1
    Felidae PetFamily = 2
)

type Pet struct {
    Name     string
    Birthday time.Time
    Family   PetFamily
}

type Master struct {
    Name         string
    AnnualIncome int
    Pets         []*Pet
}

// Imagine a function returning a Master slice...
masters := []Master{
    {
        Name:         "Bob Smith",
        AnnualIncome: 25000,
        Pets: []*Pet{
            {
                Name:     "Quizz",
                Birthday: dateToTime("2010-11-05T10:00:00Z"),
                Family:   Canidae,
            },
            {
                Name:     "Charlie",
                Birthday: dateToTime("2013-05-11T08:00:00Z"),
                Family:   Canidae,
            },
        },
    },
    {
        Name:         "John Doe",
        AnnualIncome: 38000,
        Pets: []*Pet{
            {
                Name:     "Coco",
                Birthday: dateToTime("2015-08-05T18:00:00Z"),
                Family:   Felidae,
            },
            {
                Name:     "Lucky",
                Birthday: dateToTime("2014-04-17T07:00:00Z"),
                Family:   Canidae,
            },
        },
    },
}

// Let's check masters slice contents
ok := CmpDeeply(t, masters, All(
    Len(Gt(0)), // len(masters) should be > 0
    ArrayEach(
        // For each Master
        Struct(Master{}, StructFields{
            // Master Name should be composed of 2 words, with 1st letter uppercased
            "Name": Re(`^[A-Z][a-z]+ [A-Z][a-z]+\z`),
            // Annual income should be greater than $10000
            "AnnualIncome": Gt(10000),
            "Pets": ArrayEach(
                // For each Pet
                Struct(&Pet{}, StructFields{
                    // Pet Name should be composed of 1 word, with 1st letter uppercased
                    "Name": Re(`^[A-Z][a-z]+\z`),
                    "Birthday": All(
                        // Pet should be born after 2010, January 1st, but before now!
                        Between(dateToTime("2010-01-01T00:00:00Z"), time.Now()),
                        // AND minutes, seconds and nanoseconds should be 0
                        Code(func(t time.Time) bool {
                            return t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0
                        }),
                    ),
                    // Only dogs and cats allowed
                    "Family": Any(Canidae, Felidae),
                }),
            ),
        }),
    ),
))
fmt.Println(ok)

Output:

true

Index

Examples

Package Files

cmp_deeply.go cmp_funcs.go cmp_funcs_misc.go config.go equal.go t.go t_struct.go td_all.go td_any.go td_array.go td_array_each.go td_bag.go td_between.go td_code.go td_contains.go td_contains_key.go td_empty.go td_expected_type.go td_ignore.go td_isa.go td_len_cap.go td_list.go td_map.go td_map_each.go td_nan.go td_nil.go td_none.go td_ptr.go td_re.go td_set.go td_set_base.go td_set_result.go td_shallow.go td_smuggle.go td_smuggler_base.go td_string.go td_struct.go td_trunc_time.go td_zero.go testdeep.go types.go utils.go

Variables

var DefaultContextConfig = ContextConfig{
    RootName:       contextDefaultRootName,
    MaxErrors:      getMaxErrorsFromEnv(),
    FailureIsFatal: false,
}

DefaultContextConfig is the default configuration used to render tests failures. If overridden, new settings will impact all Cmp* functions and *T methods (if not specifically configured.)

func CmpAll Uses

func CmpAll(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool

CmpAll is a shortcut for:

CmpDeeply(t, got, All(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#All for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foo/bar"

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "foo/bar" string
ok := CmpAll(t, got, []interface{}{Re("o/b"), HasSuffix("bar"), "foo/bar"},
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "fooX/Ybar" string
ok = CmpAll(t, got, []interface{}{Re("o/b"), HasSuffix("bar"), "fooX/Ybar"},
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func CmpAny Uses

func CmpAny(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool

CmpAny is a shortcut for:

CmpDeeply(t, got, Any(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Any for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foo/bar"

// Checks got string against:
//   "zip" regexp *OR* "bar" suffix
ok := CmpAny(t, got, []interface{}{Re("zip"), HasSuffix("bar")},
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "zip" regexp *OR* "foo" suffix
ok = CmpAny(t, got, []interface{}{Re("zip"), HasSuffix("foo")},
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func CmpArray Uses

func CmpArray(t TestingT, got interface{}, model interface{}, expectedEntries ArrayEntries, args ...interface{}) bool

CmpArray is a shortcut for:

CmpDeeply(t, got, Array(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Array for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := [3]int{42, 58, 26}

ok := CmpArray(t, got, [3]int{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks array %v", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := CmpArray(t, got, MyArray{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks typed array %v", got)
fmt.Println(ok)

ok = CmpArray(t, &got, &MyArray{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = CmpArray(t, &got, &MyArray{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = CmpArray(t, &got, (*MyArray)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func CmpArrayEach Uses

func CmpArrayEach(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool

CmpArrayEach is a shortcut for:

CmpDeeply(t, got, ArrayEach(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ArrayEach for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := [3]int{42, 58, 26}

ok := CmpArrayEach(t, got, Between(25, 60),
    "checks each item of array %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := []int{42, 58, 26}

ok := CmpArrayEach(t, got, Between(25, 60),
    "checks each item of slice %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := CmpArrayEach(t, got, Between(25, 60),
    "checks each item of typed array %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = CmpArrayEach(t, &got, Between(25, 60),
    "checks each item of typed array pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

type MySlice []int

got := MySlice{42, 58, 26}

ok := CmpArrayEach(t, got, Between(25, 60),
    "checks each item of typed slice %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = CmpArrayEach(t, &got, Between(25, 60),
    "checks each item of typed slice pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

func CmpBag Uses

func CmpBag(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpBag is a shortcut for:

CmpDeeply(t, got, Bag(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Bag for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present
ok := CmpBag(t, got, []interface{}{1, 1, 2, 3, 5, 8, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Does not match as got contains 2 times 1 and 8, and these
// duplicates are not expected
ok = CmpBag(t, got, []interface{}{1, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 8, 2}

// Duplicates of 1 and 8 are expected but not present in got
ok = CmpBag(t, got, []interface{}{1, 1, 2, 3, 5, 8, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Matches as all items are present
ok = CmpBag(t, got, []interface{}{1, 2, 3, 5, Gt(7)},
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
false
false
true

func CmpBetween Uses

func CmpBetween(t TestingT, got interface{}, from interface{}, to interface{}, bounds BoundsKind, args ...interface{}) bool

CmpBetween is a shortcut for:

CmpDeeply(t, got, Between(from, to, bounds), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Between for details.

Between() optional parameter "bounds" is here mandatory. BoundsInIn value should be passed to mimic its absence in original Between() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 156

ok := CmpBetween(t, got, 154, 156, BoundsInIn,
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = CmpBetween(t, got, 154, 156, BoundsInIn,
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

ok = CmpBetween(t, got, 154, 156, BoundsInOut,
    "checks %v is in [154 .. 156[", got)
fmt.Println(ok)

ok = CmpBetween(t, got, 154, 156, BoundsOutIn,
    "checks %v is in ]154 .. 156]", got)
fmt.Println(ok)

ok = CmpBetween(t, got, 154, 156, BoundsOutOut,
    "checks %v is in ]154 .. 156[", got)
fmt.Println(ok)

Output:

true
true
false
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpBetween(t, got, "aaa", "abc", BoundsInIn,
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = CmpBetween(t, got, "aaa", "abc", BoundsInIn,
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = CmpBetween(t, got, "aaa", "abc", BoundsInOut,
    `checks "%v" is in ["aaa" .. "abc"[`, got)
fmt.Println(ok)

ok = CmpBetween(t, got, "aaa", "abc", BoundsOutIn,
    `checks "%v" is in ]"aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = CmpBetween(t, got, "aaa", "abc", BoundsOutOut,
    `checks "%v" is in ]"aaa" .. "abc"[`, got)
fmt.Println(ok)

Output:

true
true
false
true
false

func CmpCap Uses

func CmpCap(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpCap is a shortcut for:

CmpDeeply(t, got, Cap(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Cap for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := make([]int, 0, 12)

ok := CmpCap(t, got, 12, "checks %v capacity is 12", got)
fmt.Println(ok)

ok = CmpCap(t, got, 0, "checks %v capacity is 0", got)
fmt.Println(ok)

got = nil

ok = CmpCap(t, got, 0, "checks %v capacity is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := make([]int, 0, 12)

ok := CmpCap(t, got, Between(10, 12),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

ok = CmpCap(t, got, Gt(10),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

Output:

true
true

func CmpCode Uses

func CmpCode(t TestingT, got interface{}, fn interface{}, args ...interface{}) bool

CmpCode is a shortcut for:

CmpDeeply(t, got, Code(fn), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Code for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "12"

ok := CmpCode(t, got, func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason
ok = CmpCode(t, got, func(num string) (bool, string) {
    n, err := strconv.Atoi(num)
    if err != nil {
        return false, "not a number"
    }
    if n > 10 && n < 100 {
        return true, ""
    }
    return false, "not in ]10 .. 100["
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason thanks to error
ok = CmpCode(t, got, func(num string) error {
    n, err := strconv.Atoi(num)
    if err != nil {
        return err
    }
    if n > 10 && n < 100 {
        return nil
    }
    return fmt.Errorf("%d not in ]10 .. 100[", n)
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

Output:

true
true
true

func CmpContains Uses

func CmpContains(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool

CmpContains is a shortcut for:

CmpDeeply(t, got, Contains(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Contains for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpContains(t, [...]int{11, 22, 33, 44}, 22)
fmt.Println("array contains 22:", ok)

ok = CmpContains(t, [...]int{11, 22, 33, 44}, Between(20, 25))
fmt.Println("array contains at least one item in [20 .. 25]:", ok)

ok = CmpContains(t, []int{11, 22, 33, 44}, 22)
fmt.Println("slice contains 22:", ok)

ok = CmpContains(t, []int{11, 22, 33, 44}, Between(20, 25))
fmt.Println("slice contains at least one item in [20 .. 25]:", ok)

Output:

array contains 22: true
array contains at least one item in [20 .. 25]: true
slice contains 22: true
slice contains at least one item in [20 .. 25]: true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpContains(t, got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpContains(t, got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpContains(t, got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = CmpContains(t, got, Between('n', 'p'), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

Code:

t := &testing.T{}

ok := CmpContains(t, map[string]int{"foo": 11, "bar": 22, "zip": 33}, 22)
fmt.Println("map contains value 22:", ok)

ok = CmpContains(t, map[string]int{"foo": 11, "bar": 22, "zip": 33}, Between(20, 25))
fmt.Println("map contains at least one value in [20 .. 25]:", ok)

Output:

map contains value 22: true
map contains at least one value in [20 .. 25]: true

Code:

t := &testing.T{}

num := 123
got := [...]*int{&num, nil}

ok := CmpContains(t, got, nil)
fmt.Println("array contains untyped nil:", ok)

ok = CmpContains(t, got, (*int)(nil))
fmt.Println("array contains *int nil:", ok)

ok = CmpContains(t, got, Nil())
fmt.Println("array contains Nil():", ok)

ok = CmpContains(t, got, (*byte)(nil))
fmt.Println("array contains *byte nil:", ok) // types differ: *byte ≠ *int

Output:

array contains untyped nil: true
array contains *int nil: true
array contains Nil(): true
array contains *byte nil: false

Code:

t := &testing.T{}

got := "foobar"

ok := CmpContains(t, got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpContains(t, got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpContains(t, got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

ok = CmpContains(t, got, Between('n', 'p'), "checks %s", got)
fmt.Println("contains at least one character ['n' .. 'p']:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
contains at least one character ['n' .. 'p']: true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpContains(t, got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpContains(t, got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpContains(t, got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = CmpContains(t, got, Between('n', 'p'), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

func CmpContainsKey Uses

func CmpContainsKey(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool

CmpContainsKey is a shortcut for:

CmpDeeply(t, got, ContainsKey(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ContainsKey for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpContainsKey(t, map[string]int{"foo": 11, "bar": 22, "zip": 33}, "foo")
fmt.Println(`map contains key "foo":`, ok)

ok = CmpContainsKey(t, map[int]bool{12: true, 24: false, 42: true, 51: false}, Between(40, 50))
fmt.Println("map contains at least a key in [40 .. 50]:", ok)

Output:

map contains key "foo": true
map contains at least a key in [40 .. 50]: true

Code:

t := &testing.T{}

num := 1234
got := map[*int]bool{&num: false, nil: true}

ok := CmpContainsKey(t, got, nil)
fmt.Println("map contains untyped nil key:", ok)

ok = CmpContainsKey(t, got, (*int)(nil))
fmt.Println("map contains *int nil key:", ok)

ok = CmpContainsKey(t, got, Nil())
fmt.Println("map contains Nil() key:", ok)

ok = CmpContainsKey(t, got, (*byte)(nil))
fmt.Println("map contains *byte nil key:", ok) // types differ: *byte ≠ *int

Output:

map contains untyped nil key: true
map contains *int nil key: true
map contains Nil() key: true
map contains *byte nil key: false

func CmpDeeply Uses

func CmpDeeply(t TestingT, got, expected interface{},
    args ...interface{}) bool

CmpDeeply returns true if "got" matches "expected". "expected" can be the same type as "got" is, or contains some TestDeep operators. If "got" does not match "expected", it returns false and the reason of failure is logged with the help of "t" Error() method.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

func CmpEmpty Uses

func CmpEmpty(t TestingT, got interface{}, args ...interface{}) bool

CmpEmpty is a shortcut for:

CmpDeeply(t, got, Empty(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Empty for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpEmpty(t, nil) // special case: nil is considered empty
fmt.Println(ok)

// fails, typed nil is not empty (expect for channel, map, slice or
// pointers on array, channel, map slice and strings)
ok = CmpEmpty(t, (*int)(nil))
fmt.Println(ok)

ok = CmpEmpty(t, "")
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use Zero() instead
ok = CmpEmpty(t, 0)
fmt.Println(ok)

ok = CmpEmpty(t, (map[string]int)(nil))
fmt.Println(ok)

ok = CmpEmpty(t, map[string]int{})
fmt.Println(ok)

ok = CmpEmpty(t, ([]int)(nil))
fmt.Println(ok)

ok = CmpEmpty(t, []int{})
fmt.Println(ok)

ok = CmpEmpty(t, []int{3}) // fails, as not empty
fmt.Println(ok)

ok = CmpEmpty(t, [3]int{}) // fails, Empty() is not Zero()!
fmt.Println(ok)

Output:

true
false
true
false
true
true
true
true
false
false

Code:

t := &testing.T{}

type MySlice []int

ok := CmpEmpty(t, MySlice{}) // Ptr() not needed
fmt.Println(ok)

ok = CmpEmpty(t, &MySlice{})
fmt.Println(ok)

l1 := &MySlice{}
l2 := &l1
l3 := &l2
ok = CmpEmpty(t, &l3)
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = CmpEmpty(t, &MyStruct{}) // fails, use Zero() instead
fmt.Println(ok)

Output:

true
true
true
false

func CmpError Uses

func CmpError(t TestingT, got error, args ...interface{}) bool

CmpError checks that "got" is non-nil error.

_, err := MyFunction(1, 2, 3)
CmpError(t, err, "MyFunction(1, 2, 3) should return an error")

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := fmt.Errorf("Error #%d", 42)
ok := CmpError(t, got, "An error occurred")
fmt.Println(ok)

got = nil
ok = CmpError(t, got, "An error occurred") // fails
fmt.Println(ok)

Output:

true
false

func CmpFalse Uses

func CmpFalse(t TestingT, got interface{}, args ...interface{}) bool

CmpFalse is a shortcut for:

CmpDeeply(t, got, false, args...)

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := false
ok := CmpFalse(t, got, "check that got is false!")
fmt.Println(ok)

got = true
ok = CmpFalse(t, got, "check that got is false!")
fmt.Println(ok)

Output:

true
false

func CmpGt Uses

func CmpGt(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpGt is a shortcut for:

CmpDeeply(t, got, Gt(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Gt for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 156

ok := CmpGt(t, got, 155, "checks %v is > 155", got)
fmt.Println(ok)

ok = CmpGt(t, got, 156, "checks %v is > 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpGt(t, got, "abb", `checks "%v" is > "abb"`, got)
fmt.Println(ok)

ok = CmpGt(t, got, "abc", `checks "%v" is > "abc"`, got)
fmt.Println(ok)

Output:

true
false

func CmpGte Uses

func CmpGte(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpGte is a shortcut for:

CmpDeeply(t, got, Gte(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Gte for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 156

ok := CmpGte(t, got, 156, "checks %v is ≥ 156", got)
fmt.Println(ok)

ok = CmpGte(t, got, 155, "checks %v is ≥ 155", got)
fmt.Println(ok)

ok = CmpGte(t, got, 157, "checks %v is ≥ 157", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpGte(t, got, "abc", `checks "%v" is ≥ "abc"`, got)
fmt.Println(ok)

ok = CmpGte(t, got, "abb", `checks "%v" is ≥ "abb"`, got)
fmt.Println(ok)

ok = CmpGte(t, got, "abd", `checks "%v" is ≥ "abd"`, got)
fmt.Println(ok)

Output:

true
true
false

func CmpHasPrefix Uses

func CmpHasPrefix(t TestingT, got interface{}, expected string, args ...interface{}) bool

CmpHasPrefix is a shortcut for:

CmpDeeply(t, got, HasPrefix(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#HasPrefix for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foobar"

ok := CmpHasPrefix(t, got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpHasPrefix(t, got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpHasPrefix(t, got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

func CmpHasSuffix Uses

func CmpHasSuffix(t TestingT, got interface{}, expected string, args ...interface{}) bool

CmpHasSuffix is a shortcut for:

CmpDeeply(t, got, HasSuffix(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#HasSuffix for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foobar"

ok := CmpHasSuffix(t, got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpHasSuffix(t, got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpHasSuffix(t, got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

func CmpIsa Uses

func CmpIsa(t TestingT, got interface{}, model interface{}, args ...interface{}) bool

CmpIsa is a shortcut for:

CmpDeeply(t, got, Isa(model), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Isa for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

type TstStruct struct {
    Field int
}

got := TstStruct{Field: 1}

ok := CmpIsa(t, got, TstStruct{}, "checks got is a TstStruct")
fmt.Println(ok)

ok = CmpIsa(t, got, &TstStruct{},
    "checks got is a pointer on a TstStruct")
fmt.Println(ok)

ok = CmpIsa(t, &got, &TstStruct{},
    "checks &got is a pointer on a TstStruct")
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := bytes.NewBufferString("foobar")

ok := CmpIsa(t, got, (*fmt.Stringer)(nil),
    "checks got implements fmt.Stringer interface")
fmt.Println(ok)

errGot := fmt.Errorf("An error #%d occurred", 123)

ok = CmpIsa(t, errGot, (*error)(nil),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// As nil, is passed below, it is not an interface but nil... So it
// does not match
errGot = nil

ok = CmpIsa(t, errGot, (*error)(nil),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// BUT if its address is passed, now it is OK as the types match
ok = CmpIsa(t, &errGot, (*error)(nil),
    "checks &errGot is a *error or implements error interface")
fmt.Println(ok)

Output:

true
true
false
true

func CmpLen Uses

func CmpLen(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpLen is a shortcut for:

CmpDeeply(t, got, Len(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Len for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := map[int]bool{11: true, 22: false, 33: false}

ok := CmpLen(t, got, 3, "checks %v len is 3", got)
fmt.Println(ok)

ok = CmpLen(t, got, 0, "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = CmpLen(t, got, 0, "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := map[int]bool{11: true, 22: false, 33: false}

ok := CmpLen(t, got, Between(3, 8),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = CmpLen(t, got, Gte(3), "checks %v len is ≥ 3", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

got := []int{11, 22, 33}

ok := CmpLen(t, got, Between(3, 8),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = CmpLen(t, got, Lt(5), "checks %v len is < 5", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

got := []int{11, 22, 33}

ok := CmpLen(t, got, 3, "checks %v len is 3", got)
fmt.Println(ok)

ok = CmpLen(t, got, 0, "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = CmpLen(t, got, 0, "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

func CmpLt Uses

func CmpLt(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpLt is a shortcut for:

CmpDeeply(t, got, Lt(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Lt for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 156

ok := CmpLt(t, got, 157, "checks %v is < 157", got)
fmt.Println(ok)

ok = CmpLt(t, got, 156, "checks %v is < 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpLt(t, got, "abd", `checks "%v" is < "abd"`, got)
fmt.Println(ok)

ok = CmpLt(t, got, "abc", `checks "%v" is < "abc"`, got)
fmt.Println(ok)

Output:

true
false

func CmpLte Uses

func CmpLte(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpLte is a shortcut for:

CmpDeeply(t, got, Lte(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Lte for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 156

ok := CmpLte(t, got, 156, "checks %v is ≤ 156", got)
fmt.Println(ok)

ok = CmpLte(t, got, 157, "checks %v is ≤ 157", got)
fmt.Println(ok)

ok = CmpLte(t, got, 155, "checks %v is ≤ 155", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpLte(t, got, "abc", `checks "%v" is ≤ "abc"`, got)
fmt.Println(ok)

ok = CmpLte(t, got, "abd", `checks "%v" is ≤ "abd"`, got)
fmt.Println(ok)

ok = CmpLte(t, got, "abb", `checks "%v" is ≤ "abb"`, got)
fmt.Println(ok)

Output:

true
true
false

func CmpMap Uses

func CmpMap(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

CmpMap is a shortcut for:

CmpDeeply(t, got, Map(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Map for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpMap(t, got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

ok = CmpMap(t, got, map[string]int{}, MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

ok = CmpMap(t, got, (map[string]int)(nil), MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpMap(t, got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks typed map %v", got)
fmt.Println(ok)

ok = CmpMap(t, &got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = CmpMap(t, &got, &MyMap{}, MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = CmpMap(t, &got, (*MyMap)(nil), MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func CmpMapEach Uses

func CmpMapEach(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool

CmpMapEach is a shortcut for:

CmpDeeply(t, got, MapEach(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#MapEach for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpMapEach(t, got, Between(10, 90),
    "checks each value of map %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpMapEach(t, got, Between(10, 90),
    "checks each value of typed map %v is in [10 .. 90]", got)
fmt.Println(ok)

ok = CmpMapEach(t, &got, Between(10, 90),
    "checks each value of typed map pointer %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true
true

func CmpN Uses

func CmpN(t TestingT, got interface{}, num interface{}, tolerance interface{}, args ...interface{}) bool

CmpN is a shortcut for:

CmpDeeply(t, got, N(num, tolerance), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#N for details.

N() optional parameter "tolerance" is here mandatory. 0 value should be passed to mimic its absence in original N() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 1.12345

ok := CmpN(t, got, 1.1234, 0.00006,
    "checks %v = 1.1234 ± 0.00006", got)
fmt.Println(ok)

Output:

true

func CmpNaN Uses

func CmpNaN(t TestingT, got interface{}, args ...interface{}) bool

CmpNaN is a shortcut for:

CmpDeeply(t, got, NaN(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NaN for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := float32(math.NaN())

ok := CmpNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is float32 not-a-number:", ok)

got = 12

ok = CmpNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is float32 not-a-number:", ok)

Output:

float32(math.NaN()) is float32 not-a-number: true
float32(12) is float32 not-a-number: false

Code:

t := &testing.T{}

got := math.NaN()

ok := CmpNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = CmpNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is not-a-number: true
// float64(12) is not-a-number: false

func CmpNil Uses

func CmpNil(t TestingT, got interface{}, args ...interface{}) bool

CmpNil is a shortcut for:

CmpDeeply(t, got, Nil(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Nil for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

var got fmt.Stringer // interface

// nil value can be compared directly with nil, no need of Nil() here
ok := CmpDeeply(t, got, nil)
fmt.Println(ok)

// But it works with Nil() anyway
ok = CmpNil(t, got)
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with nil fails, as the interface is not nil
ok = CmpDeeply(t, got, nil)
fmt.Println(ok)

// In this case Nil() succeed
ok = CmpNil(t, got)
fmt.Println(ok)

Output:

true
true
false
true

func CmpNoError Uses

func CmpNoError(t TestingT, got error, args ...interface{}) bool

CmpNoError checks that "got" is nil error.

value, err := MyFunction(1, 2, 3)
if CmpNoError(t, err) {
  // one can now check value...
}

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := fmt.Errorf("Error #%d", 42)
ok := CmpNoError(t, got, "An error occurred") // fails
fmt.Println(ok)

got = nil
ok = CmpNoError(t, got, "An error occurred")
fmt.Println(ok)

Output:

false
true

func CmpNone Uses

func CmpNone(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool

CmpNone is a shortcut for:

CmpDeeply(t, got, None(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#None for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 18

ok := CmpNone(t, got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 20

ok = CmpNone(t, got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 142

ok = CmpNone(t, got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

Output:

true
false
false

func CmpNot Uses

func CmpNot(t TestingT, got interface{}, expected interface{}, args ...interface{}) bool

CmpNot is a shortcut for:

CmpDeeply(t, got, Not(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Not for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 42

ok := CmpNot(t, got, 0, "checks %v is non-null", got)
fmt.Println(ok)

ok = CmpNot(t, got, Between(10, 30),
    "checks %v is not in [10 .. 30]", got)
fmt.Println(ok)

got = 0

ok = CmpNot(t, got, 0, "checks %v is non-null", got)
fmt.Println(ok)

Output:

true
true
false

func CmpNotAny Uses

func CmpNotAny(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpNotAny is a shortcut for:

CmpDeeply(t, got, NotAny(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotAny for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{4, 5, 9, 42}

ok := CmpNotAny(t, got, []interface{}{3, 6, 8, 41, 43},
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

ok = CmpNotAny(t, got, []interface{}{3, 6, 8, 42, 43},
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

Output:

true
false

func CmpNotEmpty Uses

func CmpNotEmpty(t TestingT, got interface{}, args ...interface{}) bool

CmpNotEmpty is a shortcut for:

CmpDeeply(t, got, NotEmpty(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotEmpty for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpNotEmpty(t, nil) // fails, as nil is considered empty
fmt.Println(ok)

ok = CmpNotEmpty(t, "foobar")
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use NotZero() instead
ok = CmpNotEmpty(t, 0)
fmt.Println(ok)

ok = CmpNotEmpty(t, map[string]int{"foobar": 42})
fmt.Println(ok)

ok = CmpNotEmpty(t, []int{1})
fmt.Println(ok)

ok = CmpNotEmpty(t, [3]int{}) // succeeds, NotEmpty() is not NotZero()!
fmt.Println(ok)

Output:

false
true
false
true
true
true

Code:

t := &testing.T{}

type MySlice []int

ok := CmpNotEmpty(t, MySlice{12})
fmt.Println(ok)

ok = CmpNotEmpty(t, &MySlice{12}) // Ptr() not needed
fmt.Println(ok)

l1 := &MySlice{12}
l2 := &l1
l3 := &l2
ok = CmpNotEmpty(t, &l3)
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = CmpNotEmpty(t, &MyStruct{}) // fails, use NotZero() instead
fmt.Println(ok)

Output:

true
true
true
false

func CmpNotNaN Uses

func CmpNotNaN(t TestingT, got interface{}, args ...interface{}) bool

CmpNotNaN is a shortcut for:

CmpDeeply(t, got, NotNaN(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotNaN for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := float32(math.NaN())

ok := CmpNotNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is NOT float32 not-a-number:", ok)

got = 12

ok = CmpNotNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is NOT float32 not-a-number:", ok)

Output:

float32(math.NaN()) is NOT float32 not-a-number: false
float32(12) is NOT float32 not-a-number: true

Code:

t := &testing.T{}

got := math.NaN()

ok := CmpNotNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = CmpNotNaN(t, got,
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is NOT not-a-number: false
// float64(12) is NOT not-a-number: true

func CmpNotNil Uses

func CmpNotNil(t TestingT, got interface{}, args ...interface{}) bool

CmpNotNil is a shortcut for:

CmpDeeply(t, got, NotNil(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotNil for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

var got fmt.Stringer = &bytes.Buffer{}

// nil value can be compared directly with Not(nil), no need of NotNil() here
ok := CmpDeeply(t, got, Not(nil))
fmt.Println(ok)

// But it works with NotNil() anyway
ok = CmpNotNil(t, got)
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with Not(nil) succeeds, as the interface is not nil
ok = CmpDeeply(t, got, Not(nil))
fmt.Println(ok)

// In this case NotNil() fails
ok = CmpNotNil(t, got)
fmt.Println(ok)

Output:

true
true
true
false

func CmpNotPanic Uses

func CmpNotPanic(t TestingT, fn func(), args ...interface{}) bool

CmpNotPanic calls "fn" and checks no panic() occurred. If a panic() occurred false is returned then the panic() parameter and the stack trace appear in the test report.

Note that calling panic(nil) in "fn" body is detected as a panic.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpNotPanic(t, func() {}, nil)
fmt.Println("checks a panic DID NOT occur:", ok)

// Classic panic
ok = CmpNotPanic(t, func() { panic("I am panicking!") },
    "Hope it does not panic!")
fmt.Println("still no panic?", ok)

// Can detect panic(nil)
ok = CmpNotPanic(t, func() { panic(nil) }, "Checks for panic(nil)")
fmt.Println("last no panic?", ok)

Output:

checks a panic DID NOT occur: true
still no panic? false
last no panic? false

func CmpNotZero Uses

func CmpNotZero(t TestingT, got interface{}, args ...interface{}) bool

CmpNotZero is a shortcut for:

CmpDeeply(t, got, NotZero(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotZero for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpNotZero(t, 0) // fails
fmt.Println(ok)

ok = CmpNotZero(t, float64(0)) // fails
fmt.Println(ok)

ok = CmpNotZero(t, 12)
fmt.Println(ok)

ok = CmpNotZero(t, (map[string]int)(nil)) // fails, as nil
fmt.Println(ok)

ok = CmpNotZero(t, map[string]int{}) // succeeds, as not nil
fmt.Println(ok)

ok = CmpNotZero(t, ([]int)(nil)) // fails, as nil
fmt.Println(ok)

ok = CmpNotZero(t, []int{}) // succeeds, as not nil
fmt.Println(ok)

ok = CmpNotZero(t, [3]int{}) // fails
fmt.Println(ok)

ok = CmpNotZero(t, [3]int{0, 1}) // succeeds, DATA[1] is not 0
fmt.Println(ok)

ok = CmpNotZero(t, bytes.Buffer{}) // fails
fmt.Println(ok)

ok = CmpNotZero(t, &bytes.Buffer{}) // succeeds, as pointer not nil
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, Ptr(NotZero())) // fails as deref by Ptr()
fmt.Println(ok)

Output:

false
false
true
false
true
false
true
false
true
false
true
false

func CmpPPtr Uses

func CmpPPtr(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpPPtr is a shortcut for:

CmpDeeply(t, got, PPtr(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#PPtr for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

num := 12
got := &num

ok := CmpPPtr(t, &got, 12)
fmt.Println(ok)

ok = CmpPPtr(t, &got, Between(4, 15))
fmt.Println(ok)

Output:

true
true

func CmpPanic Uses

func CmpPanic(t TestingT, fn func(), expectedPanic interface{},
    args ...interface{}) bool

CmpPanic calls "fn" and checks a panic() occurred with the "expectedPanic" parameter. It returns true only if both conditions are fulfilled.

Note that calling panic(nil) in "fn" body is detected as a panic (in this case "expectedPanic" has to be nil.)

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpPanic(t,
    func() { panic("I am panicking!") }, "I am panicking!",
    "Checks for panic")
fmt.Println("checks exact panic() string:", ok)

// Can use TestDeep operator too
ok = CmpPanic(t,
    func() { panic("I am panicking!") }, Contains("panicking!"),
    "Checks for panic")
fmt.Println("checks panic() sub-string:", ok)

// Can detect panic(nil)
ok = CmpPanic(t, func() { panic(nil) }, nil, "Checks for panic(nil)")
fmt.Println("checks for panic(nil):", ok)

// As well as structured data panic
type PanicStruct struct {
    Error string
    Code  int
}

ok = CmpPanic(t,
    func() {
        panic(PanicStruct{Error: "Memory violation", Code: 11})
    },
    PanicStruct{
        Error: "Memory violation",
        Code:  11,
    })
fmt.Println("checks exact panic() struct:", ok)

// or combined with TestDeep operators too
ok = CmpPanic(t,
    func() {
        panic(PanicStruct{Error: "Memory violation", Code: 11})
    },
    Struct(PanicStruct{}, StructFields{
        "Code": Between(10, 20),
    }))
fmt.Println("checks panic() struct against TestDeep operators:", ok)

// Of course, do not panic = test failure, even for expected nil
// panic parameter
ok = CmpPanic(t, func() {}, nil)
fmt.Println("checks a panic occurred:", ok)

Output:

checks exact panic() string: true
checks panic() sub-string: true
checks for panic(nil): true
checks exact panic() struct: true
checks panic() struct against TestDeep operators: true
checks a panic occurred: false

func CmpPtr Uses

func CmpPtr(t TestingT, got interface{}, val interface{}, args ...interface{}) bool

CmpPtr is a shortcut for:

CmpDeeply(t, got, Ptr(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Ptr for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := 12

ok := CmpPtr(t, &got, 12)
fmt.Println(ok)

ok = CmpPtr(t, &got, Between(4, 15))
fmt.Println(ok)

Output:

true
true

func CmpRe Uses

func CmpRe(t TestingT, got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool

CmpRe is a shortcut for:

CmpDeeply(t, got, Re(reg, capture), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Re for details.

Re() optional parameter "capture" is here mandatory. nil value should be passed to mimic its absence in original Re() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foo bar"
ok := CmpRe(t, got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = CmpRe(t, got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "foo bar biz"
ok := CmpRe(t, got, `^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = CmpRe(t, got, `^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

got := "foo bar"
ok := CmpRe(t, got, expected, nil, "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = CmpRe(t, got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`^(\w+) (\w+) (\w+)$`)

got := "foo bar biz"
ok := CmpRe(t, got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = CmpRe(t, got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

got := errors.New("foo bar")
ok := CmpRe(t, got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := CmpRe(t, got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foo bar")
ok := CmpRe(t, got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := CmpRe(t, got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

func CmpReAll Uses

func CmpReAll(t TestingT, got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool

CmpReAll is a shortcut for:

CmpDeeply(t, got, ReAll(reg, capture), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ReAll for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foo bar biz"
ok := CmpReAll(t, got, `(\w+)`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = CmpReAll(t, got, `(\w+)`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "11 45 23 56 85 96"
ok := CmpReAll(t, got, `(\d+)`, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = CmpReAll(t, got, `(\d+)`, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 20 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`(\w+)`)

got := "foo bar biz"
ok := CmpReAll(t, got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = CmpReAll(t, got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`(\d+)`)

got := "11 45 23 56 85 96"
ok := CmpReAll(t, got, expected, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = CmpReAll(t, got, expected, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 20 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func CmpSet Uses

func CmpSet(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpSet is a shortcut for:

CmpDeeply(t, got, Set(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Set for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present, ignoring duplicates
ok := CmpSet(t, got, []interface{}{1, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Duplicates are ignored in a Set
ok = CmpSet(t, got, []interface{}{1, 2, 2, 2, 2, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several Set entries
ok = CmpSet(t, got, []interface{}{Between(1, 4), 3, Between(2, 10)},
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
true
true

func CmpShallow Uses

func CmpShallow(t TestingT, got interface{}, expectedPtr interface{}, args ...interface{}) bool

CmpShallow is a shortcut for:

CmpDeeply(t, got, Shallow(expectedPtr), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Shallow for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

type MyStruct struct {
    Value int
}
data := MyStruct{Value: 12}
got := &data

ok := CmpShallow(t, got, &data,
    "checks pointers only, not contents")
fmt.Println(ok)

// Same contents, but not same pointer
ok = CmpShallow(t, got, &MyStruct{Value: 12},
    "checks pointers only, not contents")
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

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

ok := CmpShallow(t, a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpShallow(t, b, back)
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

Code:

t := &testing.T{}

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := CmpShallow(t, a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpShallow(t, b, a)
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

func CmpSlice Uses

func CmpSlice(t TestingT, got interface{}, model interface{}, expectedEntries ArrayEntries, args ...interface{}) bool

CmpSlice is a shortcut for:

CmpDeeply(t, got, Slice(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Slice for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{42, 58, 26}

ok := CmpSlice(t, got, []int{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

ok = CmpSlice(t, got, []int{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

ok = CmpSlice(t, got, ([]int)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := &testing.T{}

type MySlice []int

got := MySlice{42, 58, 26}

ok := CmpSlice(t, got, MySlice{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks typed slice %v", got)
fmt.Println(ok)

ok = CmpSlice(t, &got, &MySlice{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = CmpSlice(t, &got, &MySlice{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = CmpSlice(t, &got, (*MySlice)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func CmpSmuggle Uses

func CmpSmuggle(t TestingT, got interface{}, fn interface{}, expectedValue interface{}, args ...interface{}) bool

CmpSmuggle is a shortcut for:

CmpDeeply(t, got, Smuggle(fn, expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Smuggle for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

// No end date but a start date and a duration
type StartDuration struct {
    StartDate time.Time
    Duration  time.Duration
}

// Checks that end date is between 17th and 19th February both at 0h
// for each of these durations in hours

for _, duration := range []time.Duration{48, 72, 96} {
    got := StartDuration{
        StartDate: time.Date(2018, time.February, 14, 12, 13, 14, 0, time.UTC),
        Duration:  duration * time.Hour,
    }

    // Simplest way, but in case of Between() failure, error will be bound
    // to DATA<smuggled>, not very clear...
    ok := CmpSmuggle(t, got, func(sd StartDuration) time.Time {
        return sd.StartDate.Add(sd.Duration)
    }, Between(
        time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
        time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))
    fmt.Println(ok)

    // Name the computed value "ComputedEndDate" to render a Between() failure
    // more understandable, so error will be bound to DATA.ComputedEndDate
    ok = CmpSmuggle(t, got, func(sd StartDuration) SmuggledGot {
        return SmuggledGot{
            Name: "ComputedEndDate",
            Got:  sd.StartDate.Add(sd.Duration),
        }
    }, Between(
        time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
        time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))
    fmt.Println(ok)
}

Output:

false
false
true
true
true
true

Code:

t := &testing.T{}

got := int64(123)

ok := CmpSmuggle(t, got, func(n int64) int { return int(n) }, 123,
    "checks int64 got against an int value")
fmt.Println(ok)

ok = CmpSmuggle(t, "123", func(numStr string) (int, bool) {
    n, err := strconv.Atoi(numStr)
    return n, err == nil
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = CmpSmuggle(t, "123", func(numStr string) (int, bool, string) {
    n, err := strconv.Atoi(numStr)
    if err != nil {
        return 0, false, "string must contain a number"
    }
    return n, true, ""
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = CmpSmuggle(t, "123", func(numStr string) (int, error) {
    return strconv.Atoi(numStr)
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

// Short version :)
ok = CmpSmuggle(t, "123", strconv.Atoi, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

Output:

true
true
true
true
true

Code:

t := &testing.T{}

gotTime, err := time.Parse(time.RFC3339, "2018-05-23T12:13:14Z")
if err != nil {
    t.Fatal(err)
}

// Do not check the struct itself, but its stringified form
ok := CmpSmuggle(t, gotTime, func(s fmt.Stringer) string {
    return s.String()
}, "2018-05-23 12:13:14 +0000 UTC")
fmt.Println("stringified time.Time OK:", ok)

// If got does not implement the fmt.Stringer interface, it fails
// without calling the Smuggle func
type MyTime time.Time
ok = CmpSmuggle(t, MyTime(gotTime), func(s fmt.Stringer) string {
    fmt.Println("Smuggle func called!")
    return s.String()
}, "2018-05-23 12:13:14 +0000 UTC")
fmt.Println("stringified MyTime OK:", ok)

// Output
// stringified time.Time OK: true
// stringified MyTime OK: false

Code:

t := &testing.T{}

// got is an int16 and Smuggle func input is an int64: it is OK
got := int(123)

ok := CmpSmuggle(t, got, func(n int64) uint32 { return uint32(n) }, uint32(123))
fmt.Println("got int16(123) → smuggle via int64 → uint32(123):", ok)

Output:

got int16(123) → smuggle via int64 → uint32(123): true

func CmpString Uses

func CmpString(t TestingT, got interface{}, expected string, args ...interface{}) bool

CmpString is a shortcut for:

CmpDeeply(t, got, String(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#String for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := "foobar"

ok := CmpString(t, got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpString(t, got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpString(t, got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

func CmpStruct Uses

func CmpStruct(t TestingT, got interface{}, model interface{}, expectedFields StructFields, args ...interface{}) bool

CmpStruct is a shortcut for:

CmpDeeply(t, got, Struct(model, expectedFields), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Struct for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

type Person struct {
    Name        string
    Age         int
    NumChildren int
}

got := Person{
    Name:        "Foobar",
    Age:         42,
    NumChildren: 3,
}

// As NumChildren is zero in Struct() call, it is not checked
ok := CmpStruct(t, got, Person{Name: "Foobar"}, StructFields{
    "Age": Between(40, 50),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Model can be empty
ok = CmpStruct(t, got, Person{}, StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Works with pointers too
ok = CmpStruct(t, &got, &Person{}, StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Model does not need to be instanciated
ok = CmpStruct(t, &got, (*Person)(nil), StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

Output:

true
true
true
true

func CmpSubBagOf Uses

func CmpSubBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpSubBagOf is a shortcut for:

CmpDeeply(t, got, SubBagOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubBagOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpSubBagOf(t, got, []interface{}{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 8, 9, 9},
    "checks at least all items are present, in any order")
fmt.Println(ok)

// got contains one 8 too many
ok = CmpSubBagOf(t, got, []interface{}{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 9, 9},
    "checks at least all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 2}

ok = CmpSubBagOf(t, got, []interface{}{Between(0, 3), Between(0, 3), Between(0, 3), Between(0, 3), Gt(4), Gt(4)},
    "checks at least all items match, in any order with TestDeep operators")
fmt.Println(ok)

Output:

true
false
true

func CmpSubMapOf Uses

func CmpSubMapOf(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

CmpSubMapOf is a shortcut for:

CmpDeeply(t, got, SubMapOf(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubMapOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42}

ok := CmpSubMapOf(t, got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42}

ok := CmpSubMapOf(t, got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks typed map %v is included in expected keys/values", got)
fmt.Println(ok)

ok = CmpSubMapOf(t, &got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks pointed typed map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true
true

func CmpSubSetOf Uses

func CmpSubSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpSubSetOf is a shortcut for:

CmpDeeply(t, got, SubSetOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubSetOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are expected, ignoring duplicates
ok := CmpSubSetOf(t, got, []interface{}{1, 2, 3, 4, 5, 6, 7, 8},
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several SubSetOf entries
ok = CmpSubSetOf(t, got, []interface{}{Between(1, 4), 3, Between(2, 10), Gt(100)},
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

Output:

true
true

func CmpSuperBagOf Uses

func CmpSuperBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpSuperBagOf is a shortcut for:

CmpDeeply(t, got, SuperBagOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperBagOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpSuperBagOf(t, got, []interface{}{8, 5, 8},
    "checks the items are present, in any order")
fmt.Println(ok)

ok = CmpSuperBagOf(t, got, []interface{}{Gt(5), Lte(2)},
    "checks at least 2 items of %v match", got)
fmt.Println(ok)

Output:

true
true

func CmpSuperMapOf Uses

func CmpSuperMapOf(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

CmpSuperMapOf is a shortcut for:

CmpDeeply(t, got, SuperMapOf(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperMapOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpSuperMapOf(t, got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpSuperMapOf(t, got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks typed map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

ok = CmpSuperMapOf(t, &got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks pointed typed map %v contains at leat all expected keys/values",
    got)
fmt.Println(ok)

Output:

true
true

func CmpSuperSetOf Uses

func CmpSuperSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool

CmpSuperSetOf is a shortcut for:

CmpDeeply(t, got, SuperSetOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperSetOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpSuperSetOf(t, got, []interface{}{1, 2, 3},
    "checks the items are present, in any order and ignoring duplicates")
fmt.Println(ok)

ok = CmpSuperSetOf(t, got, []interface{}{Gt(5), Lte(2)},
    "checks at least 2 items of %v match ignoring duplicates", got)
fmt.Println(ok)

Output:

true
true

func CmpTrue Uses

func CmpTrue(t TestingT, got interface{}, args ...interface{}) bool

CmpTrue is a shortcut for:

CmpDeeply(t, got, true, args...)

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

got := true
ok := CmpTrue(t, got, "check that got is true!")
fmt.Println(ok)

got = false
ok = CmpTrue(t, got, "check that got is true!")
fmt.Println(ok)

Output:

true
false

func CmpTruncTime Uses

func CmpTruncTime(t TestingT, got interface{}, expectedTime interface{}, trunc time.Duration, args ...interface{}) bool

CmpTruncTime is a shortcut for:

CmpDeeply(t, got, TruncTime(expectedTime, trunc), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#TruncTime for details.

TruncTime() optional parameter "trunc" is here mandatory. 0 value should be passed to mimic its absence in original TruncTime() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

dateToTime := func(str string) time.Time {
    t, err := time.Parse(time.RFC3339Nano, str)
    if err != nil {
        panic(err)
    }
    return t
}

got := dateToTime("2018-05-01T12:45:53.123456789Z")

// Compare dates ignoring nanoseconds and monotonic parts
expected := dateToTime("2018-05-01T12:45:53Z")
ok := CmpTruncTime(t, got, expected, time.Second,
    "checks date %v, truncated to the second", got)
fmt.Println(ok)

// Compare dates ignoring time and so monotonic parts
expected = dateToTime("2018-05-01T11:22:33.444444444Z")
ok = CmpTruncTime(t, got, expected, 24*time.Hour,
    "checks date %v, truncated to the day", got)
fmt.Println(ok)

// Compare dates exactly but ignoring monotonic part
expected = dateToTime("2018-05-01T12:45:53.123456789Z")
ok = CmpTruncTime(t, got, expected, 0,
    "checks date %v ignoring monotonic part", got)
fmt.Println(ok)

Output:

true
true
true

func CmpZero Uses

func CmpZero(t TestingT, got interface{}, args ...interface{}) bool

CmpZero is a shortcut for:

CmpDeeply(t, got, Zero(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Zero for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := &testing.T{}

ok := CmpZero(t, 0)
fmt.Println(ok)

ok = CmpZero(t, float64(0))
fmt.Println(ok)

ok = CmpZero(t, 12) // fails, as 12 is not 0 :)
fmt.Println(ok)

ok = CmpZero(t, (map[string]int)(nil))
fmt.Println(ok)

ok = CmpZero(t, map[string]int{}) // fails, as not nil
fmt.Println(ok)

ok = CmpZero(t, ([]int)(nil))
fmt.Println(ok)

ok = CmpZero(t, []int{}) // fails, as not nil
fmt.Println(ok)

ok = CmpZero(t, [3]int{})
fmt.Println(ok)

ok = CmpZero(t, [3]int{0, 1}) // fails, DATA[1] is not 0
fmt.Println(ok)

ok = CmpZero(t, bytes.Buffer{})
fmt.Println(ok)

ok = CmpZero(t, &bytes.Buffer{}) // fails, as pointer not nil
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, Ptr(Zero())) // OK with the help of Ptr()
fmt.Println(ok)

Output:

true
true
false
true
false
true
false
true
false
true
false
true

func EqDeeply Uses

func EqDeeply(got, expected interface{}) bool

EqDeeply returns true if "got" matches "expected". "expected" can be the same type as "got" is, or contains some TestDeep operators.

Code:

type MyStruct struct {
    Name  string
    Num   int
    Items []int
}

got := &MyStruct{
    Name:  "Foobar",
    Num:   12,
    Items: []int{4, 5, 9, 3, 8},
}

if EqDeeply(got,
    Struct(&MyStruct{},
        StructFields{
            "Name":  Re("^Foo"),
            "Num":   Between(10, 20),
            "Items": ArrayEach(Between(3, 9)),
        })) {
    fmt.Println("Match!")
} else {
    fmt.Println("NO!")
}

Output:

Match!

func EqDeeplyError Uses

func EqDeeplyError(got, expected interface{}) error

EqDeeplyError returns nil if "got" matches "expected". "expected" can be the same type as got is, or contains some TestDeep operators. If "got" does not match "expected", the returned *ctxerr.Error contains the reason of the first mismatch detected.

Code:

//
type MyStruct struct {
    Name  string
    Num   int
    Items []int
}

got := &MyStruct{
    Name:  "Foobar",
    Num:   12,
    Items: []int{4, 5, 9, 3, 8},
}

err := EqDeeplyError(got,
    Struct(&MyStruct{},
        StructFields{
            "Name":  Re("^Foo"),
            "Num":   Between(10, 20),
            "Items": ArrayEach(Between(3, 8)),
        }))
if err != nil {
    fmt.Println(err)
}

Output:

DATA.Items[2]: values differ
	     got: 9
	expected: 3 ≤ got ≤ 8
[under TestDeep operator Between at example.go:18]

type ArrayEntries Uses

type ArrayEntries map[int]interface{}

ArrayEntries allows to pass array or slice entries to check in functions Array and Slice. It is a map whose each key is the item index and the corresponding value the expected item value (which can be a TestDeep operator as well as a zero value.)

type Base Uses

type Base struct {
    types.TestDeepStamp
    // contains filtered or unexported fields
}

Base is a base type providing some methods needed by the TestDeep interface.

func NewBase Uses

func NewBase(callDepth int) (b Base)

NewBase returns a new Base struct with location.Location set to the "callDepth" depth.

func (*Base) GetLocation Uses

func (t *Base) GetLocation() location.Location

GetLocation returns a copy of the location.Location where the TestDeep operator has been created.

func (Base) HandleInvalid Uses

func (t Base) HandleInvalid() bool

HandleInvalid tells testdeep internals that this operator does not handle nil values directly.

func (Base) TypeBehind Uses

func (t Base) TypeBehind() reflect.Type

TypeBehind returns the type handled by the operator. Only few operators knows the type they are handling. If they do not know, nil is returned.

type BaseOKNil Uses

type BaseOKNil struct {
    Base
}

BaseOKNil is a base type providing some methods needed by the TestDeep interface, for operators handling nil values.

func NewBaseOKNil Uses

func NewBaseOKNil(callDepth int) (b BaseOKNil)

NewBaseOKNil returns a new BaseOKNil struct with location.Location set to the "callDepth" depth.

func (BaseOKNil) HandleInvalid Uses

func (t BaseOKNil) HandleInvalid() bool

HandleInvalid tells testdeep internals that this operator handles nil values directly.

type BoundsKind Uses

type BoundsKind uint8

BoundsKind type qualifies the "Between" bounds.

const (
    // BoundsInIn allows to match between "from" and "to" both included
    BoundsInIn BoundsKind = iota
    // BoundsInOut allows to match between "from" included and "to" excluded
    BoundsInOut
    // BoundsOutIn allows to match between "from" excluded and "to" included
    BoundsOutIn
    // BoundsOutOut allows to match between "from" and "to" both excluded
    BoundsOutOut
)

type ContextConfig Uses

type ContextConfig struct {
    // RootName is the string used to represent the root of got data. It
    // defaults to "DATA". For an HTTP response body, it could be "BODY"
    // for example.
    RootName string
    // MaxErrors is the maximal number of errors to dump in case of Cmp*
    // failure.
    //
    // It defaults to 10 except if the environment variable
    // TESTDEEP_MAX_ERRORS is set. In this latter case, the
    // TESTDEEP_MAX_ERRORS value is converted to an int and used as is.
    //
    // Setting it to 0 has the same effect as 1: only the first error
    // will be dumped without the "Too many errors" error.
    //
    // Setting it to a negative number means no limit: all errors
    // will be dumped.
    MaxErrors int
    // FailureIsFatal allows to Fatal() (instead of Error()) when a test
    // fails. Using *testing.T instance as
    // t.TestingFT value, FailNow() is called behind the scenes when
    // Fatal() is called. See testing documentation for details.
    FailureIsFatal bool
}

ContextConfig allows to configure finely how tests failures are rendered.

See NewT function to use it.

type MapEntries Uses

type MapEntries map[interface{}]interface{}

MapEntries allows to pass map entries to check in function Map. It is a map whose each key is the expected entry key and the corresponding value the expected entry value (which can be a TestDeep operator as well as a zero value.)

type SmuggledGot Uses

type SmuggledGot struct {
    Name string
    Got  interface{}
}

SmuggledGot can be returned by a Smuggle function to name the transformed / returned value.

type StructFields Uses

type StructFields map[string]interface{}

StructFields allows to pass struct fields to check in function Struct. It is a map whose each key is the expected field name and the corresponding value the expected field value (which can be a TestDeep operator as well as a zero value.)

type T Uses

type T struct {
    TestingFT
    Config ContextConfig // defaults to DefaultContextConfig
}

T is a type that encapsulates *testing.T (in fact TestingFT interface which is implemented by *testing.T) allowing to easily use *testing.T methods as well as T ones.

func NewT Uses

func NewT(t TestingFT, config ...ContextConfig) *T

NewT returns a new T instance. Typically used as:

import (
  "testing"
  td "github.com/maxatome/go-testdeep"
)

type Record struct {
  Id        uint64
  Name      string
  Age       int
  CreatedAt time.Time
}

func TestCreateRecord(tt *testing.T) {
  t := NewT(tt, ContextConfig{
    MaxErrors: 3, // in case of failure, will dump up to 3 errors
  })

  before := time.Now()
  record, err := CreateRecord()

  if t.CmpNoError(err) {
    t.Log("No error, can now check struct contents")

    ok := t.Struct(record,
      &Record{
        Name: "Bob",
        Age:  23,
      },
      td.StructFields{
        "Id":        td.NotZero(),
        "CreatedAt": td.Between(before, time.Now()),
      },
      "Newly created record")
    if ok {
      t.Log(Record created successfully!")
    }
  }
}

"config" is an optional argument and, if passed, must be unique. It allows to configure how failures will be rendered during the life time of the returned instance.

t := NewT(tt)
t.CmpDeeply(
  Record{Age: 12, Name: "Bob", Id: 12},  // got
  Record{Age: 21, Name: "John", Id: 28}) // expected

will produce:

=== RUN   TestFoobar
--- FAIL: TestFoobar (0.00s)
	foobar_test.go:88: Failed test
		DATA.Id: values differ
			     got: (uint64) 12
			expected: (uint64) 28
		DATA.Name: values differ
			     got: "Bob"
			expected: "John"
		DATA.Age: values differ
			     got: 12
			expected: 28
FAIL

Now with a special configuration:

t := NewT(tt, ContextConfig{
    RootName:  "RECORD", // got data named "RECORD" instead of "DATA"
    MaxErrors: 2,        // stops after 2 errors instead of default 10
  })
t.CmpDeeply(
  Record{Age: 12, Name: "Bob", Id: 12},  // got
  Record{Age: 21, Name: "John", Id: 28}) // expected

will produce:

=== RUN   TestFoobar
--- FAIL: TestFoobar (0.00s)
	foobar_test.go:96: Failed test
		RECORD.Id: values differ
			     got: (uint64) 12
			expected: (uint64) 28
		RECORD.Name: values differ
			     got: "Bob"
			expected: "John"
		Too many errors (use TESTDEEP_MAX_ERRORS=-1 to see all)
FAIL

See RootName method to configure RootName in a more specific fashion.

Note that setting MaxErrors to a negative value produces a dump with all errors.

If MaxErrors is not set (or set to 0), it is set to DefaultContextConfig.MaxErrors which is potentially dependent from the TESTDEEP_MAX_ERRORS environment variable (else defaults to 10.) See ContextConfig documentation for details.

func (*T) All Uses

func (t *T) All(got interface{}, expectedValues []interface{}, args ...interface{}) bool

All is a shortcut for:

t.CmpDeeply(got, All(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#All for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foo/bar"

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "foo/bar" string
ok := t.All(got, []interface{}{Re("o/b"), HasSuffix("bar"), "foo/bar"},
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "fooX/Ybar" string
ok = t.All(got, []interface{}{Re("o/b"), HasSuffix("bar"), "fooX/Ybar"},
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func (*T) Any Uses

func (t *T) Any(got interface{}, expectedValues []interface{}, args ...interface{}) bool

Any is a shortcut for:

t.CmpDeeply(got, Any(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Any for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foo/bar"

// Checks got string against:
//   "zip" regexp *OR* "bar" suffix
ok := t.Any(got, []interface{}{Re("zip"), HasSuffix("bar")},
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "zip" regexp *OR* "foo" suffix
ok = t.Any(got, []interface{}{Re("zip"), HasSuffix("foo")},
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func (*T) Array Uses

func (t *T) Array(got interface{}, model interface{}, expectedEntries ArrayEntries, args ...interface{}) bool

Array is a shortcut for:

t.CmpDeeply(got, Array(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Array for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := [3]int{42, 58, 26}

ok := t.Array(got, [3]int{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks array %v", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := t.Array(got, MyArray{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks typed array %v", got)
fmt.Println(ok)

ok = t.Array(&got, &MyArray{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = t.Array(&got, &MyArray{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = t.Array(&got, (*MyArray)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed array %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func (*T) ArrayEach Uses

func (t *T) ArrayEach(got interface{}, expectedValue interface{}, args ...interface{}) bool

ArrayEach is a shortcut for:

t.CmpDeeply(got, ArrayEach(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ArrayEach for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := [3]int{42, 58, 26}

ok := t.ArrayEach(got, Between(25, 60),
    "checks each item of array %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

got := []int{42, 58, 26}

ok := t.ArrayEach(got, Between(25, 60),
    "checks each item of slice %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := t.ArrayEach(got, Between(25, 60),
    "checks each item of typed array %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = t.ArrayEach(&got, Between(25, 60),
    "checks each item of typed array pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

Code:

t := NewT(&testing.T{})

type MySlice []int

got := MySlice{42, 58, 26}

ok := t.ArrayEach(got, Between(25, 60),
    "checks each item of typed slice %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = t.ArrayEach(&got, Between(25, 60),
    "checks each item of typed slice pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

func (*T) Bag Uses

func (t *T) Bag(got interface{}, expectedItems []interface{}, args ...interface{}) bool

Bag is a shortcut for:

t.CmpDeeply(got, Bag(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Bag for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present
ok := t.Bag(got, []interface{}{1, 1, 2, 3, 5, 8, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Does not match as got contains 2 times 1 and 8, and these
// duplicates are not expected
ok = t.Bag(got, []interface{}{1, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 8, 2}

// Duplicates of 1 and 8 are expected but not present in got
ok = t.Bag(got, []interface{}{1, 1, 2, 3, 5, 8, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Matches as all items are present
ok = t.Bag(got, []interface{}{1, 2, 3, 5, Gt(7)},
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
false
false
true

func (*T) Between Uses

func (t *T) Between(got interface{}, from interface{}, to interface{}, bounds BoundsKind, args ...interface{}) bool

Between is a shortcut for:

t.CmpDeeply(got, Between(from, to, bounds), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Between for details.

Between() optional parameter "bounds" is here mandatory. BoundsInIn value should be passed to mimic its absence in original Between() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 156

ok := t.Between(got, 154, 156, BoundsInIn,
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = t.Between(got, 154, 156, BoundsInIn,
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

ok = t.Between(got, 154, 156, BoundsInOut,
    "checks %v is in [154 .. 156[", got)
fmt.Println(ok)

ok = t.Between(got, 154, 156, BoundsOutIn,
    "checks %v is in ]154 .. 156]", got)
fmt.Println(ok)

ok = t.Between(got, 154, 156, BoundsOutOut,
    "checks %v is in ]154 .. 156[", got)
fmt.Println(ok)

Output:

true
true
false
true
false

Code:

t := NewT(&testing.T{})

got := "abc"

ok := t.Between(got, "aaa", "abc", BoundsInIn,
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = t.Between(got, "aaa", "abc", BoundsInIn,
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = t.Between(got, "aaa", "abc", BoundsInOut,
    `checks "%v" is in ["aaa" .. "abc"[`, got)
fmt.Println(ok)

ok = t.Between(got, "aaa", "abc", BoundsOutIn,
    `checks "%v" is in ]"aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = t.Between(got, "aaa", "abc", BoundsOutOut,
    `checks "%v" is in ]"aaa" .. "abc"[`, got)
fmt.Println(ok)

Output:

true
true
false
true
false

func (*T) Cap Uses

func (t *T) Cap(got interface{}, val interface{}, args ...interface{}) bool

Cap is a shortcut for:

t.CmpDeeply(got, Cap(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Cap for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := make([]int, 0, 12)

ok := t.Cap(got, 12, "checks %v capacity is 12", got)
fmt.Println(ok)

ok = t.Cap(got, 0, "checks %v capacity is 0", got)
fmt.Println(ok)

got = nil

ok = t.Cap(got, 0, "checks %v capacity is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := NewT(&testing.T{})

got := make([]int, 0, 12)

ok := t.Cap(got, Between(10, 12),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

ok = t.Cap(got, Gt(10),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

Output:

true
true

func (*T) CmpDeeply Uses

func (t *T) CmpDeeply(got, expected interface{}, args ...interface{}) bool

CmpDeeply is mostly a shortcut for:

CmpDeeply(t.TestingFT, got, expected, args...)

with the exception that t.Config is used to configure the test Context.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

func (*T) CmpError Uses

func (t *T) CmpError(got error, args ...interface{}) bool

CmpError checks that "got" is non-nil error.

_, err := MyFunction(1, 2, 3)
t.CmpError(err, "MyFunction(1, 2, 3) should return an error")

CmpError and not Error to avoid collision with t.TestingFT.Error method.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := fmt.Errorf("Error #%d", 42)
ok := t.CmpError(got, "An error occurred")
fmt.Println(ok)

got = nil
ok = t.CmpError(got, "An error occurred") // fails
fmt.Println(ok)

Output:

true
false

func (*T) CmpNoError Uses

func (t *T) CmpNoError(got error, args ...interface{}) bool

CmpNoError checks that "got" is nil error.

value, err := MyFunction(1, 2, 3)
if t.CmpNoError(err) {
  // one can now check value...
}

CmpNoError and not NoError to be consistent with CmpError method.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := fmt.Errorf("Error #%d", 42)
ok := t.CmpNoError(got, "An error occurred") // fails
fmt.Println(ok)

got = nil
ok = t.CmpNoError(got, "An error occurred")
fmt.Println(ok)

Output:

false
true

func (*T) CmpNotPanic Uses

func (t *T) CmpNotPanic(fn func(), args ...interface{}) bool

CmpNotPanic calls "fn" and checks no panic() occurred. If a panic() occurred false is returned then the panic() parameter and the stack trace appear in the test report.

Note that calling panic(nil) in "fn" body is detected as a panic.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.CmpNotPanic(func() {}, nil)
fmt.Println("checks a panic DID NOT occur:", ok)

// Classic panic
ok = t.CmpNotPanic(func() { panic("I am panicking!") },
    "Hope it does not panic!")
fmt.Println("still no panic?", ok)

// Can detect panic(nil)
ok = t.CmpNotPanic(func() { panic(nil) }, "Checks for panic(nil)")
fmt.Println("last no panic?", ok)

Output:

checks a panic DID NOT occur: true
still no panic? false
last no panic? false

func (*T) CmpPanic Uses

func (t *T) CmpPanic(fn func(), expected interface{}, args ...interface{}) bool

CmpPanic calls "fn" and checks a panic() occurred with the "expectedPanic" parameter. It returns true only if both conditions are fulfilled.

Note that calling panic(nil) in "fn" body is detected as a panic (in this case "expectedPanic" has to be nil.)

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.CmpPanic(func() { panic("I am panicking!") }, "I am panicking!",
    "Checks for panic")
fmt.Println("checks exact panic() string:", ok)

// Can use TestDeep operator too
ok = t.CmpPanic(func() { panic("I am panicking!") }, Contains("panicking!"),
    "Checks for panic")
fmt.Println("checks panic() sub-string:", ok)

// Can detect panic(nil)
ok = t.CmpPanic(func() { panic(nil) }, nil, "Checks for panic(nil)")
fmt.Println("checks for panic(nil):", ok)

// As well as structured data panic
type PanicStruct struct {
    Error string
    Code  int
}

ok = t.CmpPanic(
    func() {
        panic(PanicStruct{Error: "Memory violation", Code: 11})
    },
    PanicStruct{
        Error: "Memory violation",
        Code:  11,
    })
fmt.Println("checks exact panic() struct:", ok)

// or combined with TestDeep operators too
ok = t.CmpPanic(
    func() {
        panic(PanicStruct{Error: "Memory violation", Code: 11})
    },
    Struct(PanicStruct{}, StructFields{
        "Code": Between(10, 20),
    }))
fmt.Println("checks panic() struct against TestDeep operators:", ok)

// Of course, do not panic = test failure, even for expected nil
// panic parameter
ok = t.CmpPanic(func() {}, nil)
fmt.Println("checks a panic occurred:", ok)

Output:

checks exact panic() string: true
checks panic() sub-string: true
checks for panic(nil): true
checks exact panic() struct: true
checks panic() struct against TestDeep operators: true
checks a panic occurred: false

func (*T) Code Uses

func (t *T) Code(got interface{}, fn interface{}, args ...interface{}) bool

Code is a shortcut for:

t.CmpDeeply(got, Code(fn), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Code for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "12"

ok := t.Code(got, func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason
ok = t.Code(got, func(num string) (bool, string) {
    n, err := strconv.Atoi(num)
    if err != nil {
        return false, "not a number"
    }
    if n > 10 && n < 100 {
        return true, ""
    }
    return false, "not in ]10 .. 100["
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason thanks to error
ok = t.Code(got, func(num string) error {
    n, err := strconv.Atoi(num)
    if err != nil {
        return err
    }
    if n > 10 && n < 100 {
        return nil
    }
    return fmt.Errorf("%d not in ]10 .. 100[", n)
},
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

Output:

true
true
true

func (*T) Contains Uses

func (t *T) Contains(got interface{}, expectedValue interface{}, args ...interface{}) bool

Contains is a shortcut for:

t.CmpDeeply(got, Contains(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Contains for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.Contains([...]int{11, 22, 33, 44}, 22)
fmt.Println("array contains 22:", ok)

ok = t.Contains([...]int{11, 22, 33, 44}, Between(20, 25))
fmt.Println("array contains at least one item in [20 .. 25]:", ok)

ok = t.Contains([]int{11, 22, 33, 44}, 22)
fmt.Println("slice contains 22:", ok)

ok = t.Contains([]int{11, 22, 33, 44}, Between(20, 25))
fmt.Println("slice contains at least one item in [20 .. 25]:", ok)

Output:

array contains 22: true
array contains at least one item in [20 .. 25]: true
slice contains 22: true
slice contains at least one item in [20 .. 25]: true

Code:

t := NewT(&testing.T{})

got := errors.New("foobar")

ok := t.Contains(got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = t.Contains(got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = t.Contains(got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = t.Contains(got, Between('n', 'p'), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

Code:

t := NewT(&testing.T{})

ok := t.Contains(map[string]int{"foo": 11, "bar": 22, "zip": 33}, 22)
fmt.Println("map contains value 22:", ok)

ok = t.Contains(map[string]int{"foo": 11, "bar": 22, "zip": 33}, Between(20, 25))
fmt.Println("map contains at least one value in [20 .. 25]:", ok)

Output:

map contains value 22: true
map contains at least one value in [20 .. 25]: true

Code:

t := NewT(&testing.T{})

num := 123
got := [...]*int{&num, nil}

ok := t.Contains(got, nil)
fmt.Println("array contains untyped nil:", ok)

ok = t.Contains(got, (*int)(nil))
fmt.Println("array contains *int nil:", ok)

ok = t.Contains(got, Nil())
fmt.Println("array contains Nil():", ok)

ok = t.Contains(got, (*byte)(nil))
fmt.Println("array contains *byte nil:", ok) // types differ: *byte ≠ *int

Output:

array contains untyped nil: true
array contains *int nil: true
array contains Nil(): true
array contains *byte nil: false

Code:

t := NewT(&testing.T{})

got := "foobar"

ok := t.Contains(got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = t.Contains(got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = t.Contains(got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

ok = t.Contains(got, Between('n', 'p'), "checks %s", got)
fmt.Println("contains at least one character ['n' .. 'p']:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
contains at least one character ['n' .. 'p']: true

Code:

t := NewT(&testing.T{})

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := t.Contains(got, "oob", "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = t.Contains(got, 'b', "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = t.Contains(got, byte('a'), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = t.Contains(got, Between('n', 'p'), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

func (*T) ContainsKey Uses

func (t *T) ContainsKey(got interface{}, expectedValue interface{}, args ...interface{}) bool

ContainsKey is a shortcut for:

t.CmpDeeply(got, ContainsKey(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ContainsKey for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.ContainsKey(map[string]int{"foo": 11, "bar": 22, "zip": 33}, "foo")
fmt.Println(`map contains key "foo":`, ok)

ok = t.ContainsKey(map[int]bool{12: true, 24: false, 42: true, 51: false}, Between(40, 50))
fmt.Println("map contains at least a key in [40 .. 50]:", ok)

Output:

map contains key "foo": true
map contains at least a key in [40 .. 50]: true

Code:

t := NewT(&testing.T{})

num := 1234
got := map[*int]bool{&num: false, nil: true}

ok := t.ContainsKey(got, nil)
fmt.Println("map contains untyped nil key:", ok)

ok = t.ContainsKey(got, (*int)(nil))
fmt.Println("map contains *int nil key:", ok)

ok = t.ContainsKey(got, Nil())
fmt.Println("map contains Nil() key:", ok)

ok = t.ContainsKey(got, (*byte)(nil))
fmt.Println("map contains *byte nil key:", ok) // types differ: *byte ≠ *int

Output:

map contains untyped nil key: true
map contains *int nil key: true
map contains Nil() key: true
map contains *byte nil key: false

func (*T) Empty Uses

func (t *T) Empty(got interface{}, args ...interface{}) bool

Empty is a shortcut for:

t.CmpDeeply(got, Empty(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Empty for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.Empty(nil) // special case: nil is considered empty
fmt.Println(ok)

// fails, typed nil is not empty (expect for channel, map, slice or
// pointers on array, channel, map slice and strings)
ok = t.Empty((*int)(nil))
fmt.Println(ok)

ok = t.Empty("")
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use Zero() instead
ok = t.Empty(0)
fmt.Println(ok)

ok = t.Empty((map[string]int)(nil))
fmt.Println(ok)

ok = t.Empty(map[string]int{})
fmt.Println(ok)

ok = t.Empty(([]int)(nil))
fmt.Println(ok)

ok = t.Empty([]int{})
fmt.Println(ok)

ok = t.Empty([]int{3}) // fails, as not empty
fmt.Println(ok)

ok = t.Empty([3]int{}) // fails, Empty() is not Zero()!
fmt.Println(ok)

Output:

true
false
true
false
true
true
true
true
false
false

Code:

t := NewT(&testing.T{})

type MySlice []int

ok := t.Empty(MySlice{}) // Ptr() not needed
fmt.Println(ok)

ok = t.Empty(&MySlice{})
fmt.Println(ok)

l1 := &MySlice{}
l2 := &l1
l3 := &l2
ok = t.Empty(&l3)
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = t.Empty(&MyStruct{}) // fails, use Zero() instead
fmt.Println(ok)

Output:

true
true
true
false

func (*T) FailureIsFatal Uses

func (t *T) FailureIsFatal(enable ...bool) *T

FailureIsFatal allows to choose whether t.TestingFT.Fatal() or t.TestingFT.Error() will be used to print the next failure reports. When "enable" is true (or missing) testing.Fatal() will be called, else testing.Error(). Using *testing.T instance as t.TestingFT value, FailNow() is called behind the scenes when Fatal() is called. See testing documentation for details.

It returns a new instance of *T so does not alter the original t and used as follows:

// Following t.CmpDeeply() will call Fatal() if failure
t = t.FailureIsFatal()
t.CmpDeeply(...)
t.CmpDeeply(...)
// Following t.CmpDeeply() won't call Fatal() if failure
t = t.FailureIsFatal(false)
t.CmpDeeply(...)

or, if only one call is critic:

// This CmpDeeply() call will call Fatal() if failure
t.FailureIsFatal().CmpDeeply(...)
// Following t.CmpDeeply() won't call Fatal() if failure
t.CmpDeeply(...)
t.CmpDeeply(...)

func (*T) False Uses

func (t *T) False(got interface{}, args ...interface{}) bool

False is shortcut for:

t.CmpDeeply(got, false, args...)

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := false
ok := t.False(got, "check that got is false!")
fmt.Println(ok)

got = true
ok = t.False(got, "check that got is false!")
fmt.Println(ok)

Output:

true
false

func (*T) Gt Uses

func (t *T) Gt(got interface{}, val interface{}, args ...interface{}) bool

Gt is a shortcut for:

t.CmpDeeply(got, Gt(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Gt for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 156

ok := t.Gt(got, 155, "checks %v is > 155", got)
fmt.Println(ok)

ok = t.Gt(got, 156, "checks %v is > 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

got := "abc"

ok := t.Gt(got, "abb", `checks "%v" is > "abb"`, got)
fmt.Println(ok)

ok = t.Gt(got, "abc", `checks "%v" is > "abc"`, got)
fmt.Println(ok)

Output:

true
false

func (*T) Gte Uses

func (t *T) Gte(got interface{}, val interface{}, args ...interface{}) bool

Gte is a shortcut for:

t.CmpDeeply(got, Gte(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Gte for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 156

ok := t.Gte(got, 156, "checks %v is ≥ 156", got)
fmt.Println(ok)

ok = t.Gte(got, 155, "checks %v is ≥ 155", got)
fmt.Println(ok)

ok = t.Gte(got, 157, "checks %v is ≥ 157", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := NewT(&testing.T{})

got := "abc"

ok := t.Gte(got, "abc", `checks "%v" is ≥ "abc"`, got)
fmt.Println(ok)

ok = t.Gte(got, "abb", `checks "%v" is ≥ "abb"`, got)
fmt.Println(ok)

ok = t.Gte(got, "abd", `checks "%v" is ≥ "abd"`, got)
fmt.Println(ok)

Output:

true
true
false

func (*T) HasPrefix Uses

func (t *T) HasPrefix(got interface{}, expected string, args ...interface{}) bool

HasPrefix is a shortcut for:

t.CmpDeeply(got, HasPrefix(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#HasPrefix for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foobar"

ok := t.HasPrefix(got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

got := errors.New("foobar")

ok := t.HasPrefix(got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := t.HasPrefix(got, "foo", "checks %s", got)
fmt.Println(ok)

Output:

true

func (*T) HasSuffix Uses

func (t *T) HasSuffix(got interface{}, expected string, args ...interface{}) bool

HasSuffix is a shortcut for:

t.CmpDeeply(got, HasSuffix(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#HasSuffix for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foobar"

ok := t.HasSuffix(got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

got := errors.New("foobar")

ok := t.HasSuffix(got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := t.HasSuffix(got, "bar", "checks %s", got)
fmt.Println(ok)

Output:

true

func (*T) Isa Uses

func (t *T) Isa(got interface{}, model interface{}, args ...interface{}) bool

Isa is a shortcut for:

t.CmpDeeply(got, Isa(model), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Isa for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

type TstStruct struct {
    Field int
}

got := TstStruct{Field: 1}

ok := t.Isa(got, TstStruct{}, "checks got is a TstStruct")
fmt.Println(ok)

ok = t.Isa(got, &TstStruct{},
    "checks got is a pointer on a TstStruct")
fmt.Println(ok)

ok = t.Isa(&got, &TstStruct{},
    "checks &got is a pointer on a TstStruct")
fmt.Println(ok)

Output:

true
false
true

Code:

t := NewT(&testing.T{})

got := bytes.NewBufferString("foobar")

ok := t.Isa(got, (*fmt.Stringer)(nil),
    "checks got implements fmt.Stringer interface")
fmt.Println(ok)

errGot := fmt.Errorf("An error #%d occurred", 123)

ok = t.Isa(errGot, (*error)(nil),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// As nil, is passed below, it is not an interface but nil... So it
// does not match
errGot = nil

ok = t.Isa(errGot, (*error)(nil),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// BUT if its address is passed, now it is OK as the types match
ok = t.Isa(&errGot, (*error)(nil),
    "checks &errGot is a *error or implements error interface")
fmt.Println(ok)

Output:

true
true
false
true

func (*T) Len Uses

func (t *T) Len(got interface{}, val interface{}, args ...interface{}) bool

Len is a shortcut for:

t.CmpDeeply(got, Len(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Len for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := map[int]bool{11: true, 22: false, 33: false}

ok := t.Len(got, 3, "checks %v len is 3", got)
fmt.Println(ok)

ok = t.Len(got, 0, "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = t.Len(got, 0, "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := NewT(&testing.T{})

got := map[int]bool{11: true, 22: false, 33: false}

ok := t.Len(got, Between(3, 8),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = t.Len(got, Gte(3), "checks %v len is ≥ 3", got)
fmt.Println(ok)

Output:

true
true

Code:

t := NewT(&testing.T{})

got := []int{11, 22, 33}

ok := t.Len(got, Between(3, 8),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = t.Len(got, Lt(5), "checks %v len is < 5", got)
fmt.Println(ok)

Output:

true
true

Code:

t := NewT(&testing.T{})

got := []int{11, 22, 33}

ok := t.Len(got, 3, "checks %v len is 3", got)
fmt.Println(ok)

ok = t.Len(got, 0, "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = t.Len(got, 0, "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

func (*T) Lt Uses

func (t *T) Lt(got interface{}, val interface{}, args ...interface{}) bool

Lt is a shortcut for:

t.CmpDeeply(got, Lt(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Lt for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 156

ok := t.Lt(got, 157, "checks %v is < 157", got)
fmt.Println(ok)

ok = t.Lt(got, 156, "checks %v is < 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

got := "abc"

ok := t.Lt(got, "abd", `checks "%v" is < "abd"`, got)
fmt.Println(ok)

ok = t.Lt(got, "abc", `checks "%v" is < "abc"`, got)
fmt.Println(ok)

Output:

true
false

func (*T) Lte Uses

func (t *T) Lte(got interface{}, val interface{}, args ...interface{}) bool

Lte is a shortcut for:

t.CmpDeeply(got, Lte(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Lte for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 156

ok := t.Lte(got, 156, "checks %v is ≤ 156", got)
fmt.Println(ok)

ok = t.Lte(got, 157, "checks %v is ≤ 157", got)
fmt.Println(ok)

ok = t.Lte(got, 155, "checks %v is ≤ 155", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := NewT(&testing.T{})

got := "abc"

ok := t.Lte(got, "abc", `checks "%v" is ≤ "abc"`, got)
fmt.Println(ok)

ok = t.Lte(got, "abd", `checks "%v" is ≤ "abd"`, got)
fmt.Println(ok)

ok = t.Lte(got, "abb", `checks "%v" is ≤ "abb"`, got)
fmt.Println(ok)

Output:

true
true
false

func (*T) Map Uses

func (t *T) Map(got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

Map is a shortcut for:

t.CmpDeeply(got, Map(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Map for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := t.Map(got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

ok = t.Map(got, map[string]int{}, MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

ok = t.Map(got, (map[string]int)(nil), MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks map %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := NewT(&testing.T{})

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := t.Map(got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks typed map %v", got)
fmt.Println(ok)

ok = t.Map(&got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = t.Map(&got, &MyMap{}, MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = t.Map(&got, (*MyMap)(nil), MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()},
    "checks pointer on typed map %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func (*T) MapEach Uses

func (t *T) MapEach(got interface{}, expectedValue interface{}, args ...interface{}) bool

MapEach is a shortcut for:

t.CmpDeeply(got, MapEach(expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#MapEach for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := t.MapEach(got, Between(10, 90),
    "checks each value of map %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := t.MapEach(got, Between(10, 90),
    "checks each value of typed map %v is in [10 .. 90]", got)
fmt.Println(ok)

ok = t.MapEach(&got, Between(10, 90),
    "checks each value of typed map pointer %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true
true

func (*T) N Uses

func (t *T) N(got interface{}, num interface{}, tolerance interface{}, args ...interface{}) bool

N is a shortcut for:

t.CmpDeeply(got, N(num, tolerance), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#N for details.

N() optional parameter "tolerance" is here mandatory. 0 value should be passed to mimic its absence in original N() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 1.12345

ok := t.N(got, 1.1234, 0.00006,
    "checks %v = 1.1234 ± 0.00006", got)
fmt.Println(ok)

Output:

true

func (*T) NaN Uses

func (t *T) NaN(got interface{}, args ...interface{}) bool

NaN is a shortcut for:

t.CmpDeeply(got, NaN(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NaN for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := float32(math.NaN())

ok := t.NaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is float32 not-a-number:", ok)

got = 12

ok = t.NaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is float32 not-a-number:", ok)

Output:

float32(math.NaN()) is float32 not-a-number: true
float32(12) is float32 not-a-number: false

Code:

t := NewT(&testing.T{})

got := math.NaN()

ok := t.NaN(got,
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = t.NaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is not-a-number: true
// float64(12) is not-a-number: false

func (*T) Nil Uses

func (t *T) Nil(got interface{}, args ...interface{}) bool

Nil is a shortcut for:

t.CmpDeeply(got, Nil(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Nil for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

var got fmt.Stringer // interface

// nil value can be compared directly with nil, no need of Nil() here
ok := t.CmpDeeply(got, nil)
fmt.Println(ok)

// But it works with Nil() anyway
ok = t.Nil(got)
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with nil fails, as the interface is not nil
ok = t.CmpDeeply(got, nil)
fmt.Println(ok)

// In this case Nil() succeed
ok = t.Nil(got)
fmt.Println(ok)

Output:

true
true
false
true

func (*T) None Uses

func (t *T) None(got interface{}, expectedValues []interface{}, args ...interface{}) bool

None is a shortcut for:

t.CmpDeeply(got, None(expectedValues...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#None for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 18

ok := t.None(got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 20

ok = t.None(got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 142

ok = t.None(got, []interface{}{0, 10, 20, 30, Between(100, 199)},
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

Output:

true
false
false

func (*T) Not Uses

func (t *T) Not(got interface{}, expected interface{}, args ...interface{}) bool

Not is a shortcut for:

t.CmpDeeply(got, Not(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Not for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 42

ok := t.Not(got, 0, "checks %v is non-null", got)
fmt.Println(ok)

ok = t.Not(got, Between(10, 30),
    "checks %v is not in [10 .. 30]", got)
fmt.Println(ok)

got = 0

ok = t.Not(got, 0, "checks %v is non-null", got)
fmt.Println(ok)

Output:

true
true
false

func (*T) NotAny Uses

func (t *T) NotAny(got interface{}, expectedItems []interface{}, args ...interface{}) bool

NotAny is a shortcut for:

t.CmpDeeply(got, NotAny(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotAny for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{4, 5, 9, 42}

ok := t.NotAny(got, []interface{}{3, 6, 8, 41, 43},
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

ok = t.NotAny(got, []interface{}{3, 6, 8, 42, 43},
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

Output:

true
false

func (*T) NotEmpty Uses

func (t *T) NotEmpty(got interface{}, args ...interface{}) bool

NotEmpty is a shortcut for:

t.CmpDeeply(got, NotEmpty(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotEmpty for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.NotEmpty(nil) // fails, as nil is considered empty
fmt.Println(ok)

ok = t.NotEmpty("foobar")
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use NotZero() instead
ok = t.NotEmpty(0)
fmt.Println(ok)

ok = t.NotEmpty(map[string]int{"foobar": 42})
fmt.Println(ok)

ok = t.NotEmpty([]int{1})
fmt.Println(ok)

ok = t.NotEmpty([3]int{}) // succeeds, NotEmpty() is not NotZero()!
fmt.Println(ok)

Output:

false
true
false
true
true
true

Code:

t := NewT(&testing.T{})

type MySlice []int

ok := t.NotEmpty(MySlice{12})
fmt.Println(ok)

ok = t.NotEmpty(&MySlice{12}) // Ptr() not needed
fmt.Println(ok)

l1 := &MySlice{12}
l2 := &l1
l3 := &l2
ok = t.NotEmpty(&l3)
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = t.NotEmpty(&MyStruct{}) // fails, use NotZero() instead
fmt.Println(ok)

Output:

true
true
true
false

func (*T) NotNaN Uses

func (t *T) NotNaN(got interface{}, args ...interface{}) bool

NotNaN is a shortcut for:

t.CmpDeeply(got, NotNaN(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotNaN for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := float32(math.NaN())

ok := t.NotNaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is NOT float32 not-a-number:", ok)

got = 12

ok = t.NotNaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is NOT float32 not-a-number:", ok)

Output:

float32(math.NaN()) is NOT float32 not-a-number: false
float32(12) is NOT float32 not-a-number: true

Code:

t := NewT(&testing.T{})

got := math.NaN()

ok := t.NotNaN(got,
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = t.NotNaN(got,
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is NOT not-a-number: false
// float64(12) is NOT not-a-number: true

func (*T) NotNil Uses

func (t *T) NotNil(got interface{}, args ...interface{}) bool

NotNil is a shortcut for:

t.CmpDeeply(got, NotNil(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotNil for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

var got fmt.Stringer = &bytes.Buffer{}

// nil value can be compared directly with Not(nil), no need of NotNil() here
ok := t.CmpDeeply(got, Not(nil))
fmt.Println(ok)

// But it works with NotNil() anyway
ok = t.NotNil(got)
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with Not(nil) succeeds, as the interface is not nil
ok = t.CmpDeeply(got, Not(nil))
fmt.Println(ok)

// In this case NotNil() fails
ok = t.NotNil(got)
fmt.Println(ok)

Output:

true
true
true
false

func (*T) NotZero Uses

func (t *T) NotZero(got interface{}, args ...interface{}) bool

NotZero is a shortcut for:

t.CmpDeeply(got, NotZero(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#NotZero for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.NotZero(0) // fails
fmt.Println(ok)

ok = t.NotZero(float64(0)) // fails
fmt.Println(ok)

ok = t.NotZero(12)
fmt.Println(ok)

ok = t.NotZero((map[string]int)(nil)) // fails, as nil
fmt.Println(ok)

ok = t.NotZero(map[string]int{}) // succeeds, as not nil
fmt.Println(ok)

ok = t.NotZero(([]int)(nil)) // fails, as nil
fmt.Println(ok)

ok = t.NotZero([]int{}) // succeeds, as not nil
fmt.Println(ok)

ok = t.NotZero([3]int{}) // fails
fmt.Println(ok)

ok = t.NotZero([3]int{0, 1}) // succeeds, DATA[1] is not 0
fmt.Println(ok)

ok = t.NotZero(bytes.Buffer{}) // fails
fmt.Println(ok)

ok = t.NotZero(&bytes.Buffer{}) // succeeds, as pointer not nil
fmt.Println(ok)

ok = t.CmpDeeply(&bytes.Buffer{}, Ptr(NotZero())) // fails as deref by Ptr()
fmt.Println(ok)

Output:

false
false
true
false
true
false
true
false
true
false
true
false

func (*T) PPtr Uses

func (t *T) PPtr(got interface{}, val interface{}, args ...interface{}) bool

PPtr is a shortcut for:

t.CmpDeeply(got, PPtr(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#PPtr for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

num := 12
got := &num

ok := t.PPtr(&got, 12)
fmt.Println(ok)

ok = t.PPtr(&got, Between(4, 15))
fmt.Println(ok)

Output:

true
true

func (*T) Ptr Uses

func (t *T) Ptr(got interface{}, val interface{}, args ...interface{}) bool

Ptr is a shortcut for:

t.CmpDeeply(got, Ptr(val), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Ptr for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := 12

ok := t.Ptr(&got, 12)
fmt.Println(ok)

ok = t.Ptr(&got, Between(4, 15))
fmt.Println(ok)

Output:

true
true

func (*T) Re Uses

func (t *T) Re(got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool

Re is a shortcut for:

t.CmpDeeply(got, Re(reg, capture), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Re for details.

Re() optional parameter "capture" is here mandatory. nil value should be passed to mimic its absence in original Re() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foo bar"
ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = t.Re(got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

got := "foo bar biz"
ok := t.Re(got, `^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = t.Re(got, `^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile("(zip|bar)$")

got := "foo bar"
ok := t.Re(got, expected, nil, "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = t.Re(got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile(`^(\w+) (\w+) (\w+)$`)

got := "foo bar biz"
ok := t.Re(got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = t.Re(got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile("(zip|bar)$")

got := errors.New("foo bar")
ok := t.Re(got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile("(zip|bar)$")

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := t.Re(got, expected, nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

got := errors.New("foo bar")
ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)
fmt.Println(ok)

Output:

true

func (*T) ReAll Uses

func (t *T) ReAll(got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool

ReAll is a shortcut for:

t.CmpDeeply(got, ReAll(reg, capture), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#ReAll for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foo bar biz"
ok := t.ReAll(got, `(\w+)`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = t.ReAll(got, `(\w+)`, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

got := "11 45 23 56 85 96"
ok := t.ReAll(got, `(\d+)`, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = t.ReAll(got, `(\d+)`, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 20 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile(`(\w+)`)

got := "foo bar biz"
ok := t.ReAll(got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = t.ReAll(got, expected, Set("biz", "foo", "bar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

expected := regexp.MustCompile(`(\d+)`)

got := "11 45 23 56 85 96"
ok := t.ReAll(got, expected, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 10 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = t.ReAll(got, expected, ArrayEach(Code(func(num string) bool {
    n, err := strconv.Atoi(num)
    return err == nil && n > 20 && n < 100
})),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func (*T) RootName Uses

func (t *T) RootName(rootName string) *T

RootName changes the name of the got data. By default it is "DATA". For an HTTP response body, it could be "BODY" for example.

It returns a new instance of *T so does not alter the original t and used as follows:

t.RootName("RECORD").
  Struct(record,
    &Record{
      Name: "Bob",
      Age:  23,
    },
    td.StructFields{
      "Id":        td.NotZero(),
      "CreatedAt": td.Between(before, time.Now()),
    },
    "Newly created record")

In case of error for the field Age, the failure message will contain:

RECORD.Age: values differ

Which is more readable than the generic:

DATA.Age: values differ

func (*T) Run Uses

func (t *T) Run(name string, f func(t *T)) bool

Run runs "f" as a subtest of t called "name". It runs "f" in a separate goroutine and blocks until "f" returns or calls t.Parallel to become a parallel test. Run reports whether "f" succeeded (or at least did not fail before calling t.Parallel).

Run may be called simultaneously from multiple goroutines, but all such calls must return before the outer test function for t returns.

Under the hood, Run delegates all this stuff to testing.Run. That is why this documentation is a copy/paste of testing.Run one.

func (*T) Set Uses

func (t *T) Set(got interface{}, expectedItems []interface{}, args ...interface{}) bool

Set is a shortcut for:

t.CmpDeeply(got, Set(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Set for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present, ignoring duplicates
ok := t.Set(got, []interface{}{1, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Duplicates are ignored in a Set
ok = t.Set(got, []interface{}{1, 2, 2, 2, 2, 2, 3, 5, 8},
    "checks all items are present, in any order")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several Set entries
ok = t.Set(got, []interface{}{Between(1, 4), 3, Between(2, 10)},
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
true
true

func (*T) Shallow Uses

func (t *T) Shallow(got interface{}, expectedPtr interface{}, args ...interface{}) bool

Shallow is a shortcut for:

t.CmpDeeply(got, Shallow(expectedPtr), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Shallow for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

type MyStruct struct {
    Value int
}
data := MyStruct{Value: 12}
got := &data

ok := t.Shallow(got, &data,
    "checks pointers only, not contents")
fmt.Println(ok)

// Same contents, but not same pointer
ok = t.Shallow(got, &MyStruct{Value: 12},
    "checks pointers only, not contents")
fmt.Println(ok)

Output:

true
false

Code:

t := NewT(&testing.T{})

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

ok := t.Shallow(a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = t.Shallow(b, back)
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

Code:

t := NewT(&testing.T{})

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := t.Shallow(a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = t.Shallow(b, a)
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

func (*T) Slice Uses

func (t *T) Slice(got interface{}, model interface{}, expectedEntries ArrayEntries, args ...interface{}) bool

Slice is a shortcut for:

t.CmpDeeply(got, Slice(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Slice for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{42, 58, 26}

ok := t.Slice(got, []int{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

ok = t.Slice(got, []int{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

ok = t.Slice(got, ([]int)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks slice %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := NewT(&testing.T{})

type MySlice []int

got := MySlice{42, 58, 26}

ok := t.Slice(got, MySlice{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks typed slice %v", got)
fmt.Println(ok)

ok = t.Slice(&got, &MySlice{42}, ArrayEntries{1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = t.Slice(&got, &MySlice{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = t.Slice(&got, (*MySlice)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()},
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func (*T) Smuggle Uses

func (t *T) Smuggle(got interface{}, fn interface{}, expectedValue interface{}, args ...interface{}) bool

Smuggle is a shortcut for:

t.CmpDeeply(got, Smuggle(fn, expectedValue), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Smuggle for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

// No end date but a start date and a duration
type StartDuration struct {
    StartDate time.Time
    Duration  time.Duration
}

// Checks that end date is between 17th and 19th February both at 0h
// for each of these durations in hours

for _, duration := range []time.Duration{48, 72, 96} {
    got := StartDuration{
        StartDate: time.Date(2018, time.February, 14, 12, 13, 14, 0, time.UTC),
        Duration:  duration * time.Hour,
    }

    // Simplest way, but in case of Between() failure, error will be bound
    // to DATA<smuggled>, not very clear...
    ok := t.Smuggle(got, func(sd StartDuration) time.Time {
        return sd.StartDate.Add(sd.Duration)
    }, Between(
        time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
        time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))
    fmt.Println(ok)

    // Name the computed value "ComputedEndDate" to render a Between() failure
    // more understandable, so error will be bound to DATA.ComputedEndDate
    ok = t.Smuggle(got, func(sd StartDuration) SmuggledGot {
        return SmuggledGot{
            Name: "ComputedEndDate",
            Got:  sd.StartDate.Add(sd.Duration),
        }
    }, Between(
        time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
        time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))
    fmt.Println(ok)
}

Output:

false
false
true
true
true
true

Code:

t := NewT(&testing.T{})

got := int64(123)

ok := t.Smuggle(got, func(n int64) int { return int(n) }, 123,
    "checks int64 got against an int value")
fmt.Println(ok)

ok = t.Smuggle("123", func(numStr string) (int, bool) {
    n, err := strconv.Atoi(numStr)
    return n, err == nil
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = t.Smuggle("123", func(numStr string) (int, bool, string) {
    n, err := strconv.Atoi(numStr)
    if err != nil {
        return 0, false, "string must contain a number"
    }
    return n, true, ""
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = t.Smuggle("123", func(numStr string) (int, error) {
    return strconv.Atoi(numStr)
}, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

// Short version :)
ok = t.Smuggle("123", strconv.Atoi, Between(120, 130),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

Output:

true
true
true
true
true

Code:

t := NewT(&testing.T{})

gotTime, err := time.Parse(time.RFC3339, "2018-05-23T12:13:14Z")
if err != nil {
    t.Fatal(err)
}

// Do not check the struct itself, but its stringified form
ok := t.Smuggle(gotTime, func(s fmt.Stringer) string {
    return s.String()
}, "2018-05-23 12:13:14 +0000 UTC")
fmt.Println("stringified time.Time OK:", ok)

// If got does not implement the fmt.Stringer interface, it fails
// without calling the Smuggle func
type MyTime time.Time
ok = t.Smuggle(MyTime(gotTime), func(s fmt.Stringer) string {
    fmt.Println("Smuggle func called!")
    return s.String()
}, "2018-05-23 12:13:14 +0000 UTC")
fmt.Println("stringified MyTime OK:", ok)

// Output
// stringified time.Time OK: true
// stringified MyTime OK: false

Code:

t := NewT(&testing.T{})

// got is an int16 and Smuggle func input is an int64: it is OK
got := int(123)

ok := t.Smuggle(got, func(n int64) uint32 { return uint32(n) }, uint32(123))
fmt.Println("got int16(123) → smuggle via int64 → uint32(123):", ok)

Output:

got int16(123) → smuggle via int64 → uint32(123): true

func (*T) String Uses

func (t *T) String(got interface{}, expected string, args ...interface{}) bool

String is a shortcut for:

t.CmpDeeply(got, String(expected), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#String for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := "foobar"

ok := t.String(got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

got := errors.New("foobar")

ok := t.String(got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := t.String(got, "foobar", "checks %s", got)
fmt.Println(ok)

Output:

true

func (*T) Struct Uses

func (t *T) Struct(got interface{}, model interface{}, expectedFields StructFields, args ...interface{}) bool

Struct is a shortcut for:

t.CmpDeeply(got, Struct(model, expectedFields), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Struct for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

type Person struct {
    Name        string
    Age         int
    NumChildren int
}

got := Person{
    Name:        "Foobar",
    Age:         42,
    NumChildren: 3,
}

// As NumChildren is zero in Struct() call, it is not checked
ok := t.Struct(got, Person{Name: "Foobar"}, StructFields{
    "Age": Between(40, 50),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Model can be empty
ok = t.Struct(got, Person{}, StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Works with pointers too
ok = t.Struct(&got, &Person{}, StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

// Model does not need to be instanciated
ok = t.Struct(&got, (*Person)(nil), StructFields{
    "Name":        "Foobar",
    "Age":         Between(40, 50),
    "NumChildren": Not(0),
},
    "checks %v is the right Person")
fmt.Println(ok)

Output:

true
true
true
true

func (*T) SubBagOf Uses

func (t *T) SubBagOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool

SubBagOf is a shortcut for:

t.CmpDeeply(got, SubBagOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubBagOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := t.SubBagOf(got, []interface{}{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 8, 9, 9},
    "checks at least all items are present, in any order")
fmt.Println(ok)

// got contains one 8 too many
ok = t.SubBagOf(got, []interface{}{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 9, 9},
    "checks at least all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 2}

ok = t.SubBagOf(got, []interface{}{Between(0, 3), Between(0, 3), Between(0, 3), Between(0, 3), Gt(4), Gt(4)},
    "checks at least all items match, in any order with TestDeep operators")
fmt.Println(ok)

Output:

true
false
true

func (*T) SubMapOf Uses

func (t *T) SubMapOf(got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

SubMapOf is a shortcut for:

t.CmpDeeply(got, SubMapOf(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubMapOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := map[string]int{"foo": 12, "bar": 42}

ok := t.SubMapOf(got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42}

ok := t.SubMapOf(got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks typed map %v is included in expected keys/values", got)
fmt.Println(ok)

ok = t.SubMapOf(&got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666},
    "checks pointed typed map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true
true

func (*T) SubSetOf Uses

func (t *T) SubSetOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool

SubSetOf is a shortcut for:

t.CmpDeeply(got, SubSetOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SubSetOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are expected, ignoring duplicates
ok := t.SubSetOf(got, []interface{}{1, 2, 3, 4, 5, 6, 7, 8},
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several SubSetOf entries
ok = t.SubSetOf(got, []interface{}{Between(1, 4), 3, Between(2, 10), Gt(100)},
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

Output:

true
true

func (*T) SuperBagOf Uses

func (t *T) SuperBagOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool

SuperBagOf is a shortcut for:

t.CmpDeeply(got, SuperBagOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperBagOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := t.SuperBagOf(got, []interface{}{8, 5, 8},
    "checks the items are present, in any order")
fmt.Println(ok)

ok = t.SuperBagOf(got, []interface{}{Gt(5), Lte(2)},
    "checks at least 2 items of %v match", got)
fmt.Println(ok)

Output:

true
true

func (*T) SuperMapOf Uses

func (t *T) SuperMapOf(got interface{}, model interface{}, expectedEntries MapEntries, args ...interface{}) bool

SuperMapOf is a shortcut for:

t.CmpDeeply(got, SuperMapOf(model, expectedEntries), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperMapOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := t.SuperMapOf(got, map[string]int{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := NewT(&testing.T{})

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := t.SuperMapOf(got, MyMap{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks typed map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

ok = t.SuperMapOf(&got, &MyMap{"bar": 42}, MapEntries{"foo": Lt(15)},
    "checks pointed typed map %v contains at leat all expected keys/values",
    got)
fmt.Println(ok)

Output:

true
true

func (*T) SuperSetOf Uses

func (t *T) SuperSetOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool

SuperSetOf is a shortcut for:

t.CmpDeeply(got, SuperSetOf(expectedItems...), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#SuperSetOf for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := t.SuperSetOf(got, []interface{}{1, 2, 3},
    "checks the items are present, in any order and ignoring duplicates")
fmt.Println(ok)

ok = t.SuperSetOf(got, []interface{}{Gt(5), Lte(2)},
    "checks at least 2 items of %v match ignoring duplicates", got)
fmt.Println(ok)

Output:

true
true

func (*T) True Uses

func (t *T) True(got interface{}, args ...interface{}) bool

True is shortcut for:

t.CmpDeeply(got, true, args...)

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

got := true
ok := t.True(got, "check that got is true!")
fmt.Println(ok)

got = false
ok = t.True(got, "check that got is true!")
fmt.Println(ok)

Output:

true
false

func (*T) TruncTime Uses

func (t *T) TruncTime(got interface{}, expectedTime interface{}, trunc time.Duration, args ...interface{}) bool

TruncTime is a shortcut for:

t.CmpDeeply(got, TruncTime(expectedTime, trunc), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#TruncTime for details.

TruncTime() optional parameter "trunc" is here mandatory. 0 value should be passed to mimic its absence in original TruncTime() call.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

dateToTime := func(str string) time.Time {
    t, err := time.Parse(time.RFC3339Nano, str)
    if err != nil {
        panic(err)
    }
    return t
}

got := dateToTime("2018-05-01T12:45:53.123456789Z")

// Compare dates ignoring nanoseconds and monotonic parts
expected := dateToTime("2018-05-01T12:45:53Z")
ok := t.TruncTime(got, expected, time.Second,
    "checks date %v, truncated to the second", got)
fmt.Println(ok)

// Compare dates ignoring time and so monotonic parts
expected = dateToTime("2018-05-01T11:22:33.444444444Z")
ok = t.TruncTime(got, expected, 24*time.Hour,
    "checks date %v, truncated to the day", got)
fmt.Println(ok)

// Compare dates exactly but ignoring monotonic part
expected = dateToTime("2018-05-01T12:45:53.123456789Z")
ok = t.TruncTime(got, expected, 0,
    "checks date %v ignoring monotonic part", got)
fmt.Println(ok)

Output:

true
true
true

func (*T) Zero Uses

func (t *T) Zero(got interface{}, args ...interface{}) bool

Zero is a shortcut for:

t.CmpDeeply(got, Zero(), args...)

See https://godoc.org/github.com/maxatome/go-testdeep#Zero for details.

Returns true if the test is OK, false if it fails.

"args..." are optional and allow to name the test. This name is logged as is in case of failure. If len(args) > 1 and the first item of args is a string and contains a '%' rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint.

Code:

t := NewT(&testing.T{})

ok := t.Zero(0)
fmt.Println(ok)

ok = t.Zero(float64(0))
fmt.Println(ok)

ok = t.Zero(12) // fails, as 12 is not 0 :)
fmt.Println(ok)

ok = t.Zero((map[string]int)(nil))
fmt.Println(ok)

ok = t.Zero(map[string]int{}) // fails, as not nil
fmt.Println(ok)

ok = t.Zero(([]int)(nil))
fmt.Println(ok)

ok = t.Zero([]int{}) // fails, as not nil
fmt.Println(ok)

ok = t.Zero([3]int{})
fmt.Println(ok)

ok = t.Zero([3]int{0, 1}) // fails, DATA[1] is not 0
fmt.Println(ok)

ok = t.Zero(bytes.Buffer{})
fmt.Println(ok)

ok = t.Zero(&bytes.Buffer{}) // fails, as pointer not nil
fmt.Println(ok)

ok = t.CmpDeeply(&bytes.Buffer{}, Ptr(Zero())) // OK with the help of Ptr()
fmt.Println(ok)

Output:

true
true
false
true
false
true
false
true
false
true
false
true

type TestDeep Uses

type TestDeep interface {
    types.TestDeepStringer
    Match(ctx ctxerr.Context, got reflect.Value) *ctxerr.Error
    location.GetLocationer

    HandleInvalid() bool
    TypeBehind() reflect.Type
    // contains filtered or unexported methods
}

TestDeep is the representation of a testdeep operator. It is not intended to be used directly, but through Cmp* functions.

func All Uses

func All(expectedValues ...interface{}) TestDeep

All operator compares data against several expected values. During a match, all of them have to match to succeed.

TypeBehind method can return a non-nil reflect.Type if all items known non-interface types are equal, or if only interface types are found (mostly issued from Isa()) and they are equal.

Code:

t := &testing.T{}

got := "foo/bar"

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "foo/bar" string
ok := CmpDeeply(t,
    got,
    All(Re("o/b"), HasSuffix("bar"), "foo/bar"),
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "o/b" regexp *AND* "bar" suffix *AND* exact "fooX/Ybar" string
ok = CmpDeeply(t,
    got,
    All(Re("o/b"), HasSuffix("bar"), "fooX/Ybar"),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func Any Uses

func Any(expectedValues ...interface{}) TestDeep

Any operator compares data against several expected values. During a match, at least one of them has to match to succeed.

TypeBehind method can return a non-nil reflect.Type if all items known non-interface types are equal, or if only interface types are found (mostly issued from Isa()) and they are equal.

Code:

t := &testing.T{}

got := "foo/bar"

// Checks got string against:
//   "zip" regexp *OR* "bar" suffix
ok := CmpDeeply(t, got, Any(Re("zip"), HasSuffix("bar")),
    "checks value %s", got)
fmt.Println(ok)

// Checks got string against:
//   "zip" regexp *OR* "foo" suffix
ok = CmpDeeply(t, got, Any(Re("zip"), HasSuffix("foo")),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func Array Uses

func Array(model interface{}, expectedEntries ArrayEntries) TestDeep

Array operator compares the contents of an array or a pointer on an array against the non-zero values of "model" (if any) and the values of "expectedEntries".

"model" must be the same type as compared data.

"expectedEntries" can be nil, if no zero entries are expected and no TestDeep operator are involved.

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

got := [3]int{42, 58, 26}

ok := CmpDeeply(t, got, Array([3]int{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks array %v", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := CmpDeeply(t, got, Array(MyArray{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks typed array %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got, Array(&MyArray{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Array(&MyArray{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks pointer on typed array %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Array((*MyArray)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks pointer on typed array %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func ArrayEach Uses

func ArrayEach(expectedValue interface{}) TestDeep

ArrayEach operator has to be applied on arrays or slices or on pointers on array/slice. It compares each item of data array/slice against expected value. During a match, all items have to match to succeed.

Code:

t := &testing.T{}

got := [3]int{42, 58, 26}

ok := CmpDeeply(t, got, ArrayEach(Between(25, 60)),
    "checks each item of array %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := []int{42, 58, 26}

ok := CmpDeeply(t, got, ArrayEach(Between(25, 60)),
    "checks each item of slice %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyArray [3]int

got := MyArray{42, 58, 26}

ok := CmpDeeply(t, got, ArrayEach(Between(25, 60)),
    "checks each item of typed array %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got, ArrayEach(Between(25, 60)),
    "checks each item of typed array pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

type MySlice []int

got := MySlice{42, 58, 26}

ok := CmpDeeply(t, got, ArrayEach(Between(25, 60)),
    "checks each item of typed slice %v is in [25 .. 60]", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got, ArrayEach(Between(25, 60)),
    "checks each item of typed slice pointer %v is in [25 .. 60]", got)
fmt.Println(ok)

Output:

true
true

func Bag Uses

func Bag(expectedItems ...interface{}) TestDeep

Bag operator compares the contents of an array or a slice (or a pointer on array/slice) without taking care of the order of items.

During a match, each expected item should match in the compared array/slice, and each array/slice item should be matched by an expected item to succeed.

CmpDeeply(t, []int{1, 1, 2}, Bag(1, 1, 2))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, Bag(1, 2, 1))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, Bag(2, 1, 1))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, Bag(1, 2))       // fails, one 1 is missing
CmpDeeply(t, []int{1, 1, 2}, Bag(1, 2, 1, 3)) // fails, 3 is missing

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present
ok := CmpDeeply(t, got, Bag(1, 1, 2, 3, 5, 8, 8),
    "checks all items are present, in any order")
fmt.Println(ok)

// Does not match as got contains 2 times 1 and 8, and these
// duplicates are not expected
ok = CmpDeeply(t, got, Bag(1, 2, 3, 5, 8),
    "checks all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 8, 2}

// Duplicates of 1 and 8 are expected but not present in got
ok = CmpDeeply(t, got, Bag(1, 1, 2, 3, 5, 8, 8),
    "checks all items are present, in any order")
fmt.Println(ok)

// Matches as all items are present
ok = CmpDeeply(t, got, Bag(1, 2, 3, 5, Gt(7)),
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
false
false
true

func Between Uses

func Between(from interface{}, to interface{}, bounds ...BoundsKind) TestDeep

Between operator checks that data is between "from" and "to". "from" and "to" can be any numeric, string or time.Time (or assignable) value. "from" and "to" must be the same kind as the compared value if numeric, and the same type if string or time.Time (or assignable). "bounds" allows to specify whether bounds are included or not. See Bounds* constants for details. If "bounds" is missing, it defaults to BoundsInIn.

TypeBehind method returns the reflect.Type of "from" (same as the "to" one.)

Code:

t := &testing.T{}

got := 156

ok := CmpDeeply(t, got, Between(154, 156),
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = CmpDeeply(t, got, Between(154, 156, BoundsInIn),
    "checks %v is in [154 .. 156]", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between(154, 156, BoundsInOut),
    "checks %v is in [154 .. 156[", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between(154, 156, BoundsOutIn),
    "checks %v is in ]154 .. 156]", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between(154, 156, BoundsOutOut),
    "checks %v is in ]154 .. 156[", got)
fmt.Println(ok)

Output:

true
true
false
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpDeeply(t, got, Between("aaa", "abc"),
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

// BoundsInIn is implicit
ok = CmpDeeply(t, got, Between("aaa", "abc", BoundsInIn),
    `checks "%v" is in ["aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between("aaa", "abc", BoundsInOut),
    `checks "%v" is in ["aaa" .. "abc"[`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between("aaa", "abc", BoundsOutIn),
    `checks "%v" is in ]"aaa" .. "abc"]`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Between("aaa", "abc", BoundsOutOut),
    `checks "%v" is in ]"aaa" .. "abc"[`, got)
fmt.Println(ok)

Output:

true
true
false
true
false

func Cap Uses

func Cap(val interface{}) TestDeep

Cap is a smuggler operator. It takes data, applies cap() function on it and compares its result to "val". Of course, the compared value must be an array, a channel or a slice.

"val" can be an int value:

Cap(12)

as well as an other operator:

Cap(Between(3, 4))

Code:

t := &testing.T{}

got := make([]int, 0, 12)

ok := CmpDeeply(t, got, Cap(12), "checks %v capacity is 12", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Cap(0), "checks %v capacity is 0", got)
fmt.Println(ok)

got = nil

ok = CmpDeeply(t, got, Cap(0), "checks %v capacity is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := make([]int, 0, 12)

ok := CmpDeeply(t, got, Cap(Between(10, 12)),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Cap(Gt(10)),
    "checks %v capacity is in [10 .. 12]", got)
fmt.Println(ok)

Output:

true
true

func Code Uses

func Code(fn interface{}) TestDeep

Code operator allows to check data using a custom function. So "fn" is a function that must take one parameter whose type must be the same as the type of the compared value.

"fn" can return a single bool kind value, telling that yes or no the custom test is successful:

Code(func (date time.Time) bool {
    return date.Year() == 2018
  })

or two values (bool, string) kinds. The bool value has the same meaning as above, and the string value is used to describe the test when it fails:

Code(func (date time.Time) (bool, string) {
    if date.Year() == 2018 {
      return true, ""
    }
    return false, "year must be 2018"
  })

or a single error value. If the returned error is nil, the test succeeded, else the error contains the reason of failure:

Code(func (b json.RawMessage) error {
    var c map[string]int
    err := json.Unmarshal(b, &c)
    if err != nil {
      return err
    }
    if c["test"] != 42 {
      return fmt.Errorf(`key "test" does not match 42`)
    }
    return nil
  })

This operator allows to handle any specific comparison not handled by standard operators.

It is not recommended to call CmpDeeply (or any other Cmp* functions or *T methods) inside the body of "fn", because of confusion produced by output in case of failure. When the data needs to be transformed before being compared again, Smuggle operator should be used instead.

TypeBehind method returns the reflect.Type of only parameter of "fn".

Code:

t := &testing.T{}

got := "12"

ok := CmpDeeply(t, got,
    Code(func(num string) bool {
        n, err := strconv.Atoi(num)
        return err == nil && n > 10 && n < 100
    }),
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason
ok = CmpDeeply(t, got,
    Code(func(num string) (bool, string) {
        n, err := strconv.Atoi(num)
        if err != nil {
            return false, "not a number"
        }
        if n > 10 && n < 100 {
            return true, ""
        }
        return false, "not in ]10 .. 100["
    }),
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

// Same with failure reason thanks to error
ok = CmpDeeply(t, got,
    Code(func(num string) error {
        n, err := strconv.Atoi(num)
        if err != nil {
            return err
        }
        if n > 10 && n < 100 {
            return nil
        }
        return fmt.Errorf("%d not in ]10 .. 100[", n)
    }),
    "checks string `%s` contains a number and this number is in ]10 .. 100[",
    got)
fmt.Println(ok)

Output:

true
true
true

func Contains Uses

func Contains(expectedValue interface{}) TestDeep

Contains is a smuggler operator with a little convenient exception for strings. Contains has to be applied on arrays, slices, maps or strings. It compares each item of data array/slice/map/string (rune for strings) against "expectedValue".

list := []int{12, 34, 28}
CmpDeeply(t, list, Contains(34))              // succeeds
CmpDeeply(t, list, Contains(Between(30, 35))) // succeeds too
CmpDeeply(t, list, Contains(35))              // fails

hash := map[string]int{"foo": 12, "bar": 34, "zip": 28}
CmpDeeply(t, hash, Contains(34))              // succeeds
CmpDeeply(t, hash, Contains(Between(30, 35))) // succeeds too
CmpDeeply(t, hash, Contains(35))              // fails

got := "foo bar"
CmpDeeply(t, hash, Contains('o'))               // succeeds
CmpDeeply(t, hash, Contains(rune('o')))         // succeeds
CmpDeeply(t, hash, Contains(Between('n', 'p'))) // succeeds

When Contains(nil) is used, nil is automatically converted to a typed nil on the fly to avoid confusion (if the array/slice/map item type allows it of course.) So all following CmpDeeply calls are equivalent (except the (*byte)(nil) one):

num := 123
list := []*int{&num, nil}
CmpDeeply(t, list, Contains(nil))         // succeeds → (*int)(nil)
CmpDeeply(t, list, Contains((*int)(nil))) // succeeds
CmpDeeply(t, list, Contains(Nil()))       // succeeds
// But...
CmpDeeply(t, list, Contains((*byte)(nil))) // fails: (*byte)(nil) ≠ (*int)(nil)

As well as these ones:

hash := map[string]*int{"foo": nil, "bar": &num}
CmpDeeply(t, hash, Contains(nil))         // succeeds → (*int)(nil)
CmpDeeply(t, hash, Contains((*int)(nil))) // succeeds
CmpDeeply(t, hash, Contains(Nil()))       // succeeds

As a special case for string (or convertible), error or fmt.Stringer interface (error interface is tested before fmt.Stringer), "expectedValue" can be a string, a rune or a byte. In this case, it will test if the got string contains this expected string, rune or byte.

type Foobar string
CmpDeeply(t, Foobar("foobar"), Contains("ooba")) // succeeds

err := errors.New("error!")
CmpDeeply(t, err, Contains("ror")) // succeeds

bstr := bytes.NewBufferString("fmt.Stringer!")
CmpDeeply(t, bstr, Contains("String")) // succeeds

Code:

t := &testing.T{}

ok := CmpDeeply(t, [...]int{11, 22, 33, 44}, Contains(22))
fmt.Println("array contains 22:", ok)

ok = CmpDeeply(t, [...]int{11, 22, 33, 44}, Contains(Between(20, 25)))
fmt.Println("array contains at least one item in [20 .. 25]:", ok)

ok = CmpDeeply(t, []int{11, 22, 33, 44}, Contains(22))
fmt.Println("slice contains 22:", ok)

ok = CmpDeeply(t, []int{11, 22, 33, 44}, Contains(Between(20, 25)))
fmt.Println("slice contains at least one item in [20 .. 25]:", ok)

Output:

array contains 22: true
array contains at least one item in [20 .. 25]: true
slice contains 22: true
slice contains at least one item in [20 .. 25]: true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpDeeply(t, got, Contains("oob"), "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpDeeply(t, got, Contains('b'), "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpDeeply(t, got, Contains(byte('a')), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = CmpDeeply(t, got, Contains(Between('n', 'p')), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

Code:

t := &testing.T{}

ok := CmpDeeply(t,
    map[string]int{"foo": 11, "bar": 22, "zip": 33}, Contains(22))
fmt.Println("map contains value 22:", ok)

ok = CmpDeeply(t,
    map[string]int{"foo": 11, "bar": 22, "zip": 33},
    Contains(Between(20, 25)))
fmt.Println("map contains at least one value in [20 .. 25]:", ok)

Output:

map contains value 22: true
map contains at least one value in [20 .. 25]: true

Code:

t := &testing.T{}

num := 123
got := [...]*int{&num, nil}

ok := CmpDeeply(t, got, Contains(nil))
fmt.Println("array contains untyped nil:", ok)

ok = CmpDeeply(t, got, Contains((*int)(nil)))
fmt.Println("array contains *int nil:", ok)

ok = CmpDeeply(t, got, Contains(Nil()))
fmt.Println("array contains Nil():", ok)

ok = CmpDeeply(t, got, Contains((*byte)(nil)))
fmt.Println("array contains *byte nil:", ok) // types differ: *byte ≠ *int

Output:

array contains untyped nil: true
array contains *int nil: true
array contains Nil(): true
array contains *byte nil: false

Code:

t := &testing.T{}

got := "foobar"

ok := CmpDeeply(t, got, Contains("oob"), "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpDeeply(t, got, Contains('b'), "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpDeeply(t, got, Contains(byte('a')), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

ok = CmpDeeply(t, got, Contains(Between('n', 'p')), "checks %s", got)
fmt.Println("contains at least one character ['n' .. 'p']:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
contains at least one character ['n' .. 'p']: true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpDeeply(t, got, Contains("oob"), "checks %s", got)
fmt.Println("contains `oob` string:", ok)

ok = CmpDeeply(t, got, Contains('b'), "checks %s", got)
fmt.Println("contains 'b' rune:", ok)

ok = CmpDeeply(t, got, Contains(byte('a')), "checks %s", got)
fmt.Println("contains 'a' byte:", ok)

// Be careful! TestDeep operators in Contains() do not work with
// fmt.Stringer nor error interfaces
ok = CmpDeeply(t, got, Contains(Between('n', 'p')), "checks %s", got)
fmt.Println("try TestDeep operator:", ok)

Output:

contains `oob` string: true
contains 'b' rune: true
contains 'a' byte: true
try TestDeep operator: false

func ContainsKey Uses

func ContainsKey(expectedValue interface{}) TestDeep

ContainsKey is a smuggler operator and works on maps only. It compares each key of map against "expectedValue".

hash := map[string]int{"foo": 12, "bar": 34, "zip": 28}
CmpDeeply(t, hash, ContainsKey("foo"))          // succeeds
CmpDeeply(t, hash, ContainsKey(HasPrefix("z"))) // succeeds
CmpDeeply(t, hash, ContainsKey(HasPrefix("x"))  // fails

hnum := map[int]string{1: "foo", 42: "bar"}
CmpDeeply(t, hash, ContainsKey(42))             // succeeds
CmpDeeply(t, hash, ContainsKey(Between(40, 45)) // succeeds

When ContainsKey(nil) is used, nil is automatically converted to a typed nil on the fly to avoid confusion (if the map key type allows it of course.) So all following CmpDeeply calls are equivalent (except the (*byte)(nil) one):

num := 123
hnum := map[*int]bool{&num: true, nil: true}
CmpDeeply(t, hnum, ContainsKey(nil))          // succeeds → (*int)(nil)
CmpDeeply(t, hnum, ContainsKey((*int)(nil)))  // succeeds
CmpDeeply(t, hnum, ContainsKey(Nil()))        // succeeds
// But...
CmpDeeply(t, hnum, ContainsKey((*byte)(nil))) // fails: (*byte)(nil) ≠ (*int)(nil)

Code:

t := &testing.T{}

ok := CmpDeeply(t,
    map[string]int{"foo": 11, "bar": 22, "zip": 33}, ContainsKey("foo"))
fmt.Println(`map contains key "foo":`, ok)

ok = CmpDeeply(t,
    map[int]bool{12: true, 24: false, 42: true, 51: false},
    ContainsKey(Between(40, 50)))
fmt.Println("map contains at least a key in [40 .. 50]:", ok)

Output:

map contains key "foo": true
map contains at least a key in [40 .. 50]: true

Code:

t := &testing.T{}

num := 1234
got := map[*int]bool{&num: false, nil: true}

ok := CmpDeeply(t, got, ContainsKey(nil))
fmt.Println("map contains untyped nil key:", ok)

ok = CmpDeeply(t, got, ContainsKey((*int)(nil)))
fmt.Println("map contains *int nil key:", ok)

ok = CmpDeeply(t, got, ContainsKey(Nil()))
fmt.Println("map contains Nil() key:", ok)

ok = CmpDeeply(t, got, ContainsKey((*byte)(nil)))
fmt.Println("map contains *byte nil key:", ok) // types differ: *byte ≠ *int

Output:

map contains untyped nil key: true
map contains *int nil key: true
map contains Nil() key: true
map contains *byte nil key: false

func Empty Uses

func Empty() TestDeep

Empty operator checks that an array, a channel, a map, a slice or a string is empty. As a special case (non-typed) nil, as well as nil channel, map or slice are considered empty.

Note that the compared data can be a pointer (of pointer of pointer etc.) on an array, a channel, a map, a slice or a string.

Code:

t := &testing.T{}

ok := CmpDeeply(t, nil, Empty()) // special case: nil is considered empty
fmt.Println(ok)

// fails, typed nil is not empty (expect for channel, map, slice or
// pointers on array, channel, map slice and strings)
ok = CmpDeeply(t, (*int)(nil), Empty())
fmt.Println(ok)

ok = CmpDeeply(t, "", Empty())
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use Zero() instead
ok = CmpDeeply(t, 0, Empty())
fmt.Println(ok)

ok = CmpDeeply(t, (map[string]int)(nil), Empty())
fmt.Println(ok)

ok = CmpDeeply(t, map[string]int{}, Empty())
fmt.Println(ok)

ok = CmpDeeply(t, ([]int)(nil), Empty())
fmt.Println(ok)

ok = CmpDeeply(t, []int{}, Empty())
fmt.Println(ok)

ok = CmpDeeply(t, []int{3}, Empty()) // fails, as not empty
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{}, Empty()) // fails, Empty() is not Zero()!
fmt.Println(ok)

Output:

true
false
true
false
true
true
true
true
false
false

Code:

t := &testing.T{}

type MySlice []int

ok := CmpDeeply(t, MySlice{}, Empty()) // Ptr() not needed
fmt.Println(ok)

ok = CmpDeeply(t, &MySlice{}, Empty())
fmt.Println(ok)

l1 := &MySlice{}
l2 := &l1
l3 := &l2
ok = CmpDeeply(t, &l3, Empty())
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = CmpDeeply(t, &MyStruct{}, Empty()) // fails, use Zero() instead
fmt.Println(ok)

Output:

true
true
true
false

func Gt Uses

func Gt(val interface{}) TestDeep

Gt operator checks that data is greater than "val". "val" can be any numeric or time.Time (or assignable) value. "val" must be the same kind as the compared value if numeric, and the same type if time.Time (or assignable).

TypeBehind method returns the reflect.Type of "val".

Code:

t := &testing.T{}

got := 156

ok := CmpDeeply(t, got, Gt(155), "checks %v is > 155", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gt(156), "checks %v is > 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpDeeply(t, got, Gt("abb"), `checks "%v" is > "abb"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gt("abc"), `checks "%v" is > "abc"`, got)
fmt.Println(ok)

Output:

true
false

func Gte Uses

func Gte(val interface{}) TestDeep

Gte operator checks that data is greater or equal than "val". "val" can be any numeric or time.Time (or assignable) value. "val" must be the same kind as the compared value if numeric, and the same type if time.Time (or assignable).

TypeBehind method returns the reflect.Type of "val".

Code:

t := &testing.T{}

got := 156

ok := CmpDeeply(t, got, Gte(156), "checks %v is ≥ 156", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gte(155), "checks %v is ≥ 155", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gte(157), "checks %v is ≥ 157", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpDeeply(t, got, Gte("abc"), `checks "%v" is ≥ "abc"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gte("abb"), `checks "%v" is ≥ "abb"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Gte("abd"), `checks "%v" is ≥ "abd"`, got)
fmt.Println(ok)

Output:

true
true
false

func HasPrefix Uses

func HasPrefix(expected string) TestDeep

HasPrefix operator allows to compare the prefix of a string (or convertible), error or fmt.Stringer interface (error interface is tested before fmt.Stringer.)

type Foobar string
CmpDeeply(t, Foobar("foobar"), HasPrefix("foo")) // succeeds

err := errors.New("error!")
CmpDeeply(t, err, HasPrefix("err")) // succeeds

bstr := bytes.NewBufferString("fmt.Stringer!")
CmpDeeply(t, bstr, HasPrefix("fmt")) // succeeds

Code:

t := &testing.T{}

got := "foobar"

ok := CmpDeeply(t, got, HasPrefix("foo"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpDeeply(t, got, HasPrefix("foo"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpDeeply(t, got, HasPrefix("foo"), "checks %s", got)
fmt.Println(ok)

Output:

true

func HasSuffix Uses

func HasSuffix(expected string) TestDeep

HasSuffix operator allows to compare the suffix of a string (or convertible), error or fmt.Stringer interface (error interface is tested before fmt.Stringer.)

type Foobar string
CmpDeeply(t, Foobar("foobar"), HasSuffix("bar")) // succeeds

err := errors.New("error!")
CmpDeeply(t, err, HasSuffix("!")) // succeeds

bstr := bytes.NewBufferString("fmt.Stringer!")
CmpDeeply(t, bstr, HasSuffix("!")) // succeeds

Code:

t := &testing.T{}

got := "foobar"

ok := CmpDeeply(t, got, HasSuffix("bar"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpDeeply(t, got, HasSuffix("bar"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpDeeply(t, got, HasSuffix("bar"), "checks %s", got)
fmt.Println(ok)

Output:

true

func Ignore Uses

func Ignore() TestDeep

Ignore operator is always true, whatever data is. It is useful when comparing a slice and wanting to ignore some indexes, for example.

Code:

t := &testing.T{}

ok := CmpDeeply(t, []int{1, 2, 3},
    Slice([]int{}, ArrayEntries{
        0:  1,
        1:  Ignore(), // do not care about this entry
        2:  3,
    }))
fmt.Println(ok)

Output:

true

func Isa Uses

func Isa(model interface{}) TestDeep

Isa operator checks the data type or whether data implements an interface or not.

Typically type checks:

Isa(time.Time{})
Isa(&time.Time{})
Isa(map[string]time.Time{})

For interfaces it is a bit more complicated, as:

fmt.Stringer(nil)

is not an interface, but just nil... To bypass this golang limitation, Isa accepts pointers on interfaces. So checking that data implements fmt.Stringer interface should be written as:

Isa((*fmt.Stringer)(nil))

Of course, in the latter case, if data type is *fmt.Stringer, Isa will match too (in fact before checking whether it implements fmt.Stringer or not.)

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

type TstStruct struct {
    Field int
}

got := TstStruct{Field: 1}

ok := CmpDeeply(t, got, Isa(TstStruct{}), "checks got is a TstStruct")
fmt.Println(ok)

ok = CmpDeeply(t, got, Isa(&TstStruct{}),
    "checks got is a pointer on a TstStruct")
fmt.Println(ok)

ok = CmpDeeply(t, &got, Isa(&TstStruct{}),
    "checks &got is a pointer on a TstStruct")
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := bytes.NewBufferString("foobar")

ok := CmpDeeply(t, got, Isa((*fmt.Stringer)(nil)),
    "checks got implements fmt.Stringer interface")
fmt.Println(ok)

errGot := fmt.Errorf("An error #%d occurred", 123)

ok = CmpDeeply(t, errGot, Isa((*error)(nil)),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// As nil, is passed below, it is not an interface but nil... So it
// does not match
errGot = nil

ok = CmpDeeply(t, errGot, Isa((*error)(nil)),
    "checks errGot is a *error or implements error interface")
fmt.Println(ok)

// BUT if its address is passed, now it is OK as the types match
ok = CmpDeeply(t, &errGot, Isa((*error)(nil)),
    "checks &errGot is a *error or implements error interface")
fmt.Println(ok)

Output:

true
true
false
true

func Len Uses

func Len(val interface{}) TestDeep

Len is a smuggler operator. It takes data, applies len() function on it and compares its result to "val". Of course, the compared value must be an array, a channel, a map, a slice or a string.

"val" can be an int value:

Len(12)

as well as an other operator:

Len(Between(3, 4))

Code:

t := &testing.T{}

got := map[int]bool{11: true, 22: false, 33: false}

ok := CmpDeeply(t, got, Len(3), "checks %v len is 3", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Len(0), "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = CmpDeeply(t, got, Len(0), "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

Code:

t := &testing.T{}

got := map[int]bool{11: true, 22: false, 33: false}

ok := CmpDeeply(t, got, Len(Between(3, 8)),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Len(Gte(3)), "checks %v len is ≥ 3", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

got := []int{11, 22, 33}

ok := CmpDeeply(t, got, Len(Between(3, 8)),
    "checks %v len is in [3 .. 8]", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Len(Lt(5)), "checks %v len is < 5", got)
fmt.Println(ok)

Output:

true
true

Code:

t := &testing.T{}

got := []int{11, 22, 33}

ok := CmpDeeply(t, got, Len(3), "checks %v len is 3", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Len(0), "checks %v len is 0", got)
fmt.Println(ok)

got = nil

ok = CmpDeeply(t, got, Len(0), "checks %v len is 0", got)
fmt.Println(ok)

Output:

true
false
true

func Lt Uses

func Lt(val interface{}) TestDeep

Lt operator checks that data is lesser than "val". "val" can be any numeric or time.Time (or assignable) value. "val" must be the same kind as the compared value if numeric, and the same type if time.Time (or assignable).

TypeBehind method returns the reflect.Type of "val".

Code:

t := &testing.T{}

got := 156

ok := CmpDeeply(t, got, Lt(157), "checks %v is < 157", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lt(156), "checks %v is < 156", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpDeeply(t, got, Lt("abd"), `checks "%v" is < "abd"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lt("abc"), `checks "%v" is < "abc"`, got)
fmt.Println(ok)

Output:

true
false

func Lte Uses

func Lte(val interface{}) TestDeep

Lte operator checks that data is lesser or equal than "val". "val" can be any numeric or time.Time (or assignable) value. "val" must be the same kind as the compared value if numeric, and the same type if time.Time (or assignable).

TypeBehind method returns the reflect.Type of "val".

Code:

t := &testing.T{}

got := 156

ok := CmpDeeply(t, got, Lte(156), "checks %v is ≤ 156", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lte(157), "checks %v is ≤ 157", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lte(155), "checks %v is ≤ 155", got)
fmt.Println(ok)

Output:

true
true
false

Code:

t := &testing.T{}

got := "abc"

ok := CmpDeeply(t, got, Lte("abc"), `checks "%v" is ≤ "abc"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lte("abd"), `checks "%v" is ≤ "abd"`, got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Lte("abb"), `checks "%v" is ≤ "abb"`, got)
fmt.Println(ok)

Output:

true
true
false

func Map Uses

func Map(model interface{}, expectedEntries MapEntries) TestDeep

Map operator compares the contents of a map against the non-zero values of "model" (if any) and the values of "expectedEntries".

"model" must be the same type as compared data.

"expectedEntries" can be nil, if no zero entries are expected and no TestDeep operator are involved.

During a match, all expected entries must be found and all data entries must be expected to succeed.

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got,
    Map(map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()}),
    "checks map %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, got,
    Map(map[string]int{},
        MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()}),
    "checks map %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, got,
    Map((map[string]int)(nil),
        MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()}),
    "checks map %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got,
    Map(MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()}),
    "checks typed map %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Map(&MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": Ignore()}),
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Map(&MyMap{}, MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()}),
    "checks pointer on typed map %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Map((*MyMap)(nil), MapEntries{"bar": 42, "foo": Lt(15), "zip": Ignore()}),
    "checks pointer on typed map %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func MapEach Uses

func MapEach(expectedValue interface{}) TestDeep

MapEach operator has to be applied on maps. It compares each value of data map against expected value. During a match, all values have to match to succeed.

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got, MapEach(Between(10, 90)),
    "checks each value of map %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got, MapEach(Between(10, 90)),
    "checks each value of typed map %v is in [10 .. 90]", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got, MapEach(Between(10, 90)),
    "checks each value of typed map pointer %v is in [10 .. 90]", got)
fmt.Println(ok)

Output:

true
true

func N Uses

func N(num interface{}, tolerance ...interface{}) TestDeep

N operator compares a numeric data against "num" ± "tolerance". If "tolerance" is missing, it defaults to 0. "num" and "tolerance" must be the same kind as the compared value.

TypeBehind method returns the reflect.Type of "num".

Code:

t := &testing.T{}

got := 1.12345

ok := CmpDeeply(t, got, N(1.1234, 0.00006),
    "checks %v = 1.1234 ± 0.00006", got)
fmt.Println(ok)

Output:

true

func NaN Uses

func NaN() TestDeep

NaN operator checks that data is a float and is not-a-number.

Code:

t := &testing.T{}

got := float32(math.NaN())

ok := CmpDeeply(t, got, NaN(),
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is float32 not-a-number:", ok)

got = 12

ok = CmpDeeply(t, got, NaN(),
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is float32 not-a-number:", ok)

Output:

float32(math.NaN()) is float32 not-a-number: true
float32(12) is float32 not-a-number: false

Code:

t := &testing.T{}

got := math.NaN()

ok := CmpDeeply(t, got, NaN(),
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = CmpDeeply(t, got, NaN(),
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is not-a-number: true
// float64(12) is not-a-number: false

func Nil Uses

func Nil() TestDeep

Nil operator checks that data is nil (or is a non-nil interface, but containing a nil pointer.)

Code:

t := &testing.T{}

var got fmt.Stringer // interface

// nil value can be compared directly with nil, no need of Nil() here
ok := CmpDeeply(t, got, nil)
fmt.Println(ok)

// But it works with Nil() anyway
ok = CmpDeeply(t, got, Nil())
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with nil fails, as the interface is not nil
ok = CmpDeeply(t, got, nil)
fmt.Println(ok)

// In this case Nil() succeed
ok = CmpDeeply(t, got, Nil())
fmt.Println(ok)

Output:

true
true
false
true

func None Uses

func None(expectedValues ...interface{}) TestDeep

None operator compares data against several expected values. During a match, none of them have to match to succeed.

Code:

t := &testing.T{}

got := 18

ok := CmpDeeply(t, got, None(0, 10, 20, 30, Between(100, 199)),
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 20

ok = CmpDeeply(t, got, None(0, 10, 20, 30, Between(100, 199)),
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

got = 142

ok = CmpDeeply(t, got, None(0, 10, 20, 30, Between(100, 199)),
    "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)
fmt.Println(ok)

Output:

true
false
false

func Not Uses

func Not(expected interface{}) TestDeep

Not operator compares data against the expected value. During a match, it must not match to succeed.

Not is the same operator as None() with only one argument. It is provided as a more readable function when only one argument is needed.

Code:

t := &testing.T{}

got := 42

ok := CmpDeeply(t, got, Not(0), "checks %v is non-null", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, Not(Between(10, 30)),
    "checks %v is not in [10 .. 30]", got)
fmt.Println(ok)

got = 0

ok = CmpDeeply(t, got, Not(0), "checks %v is non-null", got)
fmt.Println(ok)

Output:

true
true
false

func NotAny Uses

func NotAny(expectedItems ...interface{}) TestDeep

NotAny operator checks that the contents of an array or a slice (or a pointer on array/slice) does not contain any of "expectedItems".

CmpDeeply(t, []int{1}, NotAny(1, 2, 3)) // fails
CmpDeeply(t, []int{5}, NotAny(1, 2, 3)) // succeeds

Code:

t := &testing.T{}

got := []int{4, 5, 9, 42}

ok := CmpDeeply(t, got, NotAny(3, 6, 8, 41, 43),
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

ok = CmpDeeply(t, got, NotAny(3, 6, 8, 42, 43),
    "checks %v contains no item listed in NotAny()", got)
fmt.Println(ok)

Output:

true
false

func NotEmpty Uses

func NotEmpty() TestDeep

NotEmpty operator checks that an array, a channel, a map, a slice or a string is not empty. As a special case (non-typed) nil, as well as nil channel, map or slice are considered empty.

Note that the compared data can be a pointer (of pointer of pointer etc.) on an array, a channel, a map, a slice or a string.

Code:

t := &testing.T{}

ok := CmpDeeply(t, nil, NotEmpty()) // fails, as nil is considered empty
fmt.Println(ok)

ok = CmpDeeply(t, "foobar", NotEmpty())
fmt.Println(ok)

// Fails as 0 is a number, so not empty. Use NotZero() instead
ok = CmpDeeply(t, 0, NotEmpty())
fmt.Println(ok)

ok = CmpDeeply(t, map[string]int{"foobar": 42}, NotEmpty())
fmt.Println(ok)

ok = CmpDeeply(t, []int{1}, NotEmpty())
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{}, NotEmpty()) // succeeds, NotEmpty() is not NotZero()!
fmt.Println(ok)

Output:

false
true
false
true
true
true

Code:

t := &testing.T{}

type MySlice []int

ok := CmpDeeply(t, MySlice{12}, NotEmpty())
fmt.Println(ok)

ok = CmpDeeply(t, &MySlice{12}, NotEmpty()) // Ptr() not needed
fmt.Println(ok)

l1 := &MySlice{12}
l2 := &l1
l3 := &l2
ok = CmpDeeply(t, &l3, NotEmpty())
fmt.Println(ok)

// Works the same for array, map, channel and string

// But not for others types as:
type MyStruct struct {
    Value int
}

ok = CmpDeeply(t, &MyStruct{}, NotEmpty()) // fails, use NotZero() instead
fmt.Println(ok)

Output:

true
true
true
false

func NotNaN Uses

func NotNaN() TestDeep

NotNaN operator checks that data is a float and is not not-a-number.

Code:

t := &testing.T{}

got := float32(math.NaN())

ok := CmpDeeply(t, got, NotNaN(),
    "checks %v is not-a-number", got)

fmt.Println("float32(math.NaN()) is NOT float32 not-a-number:", ok)

got = 12

ok = CmpDeeply(t, got, NotNaN(),
    "checks %v is not-a-number", got)

fmt.Println("float32(12) is NOT float32 not-a-number:", ok)

Output:

float32(math.NaN()) is NOT float32 not-a-number: false
float32(12) is NOT float32 not-a-number: true

Code:

t := &testing.T{}

got := math.NaN()

ok := CmpDeeply(t, got, NotNaN(),
    "checks %v is not-a-number", got)

fmt.Println("math.NaN() is not-a-number:", ok)

got = 12

ok = CmpDeeply(t, got, NotNaN(),
    "checks %v is not-a-number", got)

fmt.Println("float64(12) is not-a-number:", ok)

// math.NaN() is NOT not-a-number: false
// float64(12) is NOT not-a-number: true

func NotNil Uses

func NotNil() TestDeep

NotNil operator checks that data is not nil (or is a non-nil interface, containing a non-nil pointer.)

Code:

t := &testing.T{}

var got fmt.Stringer = &bytes.Buffer{}

// nil value can be compared directly with Not(nil), no need of NotNil() here
ok := CmpDeeply(t, got, Not(nil))
fmt.Println(ok)

// But it works with NotNil() anyway
ok = CmpDeeply(t, got, NotNil())
fmt.Println(ok)

got = (*bytes.Buffer)(nil)

// In the case of an interface containing a nil pointer, comparing
// with Not(nil) succeeds, as the interface is not nil
ok = CmpDeeply(t, got, Not(nil))
fmt.Println(ok)

// In this case NotNil() fails
ok = CmpDeeply(t, got, NotNil())
fmt.Println(ok)

Output:

true
true
true
false

func NotZero Uses

func NotZero() TestDeep

NotZero operator checks that data is not zero regarding its type.

nil is the zero value of pointers, maps, slices, channels and functions;
0 is the zero value of numbers;
false is the zero value of booleans;
zero value of structs is the struct with no fields initialized.

Beware that:

CmpDeeply(t, AnyStruct{}, NotZero())       // is false
CmpDeeply(t, &AnyStruct{}, NotZero())      // is true, coz pointer ≠ nil
CmpDeeply(t, &AnyStruct{}, Ptr(NotZero())) // is false

Code:

t := &testing.T{}

ok := CmpDeeply(t, 0, NotZero()) // fails
fmt.Println(ok)

ok = CmpDeeply(t, float64(0), NotZero()) // fails
fmt.Println(ok)

ok = CmpDeeply(t, 12, NotZero())
fmt.Println(ok)

ok = CmpDeeply(t, (map[string]int)(nil), NotZero()) // fails, as nil
fmt.Println(ok)

ok = CmpDeeply(t, map[string]int{}, NotZero()) // succeeds, as not nil
fmt.Println(ok)

ok = CmpDeeply(t, ([]int)(nil), NotZero()) // fails, as nil
fmt.Println(ok)

ok = CmpDeeply(t, []int{}, NotZero()) // succeeds, as not nil
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{}, NotZero()) // fails
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{0, 1}, NotZero()) // succeeds, DATA[1] is not 0
fmt.Println(ok)

ok = CmpDeeply(t, bytes.Buffer{}, NotZero()) // fails
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, NotZero()) // succeeds, as pointer not nil
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, Ptr(NotZero())) // fails as deref by Ptr()
fmt.Println(ok)

Output:

false
false
true
false
true
false
true
false
true
false
true
false

func PPtr Uses

func PPtr(val interface{}) TestDeep

PPtr is a smuggler operator. It takes the address of the address of data and compares it to "val".

"val" depends on data type. For example, if the compared data is an **int, one can have:

PPtr(12)

as well as an other operator:

PPtr(Between(3, 4))

It is more efficient and shorter to write than:

Ptr(Ptr(val))

Code:

t := &testing.T{}

num := 12
got := &num

ok := CmpDeeply(t, &got, PPtr(12))
fmt.Println(ok)

ok = CmpDeeply(t, &got, PPtr(Between(4, 15)))
fmt.Println(ok)

Output:

true
true

func Ptr Uses

func Ptr(val interface{}) TestDeep

Ptr is a smuggler operator. It takes the address of data and compares it to "val".

"val" depends on data type. For example, if the compared data is an *int, one can have:

Ptr(12)

as well as an other operator:

Ptr(Between(3, 4))

Code:

t := &testing.T{}

got := 12

ok := CmpDeeply(t, &got, Ptr(12))
fmt.Println(ok)

ok = CmpDeeply(t, &got, Ptr(Between(4, 15)))
fmt.Println(ok)

Output:

true
true

func Re Uses

func Re(reg interface{}, capture ...interface{}) TestDeep

Re operator allows to apply a regexp on a string (or convertible), []byte, error or fmt.Stringer interface (error interface is tested before fmt.Stringer.)

"reg" is the regexp. It can be a string that is automatically compiled using regexp.MustCompile, or a *regexp.Regexp.

Optional "capture" parameter can be used to match the contents of regexp groups. Groups are presented as a []string or [][]byte depending the original matched data. Note that an other operator can be used here.

CmpDeeply(t, "foobar zip!", Re(`^foobar`))     // succeeds
CmpDeeply(t, "John Doe",
  Re(`^(\w+) (\w+)`, []string{"John", "Doe"})) // succeeds
CmpDeeply(t, "John Doe",
  Re(`^(\w+) (\w+)`, Bag("Doe", "John"))       // succeeds

Code:

t := &testing.T{}

got := "foo bar"
ok := CmpDeeply(t, got, Re("(zip|bar)$"), "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = CmpDeeply(t, got, Re("(zip|bar)$"), "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "foo bar biz"
ok := CmpDeeply(t, got, Re(`^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = CmpDeeply(t, got, Re(`^(\w+) (\w+) (\w+)$`, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

got := "foo bar"
ok := CmpDeeply(t, got, Re(expected), "checks value %s", got)
fmt.Println(ok)

got = "bar foo"
ok = CmpDeeply(t, got, Re(expected), "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`^(\w+) (\w+) (\w+)$`)

got := "foo bar biz"
ok := CmpDeeply(t, got, Re(expected, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

got = "foo bar! biz"
ok = CmpDeeply(t, got, Re(expected, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

got := errors.New("foo bar")
ok := CmpDeeply(t, got, Re(expected), "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

expected := regexp.MustCompile("(zip|bar)$")

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := CmpDeeply(t, got, Re(expected), "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foo bar")
ok := CmpDeeply(t, got, Re("(zip|bar)$"), "checks value %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foo bar")
ok := CmpDeeply(t, got, Re("(zip|bar)$"), "checks value %s", got)
fmt.Println(ok)

Output:

true

func ReAll Uses

func ReAll(reg interface{}, capture interface{}) TestDeep

ReAll operator allows to successively apply a regexp on a string (or convertible), []byte, error or fmt.Stringer interface (error interface is tested before fmt.Stringer) and to match its groups contents.

"reg" is the regexp. It can be a string that is automatically compiled using regexp.MustCompile, or a *regexp.Regexp.

"capture" is used to match the contents of regexp groups. Groups are presented as a []string or [][]byte depending the original matched data. Note that an other operator can be used here.

CmpDeeply(t, "John Doe",
  ReAll(`(\w+)(?: |\z)`, []string{"John", "Doe"})) // succeeds
CmpDeeply(t, "John Doe",
  ReAll(`(\w+)(?: |\z)`, Bag("Doe", "John"))       // succeeds

Code:

t := &testing.T{}

got := "foo bar biz"
ok := CmpDeeply(t, got, ReAll(`(\w+)`, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = CmpDeeply(t, got, ReAll(`(\w+)`, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

got := "11 45 23 56 85 96"
ok := CmpDeeply(t, got,
    ReAll(`(\d+)`, ArrayEach(Code(func(num string) bool {
        n, err := strconv.Atoi(num)
        return err == nil && n > 10 && n < 100
    }))),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = CmpDeeply(t, got,
    ReAll(`(\d+)`, ArrayEach(Code(func(num string) bool {
        n, err := strconv.Atoi(num)
        return err == nil && n > 20 && n < 100
    }))),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`(\w+)`)

got := "foo bar biz"
ok := CmpDeeply(t, got, ReAll(expected, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but all catured groups do not match Set
got = "foo BAR biz"
ok = CmpDeeply(t, got, ReAll(expected, Set("biz", "foo", "bar")),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

expected := regexp.MustCompile(`(\d+)`)

got := "11 45 23 56 85 96"
ok := CmpDeeply(t, got,
    ReAll(expected, ArrayEach(Code(func(num string) bool {
        n, err := strconv.Atoi(num)
        return err == nil && n > 10 && n < 100
    }))),
    "checks value %s", got)
fmt.Println(ok)

// Matches, but 11 is not greater than 20
ok = CmpDeeply(t, got,
    ReAll(expected, ArrayEach(Code(func(num string) bool {
        n, err := strconv.Atoi(num)
        return err == nil && n > 20 && n < 100
    }))),
    "checks value %s", got)
fmt.Println(ok)

Output:

true
false

func Set Uses

func Set(expectedItems ...interface{}) TestDeep

Set operator compares the contents of an array or a slice (or a pointer on array/slice) ignoring duplicates and without taking care of the order of items.

During a match, each expected item should match in the compared array/slice, and each array/slice item should be matched by an expected item to succeed.

CmpDeeply(t, []int{1, 1, 2}, Set(1, 2))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, Set(2, 1))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, Set(1, 2, 3)) // fails, 3 is missing

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are present, ignoring duplicates
ok := CmpDeeply(t, got, Set(1, 2, 3, 5, 8),
    "checks all items are present, in any order")
fmt.Println(ok)

// Duplicates are ignored in a Set
ok = CmpDeeply(t, got, Set(1, 2, 2, 2, 2, 2, 3, 5, 8),
    "checks all items are present, in any order")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several Set entries
ok = CmpDeeply(t, got, Set(Between(1, 4), 3, Between(2, 10)),
    "checks all items are present, in any order")
fmt.Println(ok)

Output:

true
true
true

func Shallow Uses

func Shallow(expectedPtr interface{}) TestDeep

Shallow operator compares pointers only, not their contents. It applies on channels, functions (with some restrictions), maps, pointers, slices and strings.

During a match, the compared data must be the same as "expectedPointer" to succeed.

a, b := 123, 123
CmpDeeply(t, &a, Shallow(&a)) // succeeds
CmpDeeply(t, &a, Shallow(&b)) // fails even if a == b as &a != &b

back := "foobarfoobar"
a, b := back[:6], back[6:]
// a == b but...
CmpDeeply(t, &a, Shallow(&b)) // fails

Be careful for slices and strings! Shallow can succeed but the slices/strings not be identical because of their different lengths. For example:

a := "foobar yes!"
b := a[:1]                    // aka. "f"
CmpDeeply(t, &a, Shallow(&b)) // succeeds as both strings point to the same area, even if len() differ

The same behavior occurs for slices:

a := []int{1, 2, 3, 4, 5, 6}
b := a[:2]                    // aka. []int{1, 2}
CmpDeeply(t, &a, Shallow(&b)) // succeeds as both slices point to the same area, even if len() differ

Code:

t := &testing.T{}

type MyStruct struct {
    Value int
}
data := MyStruct{Value: 12}
got := &data

ok := CmpDeeply(t, got, Shallow(&data),
    "checks pointers only, not contents")
fmt.Println(ok)

// Same contents, but not same pointer
ok = CmpDeeply(t, got, Shallow(&MyStruct{Value: 12}),
    "checks pointers only, not contents")
fmt.Println(ok)

Output:

true
false

Code:

t := &testing.T{}

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

ok := CmpDeeply(t, a, Shallow(back))
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpDeeply(t, b, Shallow(back))
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

Code:

t := &testing.T{}

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := CmpDeeply(t, a, Shallow(back))
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpDeeply(t, b, Shallow(a))
fmt.Println("are = but do not point to same area:", ok)

Output:

are ≠ but share the same area: true
are = but do not point to same area: false

func Slice Uses

func Slice(model interface{}, expectedEntries ArrayEntries) TestDeep

Slice operator compares the contents of a slice or a pointer on a slice against the non-zero values of "model" (if any) and the values of "expectedEntries".

"model" must be the same type as compared data.

"expectedEntries" can be nil, if no zero entries are expected and no TestDeep operator are involved.

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

got := []int{42, 58, 26}

ok := CmpDeeply(t, got, Slice([]int{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks slice %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, got,
    Slice([]int{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks slice %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, got,
    Slice(([]int)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks slice %v", got)
fmt.Println(ok)

Output:

true
true
true

Code:

t := &testing.T{}

type MySlice []int

got := MySlice{42, 58, 26}

ok := CmpDeeply(t, got, Slice(MySlice{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks typed slice %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got, Slice(&MySlice{42}, ArrayEntries{1: 58, 2: Ignore()}),
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Slice(&MySlice{}, ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    Slice((*MySlice)(nil), ArrayEntries{0: 42, 1: 58, 2: Ignore()}),
    "checks pointer on typed slice %v", got)
fmt.Println(ok)

Output:

true
true
true
true

func Smuggle Uses

func Smuggle(fn interface{}, expectedValue interface{}) TestDeep

Smuggle operator allows to change data contents or mutate it into another type before stepping down in favor of generic comparison process. So "fn" is a function that must take one parameter whose type must be convertible to the type of the compared value (as a convenient shortcut, "fn" can be a string specifying a fields-path through structs, see below for details).

"fn" must return at least one value, these value will be compared as is to "expectedValue", here integer 28:

Smuggle(func (value string) int {
    num, _ := strconv.Atoi(value)
    return num
  },
  28)

or using an other TestDeep operator, here Between(28, 30):

Smuggle(func (value string) int {
    num, _ := strconv.Atoi(value)
    return num
  },
  Between(28, 30))

"fn" can return a second boolean value, used to tell that a problem occurred and so stop the comparison:

Smuggle(func (value string) (int, bool) {
    num, err := strconv.Atoi(value)
    return num, err == nil
  },
  Between(28, 30))

"fn" can return a third string value which is used to describe the test when a problem occurred (false second boolean value):

Smuggle(func (value string) (int, bool, string) {
    num, err := strconv.Atoi(value)
    if err != nil {
      return 0, false, "string must contain a number"
    }
    return num, true, ""
  },
  Between(28, 30))

Instead of returning (X, bool) or (X, bool, string), "fn" can return (X, error). When a problem occurs, the returned error is non-nil, as in:

Smuggle(func (value string) (int, error) {
    num, err := strconv.Atoi(value)
    return num, err
  },
  Between(28, 30))

Which can be simplified to:

Smuggle(strconv.Atoi, Between(28, 30))

Imagine you want to compare that the Year of a date is between 2010 and 2020:

Smuggle(func (date time.Time) int {
    return date.Year()
  },
  Between(2010, 2020))

In this case the data location forwarded to next test will be something like DATA.MyTimeField<smuggled>, but you can act on it too by returning a SmuggledGot struct (by value or by address):

Smuggle(func (date time.Time) SmuggledGot {
    return SmuggledGot{
      Name: "Year",
      Got:  date.Year(),
    }
  },
  Between(2010, 2020))

then the data location forwarded to next test will be something like DATA.MyTimeField.Year. The "." between the current path (here "DATA.MyTimeField") and the returned Name "Year" is automatically added when Name starts with a Letter.

Note that SmuggledGot and *SmuggledGot returns are treated equally, and they are only used when "fn" has only one returned value or when the second boolean returned value is true.

Of course, all cases can go together:

// Accepts a "YYYY/mm/DD HH:MM:SS" string to produce a time.Time and tests
// whether this date is contained between 2 hours before now and now.
Smuggle(func (date string) (*SmuggledGot, bool, string) {
    date, err := time.Parse("2006/01/02 15:04:05", date)
    if err != nil {
      return nil, false, `date must conform to "YYYY/mm/DD HH:MM:SS" format`
    }
    return &SmuggledGot{
      Name: "Date",
      Got:  date,
    }, true, ""
  },
  Between(time.Now().Add(-2*time.Hour), time.Now()))

or:

// Accepts a "YYYY/mm/DD HH:MM:SS" string to produce a time.Time and tests
// whether this date is contained between 2 hours before now and now.
Smuggle(func (date string) (*SmuggledGot, error) {
    date, err := time.Parse("2006/01/02 15:04:05", date)
    if err != nil {
      return nil, err
    }
    return &SmuggledGot{
      Name: "Date",
      Got:  date,
    }, nil
  },
  Between(time.Now().Add(-2*time.Hour), time.Now()))

Smuggle can also be used to access a struct field embedded in several struct layers.

type A struct { Num int }
type B struct { A *A }
type C struct { B B }
got := C{B: B{A: &A{Num: 12}}}

// Tests that got.B.A.Num is 12
CmpDeeply(t, got,
  Smuggle(func (c C) int {
      return c.B.A.Num
    },
    12))

As brought up above, a field-path can be passed as "fn" value instead of a function pointer. Using this feature, the CmpDeeply call in the above example can be rewritten as follows:

// Tests that got.B.A.Num is 12
CmpDeeply(t, got, Smuggle("B.A.Num", 12))

Behind the scenes, a temporary function is automatically created to achieve the same goal, but add some checks against nil values and auto-dereference interfaces and pointers.

The difference between Smuggle and Code operators is that Code is used to do a final comparison while Smuggle transforms the data and then steps down in favor of generic comparison process. Moreover, the type accepted as input for the function is more lax to facilitate the tests writing (eg. the function can accept a float64 and the got value be an int). See examples. On the other hand, the output type is strict and must match exactly the expected value type. The fields-path string "fn" shortcut is not available with Code operator.

TypeBehind method returns the reflect.Type of only parameter of "fn". For the case where "fn" is a fields-path, it is always Interface{}, as the type can not be known in advance.

Code:

t := &testing.T{}

// No end date but a start date and a duration
type StartDuration struct {
    StartDate time.Time
    Duration  time.Duration
}

// Checks that end date is between 17th and 19th February both at 0h
// for each of these durations in hours

for _, duration := range []time.Duration{48, 72, 96} {
    got := StartDuration{
        StartDate: time.Date(2018, time.February, 14, 12, 13, 14, 0, time.UTC),
        Duration:  duration * time.Hour,
    }

    // Simplest way, but in case of Between() failure, error will be bound
    // to DATA<smuggled>, not very clear...
    ok := CmpDeeply(t, got,
        Smuggle(
            func(sd StartDuration) time.Time {
                return sd.StartDate.Add(sd.Duration)
            },
            Between(
                time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
                time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC))))
    fmt.Println(ok)

    // Name the computed value "ComputedEndDate" to render a Between() failure
    // more understandable, so error will be bound to DATA.ComputedEndDate
    ok = CmpDeeply(t, got,
        Smuggle(
            func(sd StartDuration) SmuggledGot {
                return SmuggledGot{
                    Name: "ComputedEndDate",
                    Got:  sd.StartDate.Add(sd.Duration),
                }
            },
            Between(
                time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),
                time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC))))
    fmt.Println(ok)
}

Output:

false
false
true
true
true
true

Code:

t := &testing.T{}

got := int64(123)

ok := CmpDeeply(t, got,
    Smuggle(func(n int64) int { return int(n) }, 123),
    "checks int64 got against an int value")
fmt.Println(ok)

ok = CmpDeeply(t, "123",
    Smuggle(
        func(numStr string) (int, bool) {
            n, err := strconv.Atoi(numStr)
            return n, err == nil
        },
        Between(120, 130)),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = CmpDeeply(t, "123",
    Smuggle(
        func(numStr string) (int, bool, string) {
            n, err := strconv.Atoi(numStr)
            if err != nil {
                return 0, false, "string must contain a number"
            }
            return n, true, ""
        },
        Between(120, 130)),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

ok = CmpDeeply(t, "123",
    Smuggle(
        func(numStr string) (int, error) {
            return strconv.Atoi(numStr)
        },
        Between(120, 130)),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

// Short version :)
ok = CmpDeeply(t, "123",
    Smuggle(strconv.Atoi, Between(120, 130)),
    "checks that number in %#v is in [120 .. 130]")
fmt.Println(ok)

Output:

true
true
true
true
true

Code:

t := &testing.T{}

gotTime, err := time.Parse(time.RFC3339, "2018-05-23T12:13:14Z")
if err != nil {
    t.Fatal(err)
}

// Do not check the struct itself, but its stringified form
ok := CmpDeeply(t, gotTime,
    Smuggle(func(s fmt.Stringer) string {
        return s.String()
    },
        "2018-05-23 12:13:14 +0000 UTC"))
fmt.Println("stringified time.Time OK:", ok)

// If got does not implement the fmt.Stringer interface, it fails
// without calling the Smuggle func
type MyTime time.Time
ok = CmpDeeply(t, MyTime(gotTime),
    Smuggle(func(s fmt.Stringer) string {
        fmt.Println("Smuggle func called!")
        return s.String()
    },
        "2018-05-23 12:13:14 +0000 UTC"))
fmt.Println("stringified MyTime OK:", ok)

// Output
// stringified time.Time OK: true
// stringified MyTime OK: false

Code:

t := &testing.T{}

// got is an int16 and Smuggle func input is an int64: it is OK
got := int(123)

ok := CmpDeeply(t, got,
    Smuggle(func(n int64) uint32 { return uint32(n) }, uint32(123)))
fmt.Println("got int16(123) → smuggle via int64 → uint32(123):", ok)

Output:

got int16(123) → smuggle via int64 → uint32(123): true

func String Uses

func String(expected string) TestDeep

String operator allows to compare a string (or convertible), error or fmt.Stringer interface (error interface is tested before fmt.Stringer.)

err := errors.New("error!")
CmpDeeply(t, err, String("error!")) // succeeds

bstr := bytes.NewBufferString("fmt.Stringer!")
CmpDeeply(t, bstr, String("fmt.Stringer!")) // succeeds

Code:

t := &testing.T{}

got := "foobar"

ok := CmpDeeply(t, got, String("foobar"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

got := errors.New("foobar")

ok := CmpDeeply(t, got, String("foobar"), "checks %s", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

// bytes.Buffer implements fmt.Stringer
got := bytes.NewBufferString("foobar")

ok := CmpDeeply(t, got, String("foobar"), "checks %s", got)
fmt.Println(ok)

Output:

true

func Struct Uses

func Struct(model interface{}, expectedFields StructFields) TestDeep

Struct operator compares the contents of a struct or a pointer on a struct against the non-zero values of "model" (if any) and the values of "expectedFields".

"model" must be the same type as compared data.

"expectedFields" can be nil, if no zero entries are expected and no TestDeep operator are involved.

During a match, all expected fields must be found to succeed. Non-expected fields are ignored.

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

type Person struct {
    Name        string
    Age         int
    NumChildren int
}

got := Person{
    Name:        "Foobar",
    Age:         42,
    NumChildren: 3,
}

// As NumChildren is zero in Struct() call, it is not checked
ok := CmpDeeply(t, got,
    Struct(Person{Name: "Foobar"}, StructFields{
        "Age": Between(40, 50),
    }),
    "checks %v is the right Person")
fmt.Println(ok)

// Model can be empty
ok = CmpDeeply(t, got,
    Struct(Person{}, StructFields{
        "Name":        "Foobar",
        "Age":         Between(40, 50),
        "NumChildren": Not(0),
    }),
    "checks %v is the right Person")
fmt.Println(ok)

// Works with pointers too
ok = CmpDeeply(t, &got,
    Struct(&Person{}, StructFields{
        "Name":        "Foobar",
        "Age":         Between(40, 50),
        "NumChildren": Not(0),
    }),
    "checks %v is the right Person")
fmt.Println(ok)

// Model does not need to be instanciated
ok = CmpDeeply(t, &got,
    Struct((*Person)(nil), StructFields{
        "Name":        "Foobar",
        "Age":         Between(40, 50),
        "NumChildren": Not(0),
    }),
    "checks %v is the right Person")
fmt.Println(ok)

Output:

true
true
true
true

func SubBagOf Uses

func SubBagOf(expectedItems ...interface{}) TestDeep

SubBagOf operator compares the contents of an array or a slice (or a pointer on array/slice) without taking care of the order of items.

During a match, each array/slice item should be matched by an expected item to succeed. But some expected items can be missing from the compared array/slice.

CmpDeeply(t, []int{1}, SubBagOf(1, 1, 2))       // succeeds
CmpDeeply(t, []int{1, 1, 1}, SubBagOf(1, 1, 2)) // fails, one 1 is an extra item

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpDeeply(t, got, SubBagOf(0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 8, 9, 9),
    "checks at least all items are present, in any order")
fmt.Println(ok)

// got contains one 8 too many
ok = CmpDeeply(t, got, SubBagOf(0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 9, 9),
    "checks at least all items are present, in any order")
fmt.Println(ok)

got = []int{1, 3, 5, 2}

ok = CmpDeeply(t, got, SubBagOf(
    Between(0, 3),
    Between(0, 3),
    Between(0, 3),
    Between(0, 3),
    Gt(4),
    Gt(4)),
    "checks at least all items match, in any order with TestDeep operators")
fmt.Println(ok)

Output:

true
false
true

func SubMapOf Uses

func SubMapOf(model interface{}, expectedEntries MapEntries) TestDeep

SubMapOf operator compares the contents of a map against the non-zero values of "model" (if any) and the values of "expectedEntries".

"model" must be the same type as compared data.

"expectedEntries" can be nil, if no zero entries are expected and no TestDeep operator are involved.

During a match, each map entry should be matched by an expected entry to succeed. But some expected entries can be missing from the compared map.

CmpDeeply(t, map[string]int{"a": 1},
  SubMapOf(map[string]int{"a": 1, "b": 2}, nil) // succeeds

CmpDeeply(t, map[string]int{"a": 1, "c": 3},
  SubMapOf(map[string]int{"a": 1, "b": 2}, nil) // fails, extra {"c": 3}

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42}

ok := CmpDeeply(t, got,
    SubMapOf(map[string]int{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666}),
    "checks map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42}

ok := CmpDeeply(t, got,
    SubMapOf(MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666}),
    "checks typed map %v is included in expected keys/values", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    SubMapOf(&MyMap{"bar": 42}, MapEntries{"foo": Lt(15), "zip": 666}),
    "checks pointed typed map %v is included in expected keys/values", got)
fmt.Println(ok)

Output:

true
true

func SubSetOf Uses

func SubSetOf(expectedItems ...interface{}) TestDeep

SubSetOf operator compares the contents of an array or a slice (or a pointer on array/slice) ignoring duplicates and without taking care of the order of items.

During a match, each array/slice item should be matched by an expected item to succeed. But some expected items can be missing from the compared array/slice.

CmpDeeply(t, []int{1, 1}, SubSetOf(1, 2))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, SubSetOf(1, 3)) // fails, 2 is an extra item

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

// Matches as all items are expected, ignoring duplicates
ok := CmpDeeply(t, got, SubSetOf(1, 2, 3, 4, 5, 6, 7, 8),
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

// Tries its best to not raise an error when a value can be matched
// by several SubSetOf entries
ok = CmpDeeply(t, got, SubSetOf(Between(1, 4), 3, Between(2, 10), Gt(100)),
    "checks at least all items are present, in any order, ignoring duplicates")
fmt.Println(ok)

Output:

true
true

func SuperBagOf Uses

func SuperBagOf(expectedItems ...interface{}) TestDeep

SuperBagOf operator compares the contents of an array or a slice (or a pointer on array/slice) without taking care of the order of items.

During a match, each expected item should match in the compared array/slice. But some items in the compared array/slice may not be expected.

CmpDeeply(t, []int{1, 1, 2}, SuperBagOf(1))       // succeeds
CmpDeeply(t, []int{1, 1, 2}, SuperBagOf(1, 1, 1)) // fails, one 1 is missing

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpDeeply(t, got, SuperBagOf(8, 5, 8),
    "checks the items are present, in any order")
fmt.Println(ok)

ok = CmpDeeply(t, got, SuperBagOf(Gt(5), Lte(2)),
    "checks at least 2 items of %v match", got)
fmt.Println(ok)

Output:

true
true

func SuperMapOf Uses

func SuperMapOf(model interface{}, expectedEntries MapEntries) TestDeep

SuperMapOf operator compares the contents of a map against the non-zero values of "model" (if any) and the values of "expectedEntries".

"model" must be the same type as compared data.

"expectedEntries" can be nil, if no zero entries are expected and no TestDeep operator are involved.

During a match, each expected entry should match in the compared map. But some entries in the compared map may not be expected.

CmpDeeply(t, map[string]int{"a": 1, "b": 2},
  SuperMapOf(map[string]int{"a": 1}, nil) // succeeds

CmpDeeply(t, map[string]int{"a": 1, "c": 3},
  SuperMapOf(map[string]int{"a": 1, "b": 2}, nil) // fails, missing {"b": 2}

TypeBehind method returns the reflect.Type of "model".

Code:

t := &testing.T{}

got := map[string]int{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got,
    SuperMapOf(map[string]int{"bar": 42}, MapEntries{"foo": Lt(15)}),
    "checks map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

Output:

true

Code:

t := &testing.T{}

type MyMap map[string]int

got := MyMap{"foo": 12, "bar": 42, "zip": 89}

ok := CmpDeeply(t, got,
    SuperMapOf(MyMap{"bar": 42}, MapEntries{"foo": Lt(15)}),
    "checks typed map %v contains at leat all expected keys/values", got)
fmt.Println(ok)

ok = CmpDeeply(t, &got,
    SuperMapOf(&MyMap{"bar": 42}, MapEntries{"foo": Lt(15)}),
    "checks pointed typed map %v contains at leat all expected keys/values",
    got)
fmt.Println(ok)

Output:

true
true

func SuperSetOf Uses

func SuperSetOf(expectedItems ...interface{}) TestDeep

SuperSetOf operator compares the contents of an array or a slice (or a pointer on array/slice) ignoring duplicates and without taking care of the order of items.

During a match, each expected item should match in the compared array/slice. But some items in the compared array/slice may not be expected.

CmpDeeply(t, []int{1, 1, 2}, SuperSetOf(1))    // succeeds
CmpDeeply(t, []int{1, 1, 2}, SuperSetOf(1, 3)) // fails, 3 is missing

Code:

t := &testing.T{}

got := []int{1, 3, 5, 8, 8, 1, 2}

ok := CmpDeeply(t, got, SuperSetOf(1, 2, 3),
    "checks the items are present, in any order and ignoring duplicates")
fmt.Println(ok)

ok = CmpDeeply(t, got, SuperSetOf(Gt(5), Lte(2)),
    "checks at least 2 items of %v match ignoring duplicates", got)
fmt.Println(ok)

Output:

true
true

func TruncTime Uses

func TruncTime(expectedTime interface{}, trunc ...time.Duration) TestDeep

TruncTime operator compares time.Time (or assignable) values after truncating them to the optional "trunc" duration. See time.Truncate for details about the truncation.

If "trunc" is missing, it defaults to 0.

During comparison, location does not matter as time.Equal method is used behind the scenes: a time instant in two different locations is the same time instant.

Whatever the "trunc" value is, the monotonic clock is stripped before the comparison against "expectedTime".

TypeBehind method returns the reflect.Type of "expectedTime".

Code:

t := &testing.T{}

dateToTime := func(str string) time.Time {
    t, err := time.Parse(time.RFC3339Nano, str)
    if err != nil {
        panic(err)
    }
    return t
}

got := dateToTime("2018-05-01T12:45:53.123456789Z")

// Compare dates ignoring nanoseconds and monotonic parts
expected := dateToTime("2018-05-01T12:45:53Z")
ok := CmpDeeply(t, got, TruncTime(expected, time.Second),
    "checks date %v, truncated to the second", got)
fmt.Println(ok)

// Compare dates ignoring time and so monotonic parts
expected = dateToTime("2018-05-01T11:22:33.444444444Z")
ok = CmpDeeply(t, got, TruncTime(expected, 24*time.Hour),
    "checks date %v, truncated to the day", got)
fmt.Println(ok)

// Compare dates exactly but ignoring monotonic part
expected = dateToTime("2018-05-01T12:45:53.123456789Z")
ok = CmpDeeply(t, got, TruncTime(expected),
    "checks date %v ignoring monotonic part", got)
fmt.Println(ok)

Output:

true
true
true

func Zero Uses

func Zero() TestDeep

Zero operator checks that data is zero regarding its type.

nil is the zero value of pointers, maps, slices, channels and functions;
0 is the zero value of numbers;
false is the zero value of booleans;
zero value of structs is the struct with no fields initialized.

Beware that:

CmpDeeply(t, AnyStruct{}, Zero())       // is true
CmpDeeply(t, &AnyStruct{}, Zero())      // is false, coz pointer ≠ nil
CmpDeeply(t, &AnyStruct{}, Ptr(Zero())) // is true

Code:

t := &testing.T{}

ok := CmpDeeply(t, 0, Zero())
fmt.Println(ok)

ok = CmpDeeply(t, float64(0), Zero())
fmt.Println(ok)

ok = CmpDeeply(t, 12, Zero()) // fails, as 12 is not 0 :)
fmt.Println(ok)

ok = CmpDeeply(t, (map[string]int)(nil), Zero())
fmt.Println(ok)

ok = CmpDeeply(t, map[string]int{}, Zero()) // fails, as not nil
fmt.Println(ok)

ok = CmpDeeply(t, ([]int)(nil), Zero())
fmt.Println(ok)

ok = CmpDeeply(t, []int{}, Zero()) // fails, as not nil
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{}, Zero())
fmt.Println(ok)

ok = CmpDeeply(t, [3]int{0, 1}, Zero()) // fails, DATA[1] is not 0
fmt.Println(ok)

ok = CmpDeeply(t, bytes.Buffer{}, Zero())
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, Zero()) // fails, as pointer not nil
fmt.Println(ok)

ok = CmpDeeply(t, &bytes.Buffer{}, Ptr(Zero())) // OK with the help of Ptr()
fmt.Println(ok)

Output:

true
true
false
true
false
true
false
true
false
true
false
true

type TestingFT Uses

type TestingFT interface {
    TestingT
    Errorf(format string, args ...interface{})
    Fail()
    FailNow()
    Failed() bool
    Fatalf(format string, args ...interface{})
    Log(args ...interface{})
    Logf(format string, args ...interface{})
    Name() string
    Skip(args ...interface{})
    SkipNow()
    Skipf(format string, args ...interface{})
    Skipped() bool
    Run(name string, f func(t *testing.T)) bool
}

TestingFT (aka. TestingF<ull>T) is the interface used by T to delegate common *testing.T functions to it. Of course, *testing.T implements it.

type TestingT Uses

type TestingT interface {
    Error(args ...interface{})
    Fatal(args ...interface{})
    Helper()
}

TestingT is the minimal interface used by CmpDeeply to report errors. It is commonly implemented by *testing.T and testing.TB.

Directories

PathSynopsis
helpers/tdhttpPackage tdhttp provides some functions to easily test HTTP handlers.
helpers/tdutil
internal/ctxerr
internal/dark
internal/location
internal/test
internal/types
internal/util
internal/visited

Package testdeep imports 22 packages (graph) and is imported by 1 packages. Updated 2019-03-08. Refresh now. Tools for package owners.