pax_global_header00006660000000000000000000000064135317116150014515gustar00rootroot0000000000000052 comment=6d6f5a45a2129db0670ff0c9b27e2a394e949cd6 golang-github-go-test-deep-1.0.3/000077500000000000000000000000001353171161500165405ustar00rootroot00000000000000golang-github-go-test-deep-1.0.3/.gitignore000066400000000000000000000000141353171161500205230ustar00rootroot00000000000000*.swp *.out golang-github-go-test-deep-1.0.3/.travis.yml000066400000000000000000000003111353171161500206440ustar00rootroot00000000000000language: go go: - "1.10" - "1.11" - "1.12" before_install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cover script: - $HOME/gopath/bin/goveralls -service=travis-ci golang-github-go-test-deep-1.0.3/CHANGES.md000066400000000000000000000017511353171161500201360ustar00rootroot00000000000000# go-test/deep Changelog ## v1.0.3 * Fixed issue #31: panic on typed primitives that implement error interface ## v1.0.2 released 2019-07-14 * Enabled Go module (@radeksimko) * Changed supported and tested Go versions: 1.10, 1.11, and 1.12 (dropped 1.9) * Changed Error equality: additional struct fields are compared too (PR #29) (@andrewmostello) * Fixed typos and ineffassign issues (PR #25) (@tariq1890) * Fixed diff order for nil comparison (PR #16) (@gmarik) * Fixed slice equality when slices are extracted from the same array (PR #11) (@risteli) * Fixed test spelling and messages (PR #19) (@sofuture) * Fixed issue #15: panic on comparing struct with anonymous time.Time * Fixed issue #18: Panic when comparing structs with time.Time value and CompareUnexportedFields is true * Fixed issue #21: Set default MaxDepth = 0 (disabled) (PR #23) ## v1.0.1 released 2018-01-28 * Fixed issue #12: Arrays are not properly compared (@samlitowitz) ## v1.0.0 releaesd 2017-10-27 * First release golang-github-go-test-deep-1.0.3/LICENSE000066400000000000000000000020601353171161500175430ustar00rootroot00000000000000MIT License Copyright 2015-2017 Daniel Nichter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-go-test-deep-1.0.3/README.md000066400000000000000000000033571353171161500200270ustar00rootroot00000000000000# Deep Variable Equality for Humans [![Go Report Card](https://goreportcard.com/badge/github.com/go-test/deep)](https://goreportcard.com/report/github.com/go-test/deep) [![Build Status](https://travis-ci.org/go-test/deep.svg?branch=master)](https://travis-ci.org/go-test/deep) [![Coverage Status](https://coveralls.io/repos/github/go-test/deep/badge.svg?branch=master)](https://coveralls.io/github/go-test/deep?branch=master) [![GoDoc](https://godoc.org/github.com/go-test/deep?status.svg)](https://godoc.org/github.com/go-test/deep) This package provides a single function: `deep.Equal`. It's like [reflect.DeepEqual](http://golang.org/pkg/reflect/#DeepEqual) but much friendlier to humans (or any sentient being) for two reason: * `deep.Equal` returns a list of differences * `deep.Equal` does not compare unexported fields (by default) `reflect.DeepEqual` is good (like all things Golang!), but it's a game of [Hunt the Wumpus](https://en.wikipedia.org/wiki/Hunt_the_Wumpus). For large maps, slices, and structs, finding the difference is difficult. `deep.Equal` doesn't play games with you, it lists the differences: ```go package main_test import ( "testing" "github.com/go-test/deep" ) type T struct { Name string Numbers []float64 } func TestDeepEqual(t *testing.T) { // Can you spot the difference? t1 := T{ Name: "Isabella", Numbers: []float64{1.13459, 2.29343, 3.010100010}, } t2 := T{ Name: "Isabella", Numbers: []float64{1.13459, 2.29843, 3.010100010}, } if diff := deep.Equal(t1, t2); diff != nil { t.Error(diff) } } ``` ``` $ go test --- FAIL: TestDeepEqual (0.00s) main_test.go:25: [Numbers.slice[1]: 2.29343 != 2.29843] ``` The difference is in `Numbers.slice[1]`: the two values aren't equal using Go `==`. golang-github-go-test-deep-1.0.3/deep.go000066400000000000000000000221651353171161500200120ustar00rootroot00000000000000// Package deep provides function deep.Equal which is like reflect.DeepEqual but // returns a list of differences. This is helpful when comparing complex types // like structures and maps. package deep import ( "errors" "fmt" "log" "reflect" "strings" ) var ( // FloatPrecision is the number of decimal places to round float values // to when comparing. FloatPrecision = 10 // MaxDiff specifies the maximum number of differences to return. MaxDiff = 10 // MaxDepth specifies the maximum levels of a struct to recurse into, // if greater than zero. If zero, there is no limit. MaxDepth = 0 // LogErrors causes errors to be logged to STDERR when true. LogErrors = false // CompareUnexportedFields causes unexported struct fields, like s in // T{s int}, to be compared when true. CompareUnexportedFields = false ) var ( // ErrMaxRecursion is logged when MaxDepth is reached. ErrMaxRecursion = errors.New("recursed to MaxDepth") // ErrTypeMismatch is logged when Equal passed two different types of values. ErrTypeMismatch = errors.New("variables are different reflect.Type") // ErrNotHandled is logged when a primitive Go kind is not handled. ErrNotHandled = errors.New("cannot compare the reflect.Kind") ) type cmp struct { diff []string buff []string floatFormat string } var errorType = reflect.TypeOf((*error)(nil)).Elem() // Equal compares variables a and b, recursing into their structure up to // MaxDepth levels deep (if greater than zero), and returns a list of differences, // or nil if there are none. Some differences may not be found if an error is // also returned. // // If a type has an Equal method, like time.Equal, it is called to check for // equality. func Equal(a, b interface{}) []string { aVal := reflect.ValueOf(a) bVal := reflect.ValueOf(b) c := &cmp{ diff: []string{}, buff: []string{}, floatFormat: fmt.Sprintf("%%.%df", FloatPrecision), } if a == nil && b == nil { return nil } else if a == nil && b != nil { c.saveDiff("", b) } else if a != nil && b == nil { c.saveDiff(a, "") } if len(c.diff) > 0 { return c.diff } c.equals(aVal, bVal, 0) if len(c.diff) > 0 { return c.diff // diffs } return nil // no diffs } func (c *cmp) equals(a, b reflect.Value, level int) { if MaxDepth > 0 && level > MaxDepth { logError(ErrMaxRecursion) return } // Check if one value is nil, e.g. T{x: *X} and T.x is nil if !a.IsValid() || !b.IsValid() { if a.IsValid() && !b.IsValid() { c.saveDiff(a.Type(), "") } else if !a.IsValid() && b.IsValid() { c.saveDiff("", b.Type()) } return } // If different types, they can't be equal aType := a.Type() bType := b.Type() if aType != bType { c.saveDiff(aType, bType) logError(ErrTypeMismatch) return } // Primitive https://golang.org/pkg/reflect/#Kind aKind := a.Kind() bKind := b.Kind() // Do a and b have underlying elements? Yes if they're ptr or interface. aElem := aKind == reflect.Ptr || aKind == reflect.Interface bElem := bKind == reflect.Ptr || bKind == reflect.Interface // If both types implement the error interface, compare the error strings. // This must be done before dereferencing because the interface is on a // pointer receiver. Re https://github.com/go-test/deep/issues/31, a/b might // be primitive kinds; see TestErrorPrimitiveKind. if aType.Implements(errorType) && bType.Implements(errorType) { if (!aElem || !a.IsNil()) && (!bElem || !b.IsNil()) { aString := a.MethodByName("Error").Call(nil)[0].String() bString := b.MethodByName("Error").Call(nil)[0].String() if aString != bString { c.saveDiff(aString, bString) return } } } // Dereference pointers and interface{} if aElem || bElem { if aElem { a = a.Elem() } if bElem { b = b.Elem() } c.equals(a, b, level+1) return } switch aKind { ///////////////////////////////////////////////////////////////////// // Iterable kinds ///////////////////////////////////////////////////////////////////// case reflect.Struct: /* The variables are structs like: type T struct { FirstName string LastName string } Type = .T, Kind = reflect.Struct Iterate through the fields (FirstName, LastName), recurse into their values. */ // Types with an Equal() method, like time.Time, only if struct field // is exported (CanInterface) if eqFunc := a.MethodByName("Equal"); eqFunc.IsValid() && eqFunc.CanInterface() { // Handle https://github.com/go-test/deep/issues/15: // Don't call T.Equal if the method is from an embedded struct, like: // type Foo struct { time.Time } // First, we'll encounter Equal(Ttime, time.Time) but if we pass b // as the 2nd arg we'll panic: "Call using pkg.Foo as type time.Time" // As far as I can tell, there's no way to see that the method is from // time.Time not Foo. So we check the type of the 1st (0) arg and skip // unless it's b type. Later, we'll encounter the time.Time anonymous/ // embedded field and then we'll have Equal(time.Time, time.Time). funcType := eqFunc.Type() if funcType.NumIn() == 1 && funcType.In(0) == bType { retVals := eqFunc.Call([]reflect.Value{b}) if !retVals[0].Bool() { c.saveDiff(a, b) } return } } for i := 0; i < a.NumField(); i++ { if aType.Field(i).PkgPath != "" && !CompareUnexportedFields { continue // skip unexported field, e.g. s in type T struct {s string} } c.push(aType.Field(i).Name) // push field name to buff // Get the Value for each field, e.g. FirstName has Type = string, // Kind = reflect.String. af := a.Field(i) bf := b.Field(i) // Recurse to compare the field values c.equals(af, bf, level+1) c.pop() // pop field name from buff if len(c.diff) >= MaxDiff { break } } case reflect.Map: /* The variables are maps like: map[string]int{ "foo": 1, "bar": 2, } Type = map[string]int, Kind = reflect.Map Or: type T map[string]int{} Type = .T, Kind = reflect.Map Iterate through the map keys (foo, bar), recurse into their values. */ if a.IsNil() || b.IsNil() { if a.IsNil() && !b.IsNil() { c.saveDiff("", b) } else if !a.IsNil() && b.IsNil() { c.saveDiff(a, "") } return } if a.Pointer() == b.Pointer() { return } for _, key := range a.MapKeys() { c.push(fmt.Sprintf("map[%s]", key)) aVal := a.MapIndex(key) bVal := b.MapIndex(key) if bVal.IsValid() { c.equals(aVal, bVal, level+1) } else { c.saveDiff(aVal, "") } c.pop() if len(c.diff) >= MaxDiff { return } } for _, key := range b.MapKeys() { if aVal := a.MapIndex(key); aVal.IsValid() { continue } c.push(fmt.Sprintf("map[%s]", key)) c.saveDiff("", b.MapIndex(key)) c.pop() if len(c.diff) >= MaxDiff { return } } case reflect.Array: n := a.Len() for i := 0; i < n; i++ { c.push(fmt.Sprintf("array[%d]", i)) c.equals(a.Index(i), b.Index(i), level+1) c.pop() if len(c.diff) >= MaxDiff { break } } case reflect.Slice: if a.IsNil() || b.IsNil() { if a.IsNil() && !b.IsNil() { c.saveDiff("", b) } else if !a.IsNil() && b.IsNil() { c.saveDiff(a, "") } return } aLen := a.Len() bLen := b.Len() if a.Pointer() == b.Pointer() && aLen == bLen { return } n := aLen if bLen > aLen { n = bLen } for i := 0; i < n; i++ { c.push(fmt.Sprintf("slice[%d]", i)) if i < aLen && i < bLen { c.equals(a.Index(i), b.Index(i), level+1) } else if i < aLen { c.saveDiff(a.Index(i), "") } else { c.saveDiff("", b.Index(i)) } c.pop() if len(c.diff) >= MaxDiff { break } } ///////////////////////////////////////////////////////////////////// // Primitive kinds ///////////////////////////////////////////////////////////////////// case reflect.Float32, reflect.Float64: // Avoid 0.04147685731961082 != 0.041476857319611 // 6 decimal places is close enough aval := fmt.Sprintf(c.floatFormat, a.Float()) bval := fmt.Sprintf(c.floatFormat, b.Float()) if aval != bval { c.saveDiff(a.Float(), b.Float()) } case reflect.Bool: if a.Bool() != b.Bool() { c.saveDiff(a.Bool(), b.Bool()) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if a.Int() != b.Int() { c.saveDiff(a.Int(), b.Int()) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if a.Uint() != b.Uint() { c.saveDiff(a.Uint(), b.Uint()) } case reflect.String: if a.String() != b.String() { c.saveDiff(a.String(), b.String()) } default: logError(ErrNotHandled) } } func (c *cmp) push(name string) { c.buff = append(c.buff, name) } func (c *cmp) pop() { if len(c.buff) > 0 { c.buff = c.buff[0 : len(c.buff)-1] } } func (c *cmp) saveDiff(aval, bval interface{}) { if len(c.buff) > 0 { varName := strings.Join(c.buff, ".") c.diff = append(c.diff, fmt.Sprintf("%s: %v != %v", varName, aval, bval)) } else { c.diff = append(c.diff, fmt.Sprintf("%v != %v", aval, bval)) } } func logError(err error) { if LogErrors { log.Println(err) } } golang-github-go-test-deep-1.0.3/deep_test.go000066400000000000000000000515611353171161500210530ustar00rootroot00000000000000package deep_test import ( "errors" "fmt" "reflect" "testing" "time" "github.com/go-test/deep" ) func TestString(t *testing.T) { diff := deep.Equal("foo", "foo") if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal("foo", "bar") if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "foo != bar" { t.Error("wrong diff:", diff[0]) } } func TestFloat(t *testing.T) { diff := deep.Equal(1.1, 1.1) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(1.1234561, 1.1234562) if diff == nil { t.Error("no diff") } defaultFloatPrecision := deep.FloatPrecision deep.FloatPrecision = 6 defer func() { deep.FloatPrecision = defaultFloatPrecision }() diff = deep.Equal(1.1234561, 1.1234562) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(1.123456, 1.123457) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "1.123456 != 1.123457" { t.Error("wrong diff:", diff[0]) } } func TestInt(t *testing.T) { diff := deep.Equal(1, 1) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(1, 2) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "1 != 2" { t.Error("wrong diff:", diff[0]) } } func TestUint(t *testing.T) { diff := deep.Equal(uint(2), uint(2)) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(uint(2), uint(3)) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "2 != 3" { t.Error("wrong diff:", diff[0]) } } func TestBool(t *testing.T) { diff := deep.Equal(true, true) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(false, false) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(true, false) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "true != false" { // unless you're fipar t.Error("wrong diff:", diff[0]) } } func TestTypeMismatch(t *testing.T) { type T1 int // same type kind (int) type T2 int // but different type var t1 T1 = 1 var t2 T2 = 1 diff := deep.Equal(t1, t2) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "deep_test.T1 != deep_test.T2" { t.Error("wrong diff:", diff[0]) } } func TestKindMismatch(t *testing.T) { deep.LogErrors = true var x int = 100 var y float64 = 100 diff := deep.Equal(x, y) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "int != float64" { t.Error("wrong diff:", diff[0]) } deep.LogErrors = false } func TestDeepRecursion(t *testing.T) { deep.MaxDepth = 2 defer func() { deep.MaxDepth = 10 }() type s3 struct { S int } type s2 struct { S s3 } type s1 struct { S s2 } foo := map[string]s1{ "foo": { // 1 S: s2{ // 2 S: s3{ // 3 S: 42, // 4 }, }, }, } bar := map[string]s1{ "foo": { S: s2{ S: s3{ S: 100, }, }, }, } // No diffs because MaxDepth=2 prevents seeing the diff at 3rd level down diff := deep.Equal(foo, bar) if diff != nil { t.Errorf("got %d diffs, expected none: %v", len(diff), diff) } defaultMaxDepth := deep.MaxDepth deep.MaxDepth = 4 defer func() { deep.MaxDepth = defaultMaxDepth }() diff = deep.Equal(foo, bar) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "map[foo].S.S.S: 42 != 100" { t.Error("wrong diff:", diff[0]) } } func TestMaxDiff(t *testing.T) { a := []int{1, 2, 3, 4, 5, 6, 7} b := []int{0, 0, 0, 0, 0, 0, 0} defaultMaxDiff := deep.MaxDiff deep.MaxDiff = 3 defer func() { deep.MaxDiff = defaultMaxDiff }() diff := deep.Equal(a, b) if diff == nil { t.Fatal("no diffs") } if len(diff) != deep.MaxDiff { t.Errorf("got %d diffs, expected %d", len(diff), deep.MaxDiff) } defaultCompareUnexportedFields := deep.CompareUnexportedFields deep.CompareUnexportedFields = true defer func() { deep.CompareUnexportedFields = defaultCompareUnexportedFields }() type fiveFields struct { a int // unexported fields require ^ b int c int d int e int } t1 := fiveFields{1, 2, 3, 4, 5} t2 := fiveFields{0, 0, 0, 0, 0} diff = deep.Equal(t1, t2) if diff == nil { t.Fatal("no diffs") } if len(diff) != deep.MaxDiff { t.Errorf("got %d diffs, expected %d", len(diff), deep.MaxDiff) } // Same keys, too many diffs m1 := map[int]int{ 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, } m2 := map[int]int{ 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, } diff = deep.Equal(m1, m2) if diff == nil { t.Fatal("no diffs") } if len(diff) != deep.MaxDiff { t.Log(diff) t.Errorf("got %d diffs, expected %d", len(diff), deep.MaxDiff) } // Too many missing keys m1 = map[int]int{ 1: 1, 2: 2, } m2 = map[int]int{ 1: 1, 2: 2, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, } diff = deep.Equal(m1, m2) if diff == nil { t.Fatal("no diffs") } if len(diff) != deep.MaxDiff { t.Log(diff) t.Errorf("got %d diffs, expected %d", len(diff), deep.MaxDiff) } } func TestNotHandled(t *testing.T) { a := func(int) {} b := func(int) {} diff := deep.Equal(a, b) if len(diff) > 0 { t.Error("got diffs:", diff) } } func TestStruct(t *testing.T) { type s1 struct { id int Name string Number int } sa := s1{ id: 1, Name: "foo", Number: 2, } sb := sa diff := deep.Equal(sa, sb) if len(diff) > 0 { t.Error("should be equal:", diff) } sb.Name = "bar" diff = deep.Equal(sa, sb) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "Name: foo != bar" { t.Error("wrong diff:", diff[0]) } sb.Number = 22 diff = deep.Equal(sa, sb) if diff == nil { t.Fatal("no diff") } if len(diff) != 2 { t.Error("too many diff:", diff) } if diff[0] != "Name: foo != bar" { t.Error("wrong diff:", diff[0]) } if diff[1] != "Number: 2 != 22" { t.Error("wrong diff:", diff[1]) } sb.id = 11 diff = deep.Equal(sa, sb) if diff == nil { t.Fatal("no diff") } if len(diff) != 2 { t.Error("too many diff:", diff) } if diff[0] != "Name: foo != bar" { t.Error("wrong diff:", diff[0]) } if diff[1] != "Number: 2 != 22" { t.Error("wrong diff:", diff[1]) } } func TestNestedStruct(t *testing.T) { type s2 struct { Nickname string } type s1 struct { Name string Alias s2 } sa := s1{ Name: "Robert", Alias: s2{Nickname: "Bob"}, } sb := sa diff := deep.Equal(sa, sb) if len(diff) > 0 { t.Error("should be equal:", diff) } sb.Alias.Nickname = "Bobby" diff = deep.Equal(sa, sb) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "Alias.Nickname: Bob != Bobby" { t.Error("wrong diff:", diff[0]) } } func TestMap(t *testing.T) { ma := map[string]int{ "foo": 1, "bar": 2, } mb := map[string]int{ "foo": 1, "bar": 2, } diff := deep.Equal(ma, mb) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(ma, ma) if len(diff) > 0 { t.Error("should be equal:", diff) } mb["foo"] = 111 diff = deep.Equal(ma, mb) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "map[foo]: 1 != 111" { t.Error("wrong diff:", diff[0]) } delete(mb, "foo") diff = deep.Equal(ma, mb) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "map[foo]: 1 != " { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(mb, ma) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "map[foo]: != 1" { t.Error("wrong diff:", diff[0]) } var mc map[string]int diff = deep.Equal(ma, mc) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } // handle hash order randomness if diff[0] != "map[foo:1 bar:2] != " && diff[0] != "map[bar:2 foo:1] != " { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(mc, ma) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != " != map[foo:1 bar:2]" && diff[0] != " != map[bar:2 foo:1]" { t.Error("wrong diff:", diff[0]) } } func TestArray(t *testing.T) { a := [3]int{1, 2, 3} b := [3]int{1, 2, 3} diff := deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(a, a) if len(diff) > 0 { t.Error("should be equal:", diff) } b[2] = 333 diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "array[2]: 3 != 333" { t.Error("wrong diff:", diff[0]) } c := [3]int{1, 2, 2} diff = deep.Equal(a, c) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "array[2]: 3 != 2" { t.Error("wrong diff:", diff[0]) } var d [2]int diff = deep.Equal(a, d) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "[3]int != [2]int" { t.Error("wrong diff:", diff[0]) } e := [12]int{} f := [12]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} diff = deep.Equal(e, f) if diff == nil { t.Fatal("no diff") } if len(diff) != deep.MaxDiff { t.Error("not enough diffs:", diff) } for i := 0; i < deep.MaxDiff; i++ { if diff[i] != fmt.Sprintf("array[%d]: 0 != %d", i+1, i+1) { t.Error("wrong diff:", diff[i]) } } } func TestSlice(t *testing.T) { a := []int{1, 2, 3} b := []int{1, 2, 3} diff := deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(a, a) if len(diff) > 0 { t.Error("should be equal:", diff) } b[2] = 333 diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "slice[2]: 3 != 333" { t.Error("wrong diff:", diff[0]) } b = b[0:2] diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "slice[2]: 3 != " { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(b, a) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "slice[2]: != 3" { t.Error("wrong diff:", diff[0]) } var c []int diff = deep.Equal(a, c) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "[1 2 3] != " { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(c, a) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != " != [1 2 3]" { t.Error("wrong diff:", diff[0]) } } func TestSiblingSlices(t *testing.T) { father := []int{1, 2, 3, 4} a := father[0:3] b := father[0:3] diff := deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(b, a) if len(diff) > 0 { t.Error("should be equal:", diff) } a = father[0:3] b = father[0:2] diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "slice[2]: 3 != " { t.Error("wrong diff:", diff[0]) } a = father[0:2] b = father[0:3] diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "slice[2]: != 3" { t.Error("wrong diff:", diff[0]) } a = father[0:2] b = father[2:4] diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 2 { t.Error("too many diff:", diff) } if diff[0] != "slice[0]: 1 != 3" { t.Error("wrong diff:", diff[0]) } if diff[1] != "slice[1]: 2 != 4" { t.Error("wrong diff:", diff[1]) } a = father[0:0] b = father[1:1] diff = deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } diff = deep.Equal(b, a) if len(diff) > 0 { t.Error("should be equal:", diff) } } func TestNilInterface(t *testing.T) { type T struct{ i int } a := &T{i: 1} diff := deep.Equal(nil, a) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != " != &{1}" { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(a, nil) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "&{1} != " { t.Error("wrong diff:", diff[0]) } diff = deep.Equal(nil, nil) if len(diff) > 0 { t.Error("should be equal:", diff) } } func TestPointer(t *testing.T) { type T struct{ i int } a, b := &T{i: 1}, &T{i: 1} diff := deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } a, b = nil, &T{} diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != " != deep_test.T" { t.Error("wrong diff:", diff[0]) } a, b = &T{}, nil diff = deep.Equal(a, b) if diff == nil { t.Fatal("no diff") } if len(diff) != 1 { t.Error("too many diff:", diff) } if diff[0] != "deep_test.T != " { t.Error("wrong diff:", diff[0]) } a, b = nil, nil diff = deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } } func TestTime(t *testing.T) { // In an interable kind (i.e. a struct) type sTime struct { T time.Time } now := time.Now() got := sTime{T: now} expect := sTime{T: now.Add(1 * time.Second)} diff := deep.Equal(got, expect) if len(diff) != 1 { t.Error("expected 1 diff:", diff) } // Directly a := now b := now diff = deep.Equal(a, b) if len(diff) > 0 { t.Error("should be equal:", diff) } // https://github.com/go-test/deep/issues/15 type Time15 struct { time.Time } a15 := Time15{now} b15 := Time15{now} diff = deep.Equal(a15, b15) if len(diff) > 0 { t.Error("should be equal:", diff) } later := now.Add(1 * time.Second) b15 = Time15{later} diff = deep.Equal(a15, b15) if len(diff) != 1 { t.Errorf("got %d diffs, expected 1: %s", len(diff), diff) } // No diff in Equal should not affect diff of other fields (Foo) type Time17 struct { time.Time Foo int } a17 := Time17{Time: now, Foo: 1} b17 := Time17{Time: now, Foo: 2} diff = deep.Equal(a17, b17) if len(diff) != 1 { t.Errorf("got %d diffs, expected 1: %s", len(diff), diff) } } func TestTimeUnexported(t *testing.T) { // https://github.com/go-test/deep/issues/18 // Can't call Call() on exported Value func defaultCompareUnexportedFields := deep.CompareUnexportedFields deep.CompareUnexportedFields = true defer func() { deep.CompareUnexportedFields = defaultCompareUnexportedFields }() now := time.Now() type hiddenTime struct { t time.Time } htA := &hiddenTime{t: now} htB := &hiddenTime{t: now} diff := deep.Equal(htA, htB) if len(diff) > 0 { t.Error("should be equal:", diff) } // This doesn't call time.Time.Equal(), it compares the unexported fields // in time.Time, causing a diff like: // [t.wall: 13740788835924462040 != 13740788836998203864 t.ext: 1447549 != 1001447549] later := now.Add(1 * time.Second) htC := &hiddenTime{t: later} diff = deep.Equal(htA, htC) expected := 1 if _, ok := reflect.TypeOf(htA.t).FieldByName("ext"); ok { expected = 2 } if len(diff) != expected { t.Errorf("got %d diffs, expected %d: %s", len(diff), expected, diff) } } func TestInterface(t *testing.T) { a := map[string]interface{}{ "foo": map[string]string{ "bar": "a", }, } b := map[string]interface{}{ "foo": map[string]string{ "bar": "b", }, } diff := deep.Equal(a, b) if len(diff) == 0 { t.Fatalf("expected 1 diff, got zero") } if len(diff) != 1 { t.Errorf("expected 1 diff, got %d: %s", len(diff), diff) } } func TestInterface2(t *testing.T) { defer func() { if val := recover(); val != nil { t.Fatalf("panic: %v", val) } }() a := map[string]interface{}{ "bar": 1, } b := map[string]interface{}{ "bar": 1.23, } diff := deep.Equal(a, b) if len(diff) == 0 { t.Fatalf("expected 1 diff, got zero") } if len(diff) != 1 { t.Errorf("expected 1 diff, got %d: %s", len(diff), diff) } } func TestInterface3(t *testing.T) { type Value struct{ int } a := map[string]interface{}{ "foo": &Value{}, } b := map[string]interface{}{ "foo": 1.23, } diff := deep.Equal(a, b) if len(diff) == 0 { t.Fatalf("expected 1 diff, got zero") } if len(diff) != 1 { t.Errorf("expected 1 diff, got: %s", diff) } } func TestError(t *testing.T) { a := errors.New("it broke") b := errors.New("it broke") diff := deep.Equal(a, b) if len(diff) != 0 { t.Fatalf("expected zero diffs, got %d: %s", len(diff), diff) } b = errors.New("it fell apart") diff = deep.Equal(a, b) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "it broke != it fell apart" { t.Errorf("got '%s', expected 'it broke != it fell apart'", diff[0]) } // Both errors set type tWithError struct { Error error } t1 := tWithError{ Error: a, } t2 := tWithError{ Error: b, } diff = deep.Equal(t1, t2) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "Error: it broke != it fell apart" { t.Errorf("got '%s', expected 'Error: it broke != it fell apart'", diff[0]) } // Both errors nil t1 = tWithError{ Error: nil, } t2 = tWithError{ Error: nil, } diff = deep.Equal(t1, t2) if len(diff) != 0 { t.Log(diff) t.Fatalf("expected 0 diff, got %d: %s", len(diff), diff) } // One error is nil t1 = tWithError{ Error: errors.New("foo"), } t2 = tWithError{ Error: nil, } diff = deep.Equal(t1, t2) if len(diff) != 1 { t.Log(diff) t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "Error: *errors.errorString != " { t.Errorf("got '%s', expected 'Error: *errors.errorString != '", diff[0]) } } func TestErrorWithOtherFields(t *testing.T) { a := errors.New("it broke") b := errors.New("it broke") diff := deep.Equal(a, b) if len(diff) != 0 { t.Fatalf("expected zero diffs, got %d: %s", len(diff), diff) } b = errors.New("it fell apart") diff = deep.Equal(a, b) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "it broke != it fell apart" { t.Errorf("got '%s', expected 'it broke != it fell apart'", diff[0]) } // Both errors set type tWithError struct { Error error Other string } t1 := tWithError{ Error: a, Other: "ok", } t2 := tWithError{ Error: b, Other: "ok", } diff = deep.Equal(t1, t2) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "Error: it broke != it fell apart" { t.Errorf("got '%s', expected 'Error: it broke != it fell apart'", diff[0]) } // Both errors nil t1 = tWithError{ Error: nil, Other: "ok", } t2 = tWithError{ Error: nil, Other: "ok", } diff = deep.Equal(t1, t2) if len(diff) != 0 { t.Log(diff) t.Fatalf("expected 0 diff, got %d: %s", len(diff), diff) } // Different Other value t1 = tWithError{ Error: nil, Other: "ok", } t2 = tWithError{ Error: nil, Other: "nope", } diff = deep.Equal(t1, t2) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "Other: ok != nope" { t.Errorf("got '%s', expected 'Other: ok != nope'", diff[0]) } // Different Other value, same error t1 = tWithError{ Error: a, Other: "ok", } t2 = tWithError{ Error: a, Other: "nope", } diff = deep.Equal(t1, t2) if len(diff) != 1 { t.Fatalf("expected 1 diff, got %d: %s", len(diff), diff) } if diff[0] != "Other: ok != nope" { t.Errorf("got '%s', expected 'Other: ok != nope'", diff[0]) } } type primKindError string func (e primKindError) Error() string { return string(e) } func TestErrorPrimitiveKind(t *testing.T) { // The primKindError type above is valid and used by Go, e.g. // url.EscapeError and url.InvalidHostError. Before fixing this bug // (https://github.com/go-test/deep/issues/31), we presumed a and b // were ptr or interface (and not nil), so a.Elem() worked. But when // a/b are primitive kinds, Elem() causes a panic. var err1 primKindError = "abc" var err2 primKindError = "abc" diff := deep.Equal(err1, err2) if len(diff) != 0 { t.Fatalf("expected zero diffs, got %d: %s", len(diff), diff) } } func TestNil(t *testing.T) { type student struct { name string age int } mark := student{"mark", 10} var someNilThing interface{} = nil diff := deep.Equal(someNilThing, mark) if diff == nil { t.Error("Nil value to comparison should not be equal") } diff = deep.Equal(mark, someNilThing) if diff == nil { t.Error("Nil value to comparison should not be equal") } diff = deep.Equal(someNilThing, someNilThing) if diff != nil { t.Error("Nil value to comparison should not be equal") } } golang-github-go-test-deep-1.0.3/go.mod000066400000000000000000000000371353171161500176460ustar00rootroot00000000000000module github.com/go-test/deep