Documentation
¶
Overview ¶
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") } }
Example ¶
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 ¶
- Variables
- func CmpAll(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func CmpAny(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func CmpArray(t TestingT, got interface{}, model interface{}, expectedEntries ArrayEntries, ...) bool
- func CmpArrayEach(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool
- func CmpBag(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpBetween(t TestingT, got interface{}, from interface{}, to interface{}, ...) bool
- func CmpCap(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpCode(t TestingT, got interface{}, fn interface{}, args ...interface{}) bool
- func CmpContains(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool
- func CmpContainsKey(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool
- func CmpDeeply(t TestingT, got, expected interface{}, args ...interface{}) bool
- func CmpEmpty(t TestingT, got interface{}, args ...interface{}) bool
- func CmpError(t TestingT, got error, args ...interface{}) bool
- func CmpFalse(t TestingT, got interface{}, args ...interface{}) bool
- func CmpGt(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpGte(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpHasPrefix(t TestingT, got interface{}, expected string, args ...interface{}) bool
- func CmpHasSuffix(t TestingT, got interface{}, expected string, args ...interface{}) bool
- func CmpIsa(t TestingT, got interface{}, model interface{}, args ...interface{}) bool
- func CmpLen(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpLt(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpLte(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpMap(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func CmpMapEach(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool
- func CmpN(t TestingT, got interface{}, num interface{}, tolerance interface{}, ...) bool
- func CmpNaN(t TestingT, got interface{}, args ...interface{}) bool
- func CmpNil(t TestingT, got interface{}, args ...interface{}) bool
- func CmpNoError(t TestingT, got error, args ...interface{}) bool
- func CmpNone(t TestingT, got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func CmpNot(t TestingT, got interface{}, expected interface{}, args ...interface{}) bool
- func CmpNotAny(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpNotEmpty(t TestingT, got interface{}, args ...interface{}) bool
- func CmpNotNaN(t TestingT, got interface{}, args ...interface{}) bool
- func CmpNotNil(t TestingT, got interface{}, args ...interface{}) bool
- func CmpNotPanic(t TestingT, fn func(), args ...interface{}) bool
- func CmpNotZero(t TestingT, got interface{}, args ...interface{}) bool
- func CmpPPtr(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpPanic(t TestingT, fn func(), expectedPanic interface{}, args ...interface{}) bool
- func CmpPtr(t TestingT, got interface{}, val interface{}, args ...interface{}) bool
- func CmpRe(t TestingT, got interface{}, reg interface{}, capture interface{}, ...) bool
- func CmpReAll(t TestingT, got interface{}, reg interface{}, capture interface{}, ...) bool
- func CmpSet(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpShallow(t TestingT, got interface{}, expectedPtr interface{}, args ...interface{}) bool
- func CmpSlice(t TestingT, got interface{}, model interface{}, expectedEntries ArrayEntries, ...) bool
- func CmpSmuggle(t TestingT, got interface{}, fn interface{}, expectedValue interface{}, ...) bool
- func CmpString(t TestingT, got interface{}, expected string, args ...interface{}) bool
- func CmpStruct(t TestingT, got interface{}, model interface{}, expectedFields StructFields, ...) bool
- func CmpSubBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpSubMapOf(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func CmpSubSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpSuperBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpSuperMapOf(t TestingT, got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func CmpSuperSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func CmpTrue(t TestingT, got interface{}, args ...interface{}) bool
- func CmpTruncTime(t TestingT, got interface{}, expectedTime interface{}, trunc time.Duration, ...) bool
- func CmpZero(t TestingT, got interface{}, args ...interface{}) bool
- func EqDeeply(got, expected interface{}) bool
- func EqDeeplyError(got, expected interface{}) error
- type ArrayEntries
- type Base
- type BaseOKNil
- type BoundsKind
- type ContextConfig
- type MapEntries
- type SmuggledGot
- type StructFields
- type T
- func (t *T) All(got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func (t *T) Any(got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func (t *T) Array(got interface{}, model interface{}, expectedEntries ArrayEntries, ...) bool
- func (t *T) ArrayEach(got interface{}, expectedValue interface{}, args ...interface{}) bool
- func (t *T) Bag(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) Between(got interface{}, from interface{}, to interface{}, bounds BoundsKind, ...) bool
- func (t *T) Cap(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) CmpDeeply(got, expected interface{}, args ...interface{}) bool
- func (t *T) CmpError(got error, args ...interface{}) bool
- func (t *T) CmpNoError(got error, args ...interface{}) bool
- func (t *T) CmpNotPanic(fn func(), args ...interface{}) bool
- func (t *T) CmpPanic(fn func(), expected interface{}, args ...interface{}) bool
- func (t *T) Code(got interface{}, fn interface{}, args ...interface{}) bool
- func (t *T) Contains(got interface{}, expectedValue interface{}, args ...interface{}) bool
- func (t *T) ContainsKey(got interface{}, expectedValue interface{}, args ...interface{}) bool
- func (t *T) Empty(got interface{}, args ...interface{}) bool
- func (t *T) FailureIsFatal(enable ...bool) *T
- func (t *T) False(got interface{}, args ...interface{}) bool
- func (t *T) Gt(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Gte(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) HasPrefix(got interface{}, expected string, args ...interface{}) bool
- func (t *T) HasSuffix(got interface{}, expected string, args ...interface{}) bool
- func (t *T) Isa(got interface{}, model interface{}, args ...interface{}) bool
- func (t *T) Len(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Lt(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Lte(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Map(got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func (t *T) MapEach(got interface{}, expectedValue interface{}, args ...interface{}) bool
- func (t *T) N(got interface{}, num interface{}, tolerance interface{}, args ...interface{}) bool
- func (t *T) NaN(got interface{}, args ...interface{}) bool
- func (t *T) Nil(got interface{}, args ...interface{}) bool
- func (t *T) None(got interface{}, expectedValues []interface{}, args ...interface{}) bool
- func (t *T) Not(got interface{}, expected interface{}, args ...interface{}) bool
- func (t *T) NotAny(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) NotEmpty(got interface{}, args ...interface{}) bool
- func (t *T) NotNaN(got interface{}, args ...interface{}) bool
- func (t *T) NotNil(got interface{}, args ...interface{}) bool
- func (t *T) NotZero(got interface{}, args ...interface{}) bool
- func (t *T) PPtr(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Ptr(got interface{}, val interface{}, args ...interface{}) bool
- func (t *T) Re(got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool
- func (t *T) ReAll(got interface{}, reg interface{}, capture interface{}, args ...interface{}) bool
- func (t *T) RootName(rootName string) *T
- func (t *T) Run(name string, f func(t *T)) bool
- func (t *T) Set(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) Shallow(got interface{}, expectedPtr interface{}, args ...interface{}) bool
- func (t *T) Slice(got interface{}, model interface{}, expectedEntries ArrayEntries, ...) bool
- func (t *T) Smuggle(got interface{}, fn interface{}, expectedValue interface{}, ...) bool
- func (t *T) String(got interface{}, expected string, args ...interface{}) bool
- func (t *T) Struct(got interface{}, model interface{}, expectedFields StructFields, ...) bool
- func (t *T) SubBagOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) SubMapOf(got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func (t *T) SubSetOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) SuperBagOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) SuperMapOf(got interface{}, model interface{}, expectedEntries MapEntries, ...) bool
- func (t *T) SuperSetOf(got interface{}, expectedItems []interface{}, args ...interface{}) bool
- func (t *T) True(got interface{}, args ...interface{}) bool
- func (t *T) TruncTime(got interface{}, expectedTime interface{}, trunc time.Duration, ...) bool
- func (t *T) Zero(got interface{}, args ...interface{}) bool
- type TestDeep
- func All(expectedValues ...interface{}) TestDeep
- func Any(expectedValues ...interface{}) TestDeep
- func Array(model interface{}, expectedEntries ArrayEntries) TestDeep
- func ArrayEach(expectedValue interface{}) TestDeep
- func Bag(expectedItems ...interface{}) TestDeep
- func Between(from interface{}, to interface{}, bounds ...BoundsKind) TestDeep
- func Cap(val interface{}) TestDeep
- func Code(fn interface{}) TestDeep
- func Contains(expectedValue interface{}) TestDeep
- func ContainsKey(expectedValue interface{}) TestDeep
- func Empty() TestDeep
- func Gt(val interface{}) TestDeep
- func Gte(val interface{}) TestDeep
- func HasPrefix(expected string) TestDeep
- func HasSuffix(expected string) TestDeep
- func Ignore() TestDeep
- func Isa(model interface{}) TestDeep
- func Len(val interface{}) TestDeep
- func Lt(val interface{}) TestDeep
- func Lte(val interface{}) TestDeep
- func Map(model interface{}, expectedEntries MapEntries) TestDeep
- func MapEach(expectedValue interface{}) TestDeep
- func N(num interface{}, tolerance ...interface{}) TestDeep
- func NaN() TestDeep
- func Nil() TestDeep
- func None(expectedValues ...interface{}) TestDeep
- func Not(expected interface{}) TestDeep
- func NotAny(expectedItems ...interface{}) TestDeep
- func NotEmpty() TestDeep
- func NotNaN() TestDeep
- func NotNil() TestDeep
- func NotZero() TestDeep
- func PPtr(val interface{}) TestDeep
- func Ptr(val interface{}) TestDeep
- func Re(reg interface{}, capture ...interface{}) TestDeep
- func ReAll(reg interface{}, capture interface{}) TestDeep
- func Set(expectedItems ...interface{}) TestDeep
- func Shallow(expectedPtr interface{}) TestDeep
- func Slice(model interface{}, expectedEntries ArrayEntries) TestDeep
- func Smuggle(fn interface{}, expectedValue interface{}) TestDeep
- func String(expected string) TestDeep
- func Struct(model interface{}, expectedFields StructFields) TestDeep
- func SubBagOf(expectedItems ...interface{}) TestDeep
- func SubMapOf(model interface{}, expectedEntries MapEntries) TestDeep
- func SubSetOf(expectedItems ...interface{}) TestDeep
- func SuperBagOf(expectedItems ...interface{}) TestDeep
- func SuperMapOf(model interface{}, expectedEntries MapEntries) TestDeep
- func SuperSetOf(expectedItems ...interface{}) TestDeep
- func TruncTime(expectedTime interface{}, trunc ...time.Duration) TestDeep
- func Zero() TestDeep
- type TestingFT
- type TestingT
Examples ¶
- Package
- All
- Any
- Array (Array)
- Array (TypedArray)
- ArrayEach (Array)
- ArrayEach (Slice)
- ArrayEach (TypedArray)
- ArrayEach (TypedSlice)
- Bag
- Between
- Cap
- Cap (Operator)
- CmpAll
- CmpAny
- CmpArray (Array)
- CmpArray (TypedArray)
- CmpArrayEach (Array)
- CmpArrayEach (Slice)
- CmpArrayEach (TypedArray)
- CmpArrayEach (TypedSlice)
- CmpBag
- CmpBetween
- CmpCap
- CmpCap (Operator)
- CmpCode
- CmpContains (ArraySlice)
- CmpContains (Error)
- CmpContains (Map)
- CmpContains (Nil)
- CmpContains (String)
- CmpContains (Stringer)
- CmpContainsKey
- CmpContainsKey (Nil)
- CmpEmpty
- CmpEmpty (Pointers)
- CmpError
- CmpFalse
- CmpGt
- CmpGte
- CmpHasPrefix
- CmpHasPrefix (Error)
- CmpHasPrefix (Stringer)
- CmpHasSuffix
- CmpHasSuffix (Error)
- CmpHasSuffix (Stringer)
- CmpIsa
- CmpIsa (Interface)
- CmpLen (Map)
- CmpLen (OperatorMap)
- CmpLen (OperatorSlice)
- CmpLen (Slice)
- CmpLt
- CmpLte
- CmpMap (Map)
- CmpMap (TypedMap)
- CmpMapEach (Map)
- CmpMapEach (TypedMap)
- CmpN
- CmpNaN (Float32)
- CmpNaN (Float64)
- CmpNil
- CmpNoError
- CmpNone
- CmpNot
- CmpNotAny
- CmpNotEmpty
- CmpNotEmpty (Pointers)
- CmpNotNaN (Float32)
- CmpNotNaN (Float64)
- CmpNotNil
- CmpNotPanic
- CmpNotZero
- CmpPPtr
- CmpPanic
- CmpPtr
- CmpRe
- CmpRe (Capture)
- CmpRe (Compiled)
- CmpRe (CompiledCapture)
- CmpRe (CompiledError)
- CmpRe (CompiledStringer)
- CmpRe (Error)
- CmpRe (Stringer)
- CmpReAll (Capture)
- CmpReAll (CaptureComplex)
- CmpReAll (CompiledCapture)
- CmpReAll (CompiledCaptureComplex)
- CmpSet
- CmpShallow
- CmpShallow (Slice)
- CmpShallow (String)
- CmpSlice (Slice)
- CmpSlice (TypedSlice)
- CmpSmuggle (Auto_unmarshal)
- CmpSmuggle (Complex)
- CmpSmuggle (Convert)
- CmpSmuggle (Field_path)
- CmpSmuggle (Interface)
- CmpSmuggle (Lax)
- CmpString
- CmpString (Error)
- CmpString (Stringer)
- CmpStruct
- CmpSubBagOf
- CmpSubMapOf (Map)
- CmpSubMapOf (TypedMap)
- CmpSubSetOf
- CmpSuperBagOf
- CmpSuperMapOf (Map)
- CmpSuperMapOf (TypedMap)
- CmpSuperSetOf
- CmpTrue
- CmpTruncTime
- CmpZero
- Code
- Contains (ArraySlice)
- Contains (Error)
- Contains (Map)
- Contains (Nil)
- Contains (String)
- Contains (Stringer)
- ContainsKey
- ContainsKey (Nil)
- Empty
- Empty (Pointers)
- EqDeeply
- EqDeeplyError
- Gt
- Gte
- HasPrefix
- HasPrefix (Error)
- HasPrefix (Stringer)
- HasSuffix
- HasSuffix (Error)
- HasSuffix (Stringer)
- Ignore
- Isa
- Isa (Interface)
- Len (Map)
- Len (OperatorMap)
- Len (OperatorSlice)
- Len (Slice)
- Lt
- Lte
- Map (Map)
- Map (TypedMap)
- MapEach (Map)
- MapEach (TypedMap)
- N
- NaN (Float32)
- NaN (Float64)
- Nil
- None
- Not
- NotAny
- NotEmpty
- NotEmpty (Pointers)
- NotNaN (Float32)
- NotNaN (Float64)
- NotNil
- NotZero
- PPtr
- Ptr
- Re
- Re (Capture)
- Re (Compiled)
- Re (CompiledCapture)
- Re (CompiledError)
- Re (CompiledStringer)
- Re (Error)
- Re (Stringer)
- ReAll (Capture)
- ReAll (CaptureComplex)
- ReAll (CompiledCapture)
- ReAll (CompiledCaptureComplex)
- Set
- Shallow
- Shallow (Slice)
- Shallow (String)
- Slice (Slice)
- Slice (TypedSlice)
- Smuggle (Auto_unmarshal)
- Smuggle (Complex)
- Smuggle (Convert)
- Smuggle (Field_path)
- Smuggle (Interface)
- Smuggle (Lax)
- String
- String (Error)
- String (Stringer)
- Struct
- SubBagOf
- SubMapOf (Map)
- SubMapOf (TypedMap)
- SubSetOf
- SuperBagOf
- SuperMapOf (Map)
- SuperMapOf (TypedMap)
- SuperSetOf
- T.All
- T.Any
- T.Array (Array)
- T.Array (TypedArray)
- T.ArrayEach (Array)
- T.ArrayEach (Slice)
- T.ArrayEach (TypedArray)
- T.ArrayEach (TypedSlice)
- T.Bag
- T.Between
- T.Cap
- T.Cap (Operator)
- T.CmpError
- T.CmpNoError
- T.CmpNotPanic
- T.CmpPanic
- T.Code
- T.Contains (ArraySlice)
- T.Contains (Error)
- T.Contains (Map)
- T.Contains (Nil)
- T.Contains (String)
- T.Contains (Stringer)
- T.ContainsKey
- T.ContainsKey (Nil)
- T.Empty
- T.Empty (Pointers)
- T.False
- T.Gt
- T.Gte
- T.HasPrefix
- T.HasPrefix (Error)
- T.HasPrefix (Stringer)
- T.HasSuffix
- T.HasSuffix (Error)
- T.HasSuffix (Stringer)
- T.Isa
- T.Isa (Interface)
- T.Len (Map)
- T.Len (OperatorMap)
- T.Len (OperatorSlice)
- T.Len (Slice)
- T.Lt
- T.Lte
- T.Map (Map)
- T.Map (TypedMap)
- T.MapEach (Map)
- T.MapEach (TypedMap)
- T.N
- T.NaN (Float32)
- T.NaN (Float64)
- T.Nil
- T.None
- T.Not
- T.NotAny
- T.NotEmpty
- T.NotEmpty (Pointers)
- T.NotNaN (Float32)
- T.NotNaN (Float64)
- T.NotNil
- T.NotZero
- T.PPtr
- T.Ptr
- T.Re
- T.Re (Capture)
- T.Re (Compiled)
- T.Re (CompiledCapture)
- T.Re (CompiledError)
- T.Re (CompiledStringer)
- T.Re (Error)
- T.Re (Stringer)
- T.ReAll (Capture)
- T.ReAll (CaptureComplex)
- T.ReAll (CompiledCapture)
- T.ReAll (CompiledCaptureComplex)
- T.Set
- T.Shallow
- T.Shallow (Slice)
- T.Shallow (String)
- T.Slice (Slice)
- T.Slice (TypedSlice)
- T.Smuggle (Auto_unmarshal)
- T.Smuggle (Complex)
- T.Smuggle (Convert)
- T.Smuggle (Field_path)
- T.Smuggle (Interface)
- T.Smuggle (Lax)
- T.String
- T.String (Error)
- T.String (Stringer)
- T.Struct
- T.SubBagOf
- T.SubMapOf (Map)
- T.SubMapOf (TypedMap)
- T.SubSetOf
- T.SuperBagOf
- T.SuperMapOf (Map)
- T.SuperMapOf (TypedMap)
- T.SuperSetOf
- T.True
- T.TruncTime
- T.Zero
- TruncTime
- Zero
Constants ¶
This section is empty.
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.)
Functions ¶
func CmpAll ¶
CmpAll is a shortcut for:
CmpDeeply(t, got, All(expectedValues...), 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.
Example ¶
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 ¶
CmpAny is a shortcut for:
CmpDeeply(t, got, Any(expectedValues...), 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.
Example ¶
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 ¶
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...)
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.
Example (Array) ¶
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
Example (TypedArray) ¶
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 ¶
CmpArrayEach is a shortcut for:
CmpDeeply(t, got, ArrayEach(expectedValue), 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.
Example (Array) ¶
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
Example (Slice) ¶
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
Example (TypedArray) ¶
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
Example (TypedSlice) ¶
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 ¶
CmpBag is a shortcut for:
CmpDeeply(t, got, Bag(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example ¶
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
func CmpCap ¶
CmpCap is a shortcut for:
CmpDeeply(t, got, Cap(val), 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.
Example ¶
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
Example (Operator) ¶
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 ¶
CmpCode is a shortcut for:
CmpDeeply(t, got, Code(fn), 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.
Example ¶
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 ¶
CmpContains is a shortcut for:
CmpDeeply(t, got, Contains(expectedValue), 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.
Example (ArraySlice) ¶
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
Example (Error) ¶
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
Example (Map) ¶
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
Example (Nil) ¶
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
Example (String) ¶
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
Example (Stringer) ¶
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 ¶ added in v1.0.4
func CmpContainsKey(t TestingT, got interface{}, expectedValue interface{}, args ...interface{}) bool
CmpContainsKey is a shortcut for:
CmpDeeply(t, got, ContainsKey(expectedValue), 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.
Example ¶
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
Example (Nil) ¶
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 ¶
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 ¶
CmpEmpty is a shortcut for:
CmpDeeply(t, got, Empty(), 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.
Example ¶
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
Example (Pointers) ¶
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 ¶
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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
CmpGt is a shortcut for:
CmpDeeply(t, got, Gt(val), 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.
Example ¶
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
func CmpGte ¶
CmpGte is a shortcut for:
CmpDeeply(t, got, Gte(val), 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.
Example ¶
t := &testing.T{} got := 156 ok := CmpGte(t, got, 156, "checks %v is ≥ 156", got) fmt.Println(ok)
Output: true
func CmpHasPrefix ¶
CmpHasPrefix is a shortcut for:
CmpDeeply(t, got, HasPrefix(expected), 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.
Example ¶
t := &testing.T{} got := "foobar" ok := CmpHasPrefix(t, got, "foo", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpHasPrefix(t, got, "foo", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
CmpHasSuffix is a shortcut for:
CmpDeeply(t, got, HasSuffix(expected), 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.
Example ¶
t := &testing.T{} got := "foobar" ok := CmpHasSuffix(t, got, "bar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpHasSuffix(t, got, "bar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
CmpIsa is a shortcut for:
CmpDeeply(t, got, Isa(model), 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.
Example ¶
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
Example (Interface) ¶
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 ¶
CmpLen is a shortcut for:
CmpDeeply(t, got, Len(val), 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.
Example (Map) ¶
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
Example (OperatorMap) ¶
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
Example (OperatorSlice) ¶
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
Example (Slice) ¶
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 ¶
CmpLt is a shortcut for:
CmpDeeply(t, got, Lt(val), 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.
Example ¶
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
func CmpLte ¶
CmpLte is a shortcut for:
CmpDeeply(t, got, Lte(val), 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.
Example ¶
t := &testing.T{} got := 156 ok := CmpLte(t, got, 156, "checks %v is ≤ 156", got) fmt.Println(ok)
Output: true
func CmpMap ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
CmpMapEach is a shortcut for:
CmpDeeply(t, got, MapEach(expectedValue), 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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
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...)
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.
Example ¶
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 ¶ added in v1.0.1
CmpNaN is a shortcut for:
CmpDeeply(t, got, NaN(), 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.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func CmpNil ¶
CmpNil is a shortcut for:
CmpDeeply(t, got, Nil(), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
CmpNone is a shortcut for:
CmpDeeply(t, got, None(expectedValues...), 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.
Example ¶
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 ¶
CmpNot is a shortcut for:
CmpDeeply(t, got, Not(expected), 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.
Example ¶
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 ¶
CmpNotAny is a shortcut for:
CmpDeeply(t, got, NotAny(expectedItems...), 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.
Example ¶
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 ¶
CmpNotEmpty is a shortcut for:
CmpDeeply(t, got, NotEmpty(), 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.
Example ¶
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
Example (Pointers) ¶
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 ¶ added in v1.0.1
CmpNotNaN is a shortcut for:
CmpDeeply(t, got, NotNaN(), 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.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func CmpNotNil ¶
CmpNotNil is a shortcut for:
CmpDeeply(t, got, NotNil(), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
CmpNotZero is a shortcut for:
CmpDeeply(t, got, NotZero(), 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.
Example ¶
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 ¶
CmpPPtr is a shortcut for:
CmpDeeply(t, got, PPtr(val), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
CmpPtr is a shortcut for:
CmpDeeply(t, got, Ptr(val), 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.
Example ¶
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 ¶
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...)
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.
Example ¶
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
Example (Capture) ¶
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
Example (Compiled) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledError) ¶
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
Example (CompiledStringer) ¶
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
Example (Error) ¶
t := &testing.T{} got := errors.New("foo bar") ok := CmpRe(t, got, "(zip|bar)$", nil, "checks value %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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...)
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.
Example (Capture) ¶
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
Example (CaptureComplex) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledCaptureComplex) ¶
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 ¶
CmpSet is a shortcut for:
CmpDeeply(t, got, Set(expectedItems...), 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.
Example ¶
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 ¶
CmpShallow is a shortcut for:
CmpDeeply(t, got, Shallow(expectedPtr), 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.
Example ¶
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
Example (Slice) ¶
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
Example (String) ¶
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 ¶
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...)
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.
Example (Slice) ¶
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
Example (TypedSlice) ¶
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 ¶
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...)
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.
Example (Auto_unmarshal) ¶
t := &testing.T{} // Automatically json.Unmarshal to compare got := []byte(`{"a":1,"b":2}`) ok := CmpSmuggle(t, got, func(b json.RawMessage) (r map[string]int, err error) { err = json.Unmarshal(b, &r) return }, map[string]int{ "a": 1, "b": 2, }) fmt.Println("JSON contents is OK:", ok)
Output: JSON contents is OK: true
Example (Complex) ¶
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
Example (Convert) ¶
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
Example (Field_path) ¶
t := &testing.T{} type Body struct { Name string Value interface{} } type Request struct { Body *Body } type Transaction struct { Request } type ValueNum struct { Num int } got := &Transaction{ Request: Request{ Body: &Body{ Name: "test", Value: &ValueNum{Num: 123}, }, }, } // Want to check whether Num is between 100 and 200? ok := CmpSmuggle(t, got, func(t *Transaction) (int, error) { if t.Request.Body == nil || t.Request.Body.Value == nil { return 0, errors.New("Request.Body or Request.Body.Value is nil") } if v, ok := t.Request.Body.Value.(*ValueNum); ok && v != nil { return v.Num, nil } return 0, errors.New("Request.Body.Value isn't *ValueNum or nil") }, Between(100, 200)) fmt.Println("check Num by hand:", ok) // Same, but automagically generated... ok = CmpSmuggle(t, got, "Request.Body.Value.Num", Between(100, 200)) fmt.Println("check Num using a fields-path:", ok) // And as Request is an anonymous field, can be simplified further // as it can be omitted ok = CmpSmuggle(t, got, "Body.Value.Num", Between(100, 200)) fmt.Println("check Num using an other fields-path:", ok)
Output: check Num by hand: true check Num using a fields-path: true check Num using an other fields-path: true
Example (Interface) ¶
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 it 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
Output:
Example (Lax) ¶
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 ¶
CmpString is a shortcut for:
CmpDeeply(t, got, String(expected), 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.
Example ¶
t := &testing.T{} got := "foobar" ok := CmpString(t, got, "foobar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpString(t, got, "foobar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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...)
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.
Example ¶
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 ¶
func CmpSubBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
CmpSubBagOf is a shortcut for:
CmpDeeply(t, got, SubBagOf(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
func CmpSubSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
CmpSubSetOf is a shortcut for:
CmpDeeply(t, got, SubSetOf(expectedItems...), 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.
Example ¶
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 ¶
func CmpSuperBagOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
CmpSuperBagOf is a shortcut for:
CmpDeeply(t, got, SuperBagOf(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
func CmpSuperSetOf(t TestingT, got interface{}, expectedItems []interface{}, args ...interface{}) bool
CmpSuperSetOf is a shortcut for:
CmpDeeply(t, got, SuperSetOf(expectedItems...), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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...)
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.
Example ¶
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 ¶
CmpZero is a shortcut for:
CmpDeeply(t, got, Zero(), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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.
Example ¶
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 something like: // DATA.Items[2]: values differ // got: 9 // expected: 3 ≤ got ≤ 8 // [under TestDeep operator Between at equal_test.go:17]
Output:
Types ¶
type ArrayEntries ¶
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 ¶
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 ¶
NewBase returns a new Base struct with location.Location set to the "callDepth" depth.
func (*Base) GetLocation ¶
GetLocation returns a copy of the location.Location where the TestDeep operator has been created.
func (Base) HandleInvalid ¶
HandleInvalid tells testdeep internals that this operator does not handle nil values directly.
func (Base) TypeBehind ¶
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 ¶
type BaseOKNil struct {
Base
}
BaseOKNil is a base type providing some methods needed by the TestDeep interface, for operators handling nil values.
func NewBaseOKNil ¶
NewBaseOKNil returns a new BaseOKNil struct with location.Location set to the "callDepth" depth.
func (BaseOKNil) HandleInvalid ¶
HandleInvalid tells testdeep internals that this operator handles nil values directly.
type BoundsKind ¶
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 ¶
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 ¶
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 ¶
type SmuggledGot struct { Name string Got interface{} }
SmuggledGot can be returned by a Smuggle function to name the transformed / returned value.
type StructFields ¶
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 ¶
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 ¶
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: (int) 12 expected: (int) 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 ¶
All is a shortcut for:
t.CmpDeeply(got, All(expectedValues...), 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.
Example ¶
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 ¶
Any is a shortcut for:
t.CmpDeeply(got, Any(expectedValues...), 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.
Example ¶
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 ¶
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...)
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.
Example (Array) ¶
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
Example (TypedArray) ¶
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 ¶
ArrayEach is a shortcut for:
t.CmpDeeply(got, ArrayEach(expectedValue), 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.
Example (Array) ¶
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
Example (Slice) ¶
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
Example (TypedArray) ¶
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
Example (TypedSlice) ¶
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 ¶
Bag is a shortcut for:
t.CmpDeeply(got, Bag(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example ¶
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
func (*T) Cap ¶
Cap is a shortcut for:
t.CmpDeeply(got, Cap(val), 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.
Example ¶
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
Example (Operator) ¶
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 ¶
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 ¶
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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
Code is a shortcut for:
t.CmpDeeply(got, Code(fn), 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.
Example ¶
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 ¶
Contains is a shortcut for:
t.CmpDeeply(got, Contains(expectedValue), 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.
Example (ArraySlice) ¶
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
Example (Error) ¶
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
Example (Map) ¶
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
Example (Nil) ¶
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
Example (String) ¶
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
Example (Stringer) ¶
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 ¶ added in v1.0.4
ContainsKey is a shortcut for:
t.CmpDeeply(got, ContainsKey(expectedValue), 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.
Example ¶
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
Example (Nil) ¶
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 ¶
Empty is a shortcut for:
t.CmpDeeply(got, Empty(), 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.
Example ¶
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
Example (Pointers) ¶
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 ¶
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 ¶
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.
Example ¶
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 ¶
Gt is a shortcut for:
t.CmpDeeply(got, Gt(val), 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.
Example ¶
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
func (*T) Gte ¶
Gte is a shortcut for:
t.CmpDeeply(got, Gte(val), 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.
Example ¶
t := NewT(&testing.T{}) got := 156 ok := t.Gte(got, 156, "checks %v is ≥ 156", got) fmt.Println(ok)
Output: true
func (*T) HasPrefix ¶
HasPrefix is a shortcut for:
t.CmpDeeply(got, HasPrefix(expected), 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.
Example ¶
t := NewT(&testing.T{}) got := "foobar" ok := t.HasPrefix(got, "foo", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := NewT(&testing.T{}) got := errors.New("foobar") ok := t.HasPrefix(got, "foo", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
HasSuffix is a shortcut for:
t.CmpDeeply(got, HasSuffix(expected), 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.
Example ¶
t := NewT(&testing.T{}) got := "foobar" ok := t.HasSuffix(got, "bar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := NewT(&testing.T{}) got := errors.New("foobar") ok := t.HasSuffix(got, "bar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
Isa is a shortcut for:
t.CmpDeeply(got, Isa(model), 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.
Example ¶
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
Example (Interface) ¶
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 ¶
Len is a shortcut for:
t.CmpDeeply(got, Len(val), 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.
Example (Map) ¶
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
Example (OperatorMap) ¶
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
Example (OperatorSlice) ¶
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
Example (Slice) ¶
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 ¶
Lt is a shortcut for:
t.CmpDeeply(got, Lt(val), 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.
Example ¶
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
func (*T) Lte ¶
Lte is a shortcut for:
t.CmpDeeply(got, Lte(val), 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.
Example ¶
t := NewT(&testing.T{}) got := 156 ok := t.Lte(got, 156, "checks %v is ≤ 156", got) fmt.Println(ok)
Output: true
func (*T) Map ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
MapEach is a shortcut for:
t.CmpDeeply(got, MapEach(expectedValue), 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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
N is a shortcut for:
t.CmpDeeply(got, N(num, tolerance), args...)
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.
Example ¶
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 ¶ added in v1.0.1
NaN is a shortcut for:
t.CmpDeeply(got, NaN(), 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.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func (*T) Nil ¶
Nil is a shortcut for:
t.CmpDeeply(got, Nil(), 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.
Example ¶
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 ¶
None is a shortcut for:
t.CmpDeeply(got, None(expectedValues...), 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.
Example ¶
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 ¶
Not is a shortcut for:
t.CmpDeeply(got, Not(expected), 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.
Example ¶
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 ¶
NotAny is a shortcut for:
t.CmpDeeply(got, NotAny(expectedItems...), 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.
Example ¶
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 ¶
NotEmpty is a shortcut for:
t.CmpDeeply(got, NotEmpty(), 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.
Example ¶
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
Example (Pointers) ¶
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 ¶ added in v1.0.1
NotNaN is a shortcut for:
t.CmpDeeply(got, NotNaN(), 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.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func (*T) NotNil ¶
NotNil is a shortcut for:
t.CmpDeeply(got, NotNil(), 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.
Example ¶
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 ¶
NotZero is a shortcut for:
t.CmpDeeply(got, NotZero(), 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.
Example ¶
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 ¶
PPtr is a shortcut for:
t.CmpDeeply(got, PPtr(val), 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.
Example ¶
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 ¶
Ptr is a shortcut for:
t.CmpDeeply(got, Ptr(val), 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.
Example ¶
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 ¶
Re is a shortcut for:
t.CmpDeeply(got, Re(reg, capture), args...)
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.
Example ¶
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
Example (Capture) ¶
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
Example (Compiled) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledError) ¶
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
Example (CompiledStringer) ¶
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
Example (Error) ¶
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
Example (Stringer) ¶
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 ¶
ReAll is a shortcut for:
t.CmpDeeply(got, ReAll(reg, capture), 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.
Example (Capture) ¶
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
Example (CaptureComplex) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledCaptureComplex) ¶
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 ¶
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 ¶
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 ¶
Set is a shortcut for:
t.CmpDeeply(got, Set(expectedItems...), 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.
Example ¶
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 ¶
Shallow is a shortcut for:
t.CmpDeeply(got, Shallow(expectedPtr), 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.
Example ¶
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
Example (Slice) ¶
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
Example (String) ¶
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 ¶
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...)
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.
Example (Slice) ¶
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
Example (TypedSlice) ¶
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 ¶
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...)
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.
Example (Auto_unmarshal) ¶
t := NewT(&testing.T{}) // Automatically json.Unmarshal to compare got := []byte(`{"a":1,"b":2}`) ok := t.Smuggle(got, func(b json.RawMessage) (r map[string]int, err error) { err = json.Unmarshal(b, &r) return }, map[string]int{ "a": 1, "b": 2, }) fmt.Println("JSON contents is OK:", ok)
Output: JSON contents is OK: true
Example (Complex) ¶
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
Example (Convert) ¶
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
Example (Field_path) ¶
t := NewT(&testing.T{}) type Body struct { Name string Value interface{} } type Request struct { Body *Body } type Transaction struct { Request } type ValueNum struct { Num int } got := &Transaction{ Request: Request{ Body: &Body{ Name: "test", Value: &ValueNum{Num: 123}, }, }, } // Want to check whether Num is between 100 and 200? ok := t.Smuggle(got, func(t *Transaction) (int, error) { if t.Request.Body == nil || t.Request.Body.Value == nil { return 0, errors.New("Request.Body or Request.Body.Value is nil") } if v, ok := t.Request.Body.Value.(*ValueNum); ok && v != nil { return v.Num, nil } return 0, errors.New("Request.Body.Value isn't *ValueNum or nil") }, Between(100, 200)) fmt.Println("check Num by hand:", ok) // Same, but automagically generated... ok = t.Smuggle(got, "Request.Body.Value.Num", Between(100, 200)) fmt.Println("check Num using a fields-path:", ok) // And as Request is an anonymous field, can be simplified further // as it can be omitted ok = t.Smuggle(got, "Body.Value.Num", Between(100, 200)) fmt.Println("check Num using an other fields-path:", ok)
Output: check Num by hand: true check Num using a fields-path: true check Num using an other fields-path: true
Example (Interface) ¶
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 it 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
Output:
Example (Lax) ¶
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 ¶
String is a shortcut for:
t.CmpDeeply(got, String(expected), 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.
Example ¶
t := NewT(&testing.T{}) got := "foobar" ok := t.String(got, "foobar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := NewT(&testing.T{}) got := errors.New("foobar") ok := t.String(got, "foobar", "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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...)
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.
Example ¶
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 ¶
SubBagOf is a shortcut for:
t.CmpDeeply(got, SubBagOf(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
SubSetOf is a shortcut for:
t.CmpDeeply(got, SubSetOf(expectedItems...), 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.
Example ¶
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 ¶
SuperBagOf is a shortcut for:
t.CmpDeeply(got, SuperBagOf(expectedItems...), 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.
Example ¶
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 ¶
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...)
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
SuperSetOf is a shortcut for:
t.CmpDeeply(got, SuperSetOf(expectedItems...), 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.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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...)
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.
Example ¶
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 ¶
Zero is a shortcut for:
t.CmpDeeply(got, Zero(), 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.
Example ¶
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 ¶
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 ¶
func All(expectedValues ...interface{}) TestDeep
All operator compares data against several expected values. During a match, all of them have to match to succeed.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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".
Example (Array) ¶
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
Example (TypedArray) ¶
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 ¶
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.
Example (Array) ¶
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
Example (Slice) ¶
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
Example (TypedArray) ¶
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
Example (TypedSlice) ¶
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 ¶
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
Example ¶
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 ¶
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 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 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.)
Example ¶
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
func Cap ¶
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))
Example ¶
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
Example (Operator) ¶
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 ¶
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".
Example ¶
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 ¶
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
Example (ArraySlice) ¶
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
Example (Error) ¶
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
Example (Map) ¶
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
Example (Nil) ¶
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
Example (String) ¶
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
Example (Stringer) ¶
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 ¶ added in v1.0.4
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)
Example ¶
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
Example (Nil) ¶
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 ¶
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.
Example ¶
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
Example (Pointers) ¶
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 ¶
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".
Example ¶
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
func Gte ¶
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".
Example ¶
t := &testing.T{} got := 156 ok := CmpDeeply(t, got, Gte(156), "checks %v is ≥ 156", got) fmt.Println(ok)
Output: true
func HasPrefix ¶
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
Example ¶
t := &testing.T{} got := "foobar" ok := CmpDeeply(t, got, HasPrefix("foo"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpDeeply(t, got, HasPrefix("foo"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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
Example ¶
t := &testing.T{} got := "foobar" ok := CmpDeeply(t, got, HasSuffix("bar"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpDeeply(t, got, HasSuffix("bar"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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.
Example ¶
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 ¶
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".
Example ¶
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
Example (Interface) ¶
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 ¶
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))
Example (Map) ¶
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
Example (OperatorMap) ¶
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
Example (OperatorSlice) ¶
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
Example (Slice) ¶
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 ¶
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".
Example ¶
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
func Lte ¶
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".
Example ¶
t := &testing.T{} got := 156 ok := CmpDeeply(t, got, Lte(156), "checks %v is ≤ 156", got) fmt.Println(ok)
Output: true
func Map ¶
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".
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
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.
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
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".
Example ¶
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 ¶ added in v1.0.1
func NaN() TestDeep
NaN operator checks that data is a float and is not-a-number.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func Nil ¶
func Nil() TestDeep
Nil operator checks that data is nil (or is a non-nil interface, but containing a nil pointer.)
Example ¶
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 ¶
func None(expectedValues ...interface{}) TestDeep
None operator compares data against several expected values. During a match, none of them have to match to succeed.
Example ¶
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 ¶
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.
Example ¶
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 ¶
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
Example ¶
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 ¶
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.
Example ¶
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
Example (Pointers) ¶
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 ¶ added in v1.0.1
func NotNaN() TestDeep
NotNaN operator checks that data is a float and is not not-a-number.
Example (Float32) ¶
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
Example (Float64) ¶
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
Output:
func NotNil ¶
func NotNil() TestDeep
NotNil operator checks that data is not nil (or is a non-nil interface, containing a non-nil pointer.)
Example ¶
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 ¶
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
Example ¶
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 ¶
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))
Example ¶
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 ¶
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))
Example ¶
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 ¶
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
Example ¶
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
Example (Capture) ¶
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
Example (Compiled) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledError) ¶
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
Example (CompiledStringer) ¶
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
Example (Error) ¶
t := &testing.T{} got := errors.New("foo bar") ok := CmpDeeply(t, got, Re("(zip|bar)$"), "checks value %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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
Example (Capture) ¶
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
Example (CaptureComplex) ¶
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
Example (CompiledCapture) ¶
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
Example (CompiledCaptureComplex) ¶
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 ¶
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
Example ¶
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 ¶
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
Example ¶
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
Example (Slice) ¶
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
Example (String) ¶
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 ¶
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".
Example (Slice) ¶
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
Example (TypedSlice) ¶
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 ¶
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.
Example (Auto_unmarshal) ¶
t := &testing.T{} // Automatically json.Unmarshal to compare got := []byte(`{"a":1,"b":2}`) ok := CmpDeeply(t, got, Smuggle( func(b json.RawMessage) (r map[string]int, err error) { err = json.Unmarshal(b, &r) return }, map[string]int{ "a": 1, "b": 2, })) fmt.Println("JSON contents is OK:", ok)
Output: JSON contents is OK: true
Example (Complex) ¶
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
Example (Convert) ¶
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
Example (Field_path) ¶
t := &testing.T{} type Body struct { Name string Value interface{} } type Request struct { Body *Body } type Transaction struct { Request } type ValueNum struct { Num int } got := &Transaction{ Request: Request{ Body: &Body{ Name: "test", Value: &ValueNum{Num: 123}, }, }, } // Want to check whether Num is between 100 and 200? ok := CmpDeeply(t, got, Smuggle( func(t *Transaction) (int, error) { if t.Request.Body == nil || t.Request.Body.Value == nil { return 0, errors.New("Request.Body or Request.Body.Value is nil") } if v, ok := t.Request.Body.Value.(*ValueNum); ok && v != nil { return v.Num, nil } return 0, errors.New("Request.Body.Value isn't *ValueNum or nil") }, Between(100, 200))) fmt.Println("check Num by hand:", ok) // Same, but automagically generated... ok = CmpDeeply(t, got, Smuggle("Request.Body.Value.Num", Between(100, 200))) fmt.Println("check Num using a fields-path:", ok) // And as Request is an anonymous field, can be simplified further // as it can be omitted ok = CmpDeeply(t, got, Smuggle("Body.Value.Num", Between(100, 200))) fmt.Println("check Num using an other fields-path:", ok)
Output: check Num by hand: true check Num using a fields-path: true check Num using an other fields-path: true
Example (Interface) ¶
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 it 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
Output:
Example (Lax) ¶
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 ¶
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
Example ¶
t := &testing.T{} got := "foobar" ok := CmpDeeply(t, got, String("foobar"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Error) ¶
t := &testing.T{} got := errors.New("foobar") ok := CmpDeeply(t, got, String("foobar"), "checks %s", got) fmt.Println(ok)
Output: true
Example (Stringer) ¶
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 ¶
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".
Example ¶
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 ¶
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
Example ¶
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 ¶
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".
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
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
Example ¶
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 ¶
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
Example ¶
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 ¶
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".
Example (Map) ¶
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
Example (TypedMap) ¶
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 ¶
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
Example ¶
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 ¶
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".
Example ¶
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 ¶
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
Example ¶
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 ¶
type TestingFT interface { Error(args ...interface{}) Errorf(format string, args ...interface{}) Fail() FailNow() Failed() bool Fatal(args ...interface{}) 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 Helper() 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.
Source 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