From c49bfce0ac9115b09320b47c3b9534cc5afd4579 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 17 Jun 2020 14:41:50 -0700 Subject: [PATCH] Update test case names (#218) Provide a unique name for every test case. Provide a reason for every test case. The purpose of a unique name is so that insertion/removal of a case does not cause all subsequent names to suddenly shift, causing a larger number of differences in testdata/diffs. --- cmp/compare_test.go | 638 +++++++++++++++++++++++++++++--------------- cmp/testdata/diffs | 276 +++++++++---------- 2 files changed, 557 insertions(+), 357 deletions(-) diff --git a/cmp/compare_test.go b/cmp/compare_test.go index be8a2f6..c94f6c0 100644 --- a/cmp/compare_test.go +++ b/cmp/compare_test.go @@ -155,9 +155,12 @@ func TestDiff(t *testing.T) { gotDiff = cmp.Diff(tt.x, tt.y, tt.opts...) }() - // TODO: Require every test case to provide a reason. - // TODO: Forbid any test cases with the same name. - if tt.wantPanic == "" { + switch { + case strings.Contains(t.Name(), "#"): + panic("unique test name must be provided") + case tt.reason == "": + panic("reason must be provided") + case tt.wantPanic == "": if gotPanic != "" { t.Fatalf("unexpected panic message: %s\nreason: %v", gotPanic, tt.reason) } @@ -175,7 +178,7 @@ func TestDiff(t *testing.T) { if gotEqual != tt.wantEqual { t.Fatalf("Equal = %v, want %v\nreason: %v", gotEqual, tt.wantEqual, tt.reason) } - } else { + default: if !strings.Contains(gotPanic, tt.wantPanic) { t.Fatalf("panic message:\ngot: %s\nwant: %s\nreason: %v", gotPanic, tt.wantPanic, tt.reason) } @@ -234,35 +237,40 @@ func comparerTests() []test { } return []test{{ - label: label, + label: label + "/Nil", x: nil, y: nil, wantEqual: true, + reason: "nils are equal", }, { - label: label, + label: label + "/Integer", x: 1, y: 1, wantEqual: true, + reason: "identical integers are equal", }, { - label: label, + label: label + "/UnfilteredIgnore", x: 1, y: 1, opts: []cmp.Option{cmp.Ignore()}, wantPanic: "cannot use an unfiltered option", + reason: "unfiltered options are functionally useless", }, { - label: label, + label: label + "/UnfilteredCompare", x: 1, y: 1, opts: []cmp.Option{cmp.Comparer(func(_, _ interface{}) bool { return true })}, wantPanic: "cannot use an unfiltered option", + reason: "unfiltered options are functionally useless", }, { - label: label, + label: label + "/UnfilteredTransform", x: 1, y: 1, opts: []cmp.Option{cmp.Transformer("λ", func(x interface{}) interface{} { return x })}, wantPanic: "cannot use an unfiltered option", + reason: "unfiltered options are functionally useless", }, { - label: label, + label: label + "/AmbiguousOptions", x: 1, y: 1, opts: []cmp.Option{ @@ -270,8 +278,9 @@ func comparerTests() []test { cmp.Transformer("λ", func(x int) float64 { return float64(x) }), }, wantPanic: "ambiguous set of applicable options", + reason: "both options apply on int, leading to ambiguity", }, { - label: label, + label: label + "/IgnorePrecedence", x: 1, y: 1, opts: []cmp.Option{ @@ -282,84 +291,98 @@ func comparerTests() []test { cmp.Transformer("λ", func(x int) float64 { return float64(x) }), }, wantEqual: true, + reason: "ignore takes precedence over other options", }, { - label: label, + label: label + "/UnknownOption", opts: []cmp.Option{struct{ cmp.Option }{}}, wantPanic: "unknown option", + reason: "use of unknown option should panic", }, { - label: label, + label: label + "/StructEqual", x: struct{ A, B, C int }{1, 2, 3}, y: struct{ A, B, C int }{1, 2, 3}, wantEqual: true, + reason: "struct comparison with all equal fields", }, { - label: label, + label: label + "/StructInequal", x: struct{ A, B, C int }{1, 2, 3}, y: struct{ A, B, C int }{1, 2, 4}, wantEqual: false, + reason: "struct comparison with inequal C field", }, { - label: label, + label: label + "/StructUnexported", x: struct{ a, b, c int }{1, 2, 3}, y: struct{ a, b, c int }{1, 2, 4}, wantPanic: "cannot handle unexported field", + reason: "unexported fields result in a panic by default", }, { - label: label, + label: label + "/PointerStructEqual", x: &struct{ A *int }{newInt(4)}, y: &struct{ A *int }{newInt(4)}, wantEqual: true, + reason: "comparison of pointer to struct with equal A field", }, { - label: label, + label: label + "/PointerStructInequal", x: &struct{ A *int }{newInt(4)}, y: &struct{ A *int }{newInt(5)}, wantEqual: false, + reason: "comparison of pointer to struct with inequal A field", }, { - label: label, + label: label + "/PointerStructTrueComparer", x: &struct{ A *int }{newInt(4)}, y: &struct{ A *int }{newInt(5)}, opts: []cmp.Option{ cmp.Comparer(func(x, y int) bool { return true }), }, wantEqual: true, + reason: "comparison of pointer to struct with inequal A field, but treated as equal with always equal comparer", }, { - label: label, + label: label + "/PointerStructNonNilComparer", x: &struct{ A *int }{newInt(4)}, y: &struct{ A *int }{newInt(5)}, opts: []cmp.Option{ cmp.Comparer(func(x, y *int) bool { return x != nil && y != nil }), }, wantEqual: true, + reason: "comparison of pointer to struct with inequal A field, but treated as equal with comparer checking pointers for nilness", }, { - label: label, + label: label + "/StructNestedPointerEqual", x: &struct{ R *bytes.Buffer }{}, y: &struct{ R *bytes.Buffer }{}, wantEqual: true, + reason: "equal since both pointers in R field are nil", }, { - label: label, + label: label + "/StructNestedPointerInequal", x: &struct{ R *bytes.Buffer }{new(bytes.Buffer)}, y: &struct{ R *bytes.Buffer }{}, wantEqual: false, + reason: "inequal since R field is inequal", }, { - label: label, + label: label + "/StructNestedPointerTrueComparer", x: &struct{ R *bytes.Buffer }{new(bytes.Buffer)}, y: &struct{ R *bytes.Buffer }{}, opts: []cmp.Option{ cmp.Comparer(func(x, y io.Reader) bool { return true }), }, wantEqual: true, + reason: "equal despite inequal R field values since the comparer always reports true", }, { - label: label, + label: label + "/StructNestedValueUnexportedPanic1", x: &struct{ R bytes.Buffer }{}, y: &struct{ R bytes.Buffer }{}, wantPanic: "cannot handle unexported field", + reason: "bytes.Buffer contains unexported fields", }, { - label: label, + label: label + "/StructNestedValueUnexportedPanic2", x: &struct{ R bytes.Buffer }{}, y: &struct{ R bytes.Buffer }{}, opts: []cmp.Option{ cmp.Comparer(func(x, y io.Reader) bool { return true }), }, wantPanic: "cannot handle unexported field", + reason: "bytes.Buffer value does not implement io.Reader", }, { - label: label, + label: label + "/StructNestedValueEqual", x: &struct{ R bytes.Buffer }{}, y: &struct{ R bytes.Buffer }{}, opts: []cmp.Option{ @@ -367,13 +390,15 @@ func comparerTests() []test { cmp.Comparer(func(x, y io.Reader) bool { return true }), }, wantEqual: true, + reason: "bytes.Buffer pointer due to shallow copy does implement io.Reader", }, { - label: label, + label: label + "/RegexpUnexportedPanic", x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, wantPanic: "cannot handle unexported field", + reason: "regexp.Regexp contains unexported fields", }, { - label: label, + label: label + "/RegexpEqual", x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, opts: []cmp.Option{cmp.Comparer(func(x, y *regexp.Regexp) bool { @@ -383,8 +408,9 @@ func comparerTests() []test { return x.String() == y.String() })}, wantEqual: true, + reason: "comparer for *regexp.Regexp applied with equal regexp strings", }, { - label: label, + label: label + "/RegexpInequal", x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*d*")}, opts: []cmp.Option{cmp.Comparer(func(x, y *regexp.Regexp) bool { @@ -394,8 +420,9 @@ func comparerTests() []test { return x.String() == y.String() })}, wantEqual: false, + reason: "comparer for *regexp.Regexp applied with inequal regexp strings", }, { - label: label, + label: label + "/TriplePointerEqual", x: func() ***int { a := 0 b := &a @@ -409,8 +436,9 @@ func comparerTests() []test { return &c }(), wantEqual: true, + reason: "three layers of pointers to the same value", }, { - label: label, + label: label + "/TriplePointerInequal", x: func() ***int { a := 0 b := &a @@ -424,40 +452,47 @@ func comparerTests() []test { return &c }(), wantEqual: false, + reason: "three layers of pointers to different values", }, { - label: label, + label: label + "/SliceWithDifferingCapacity", x: []int{1, 2, 3, 4, 5}[:3], y: []int{1, 2, 3}, wantEqual: true, + reason: "elements past the slice length are not compared", }, { - label: label, + label: label + "/StringerEqual", x: struct{ fmt.Stringer }{bytes.NewBufferString("hello")}, y: struct{ fmt.Stringer }{regexp.MustCompile("hello")}, opts: []cmp.Option{cmp.Comparer(func(x, y fmt.Stringer) bool { return x.String() == y.String() })}, wantEqual: true, + reason: "comparer for fmt.Stringer used to compare differing types with same string", }, { - label: label, + label: label + "/StringerInequal", x: struct{ fmt.Stringer }{bytes.NewBufferString("hello")}, y: struct{ fmt.Stringer }{regexp.MustCompile("hello2")}, opts: []cmp.Option{cmp.Comparer(func(x, y fmt.Stringer) bool { return x.String() == y.String() })}, wantEqual: false, + reason: "comparer for fmt.Stringer used to compare differing types with different strings", }, { - label: label, + label: label + "/DifferingHash", x: md5.Sum([]byte{'a'}), y: md5.Sum([]byte{'b'}), wantEqual: false, + reason: "hash differs", }, { - label: label, + label: label + "/NilStringer", x: new(fmt.Stringer), y: nil, wantEqual: false, + reason: "by default differing types are always inequal", }, { - label: label, + label: label + "/TarHeaders", x: makeTarHeaders('0'), y: makeTarHeaders('\x00'), wantEqual: false, + reason: "type flag differs between the headers", }, { - label: label, + label: label + "/NonDeterministicComparer", x: make([]int, 1000), y: make([]int, 1000), opts: []cmp.Option{ @@ -466,8 +501,9 @@ func comparerTests() []test { }), }, wantPanic: "non-deterministic or non-symmetric function detected", + reason: "non-deterministic comparer", }, { - label: label, + label: label + "/NonDeterministicFilter", x: make([]int, 1000), y: make([]int, 1000), opts: []cmp.Option{ @@ -476,8 +512,9 @@ func comparerTests() []test { }, cmp.Ignore()), }, wantPanic: "non-deterministic or non-symmetric function detected", + reason: "non-deterministic filter", }, { - label: label, + label: label + "/AssymetricComparer", x: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, y: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, opts: []cmp.Option{ @@ -486,8 +523,9 @@ func comparerTests() []test { }), }, wantPanic: "non-deterministic or non-symmetric function detected", + reason: "asymmetric comparer", }, { - label: label, + label: label + "/NonDeterministicTransformer", x: make([]string, 1000), y: make([]string, 1000), opts: []cmp.Option{ @@ -496,10 +534,9 @@ func comparerTests() []test { }), }, wantPanic: "non-deterministic function detected", + reason: "non-deterministic transformer", }, { - // Make sure the dynamic checks don't raise a false positive for - // non-reflexive comparisons. - label: label, + label: label + "/IrreflexiveComparison", x: make([]int, 10), y: make([]int, 10), opts: []cmp.Option{ @@ -508,19 +545,20 @@ func comparerTests() []test { }), }, wantEqual: false, + reason: "dynamic checks should not panic for non-reflexive comparisons", }, { - // Ensure reasonable Stringer formatting of map keys. - label: label, + label: label + "/StringerMapKey", x: map[*pb.Stringer]*pb.Stringer{{"hello"}: {"world"}}, y: map[*pb.Stringer]*pb.Stringer(nil), wantEqual: false, + reason: "stringer should be used to format the map key", }, { - // Ensure Stringer avoids double-quote escaping if possible. - label: label, + label: label + "/StringerBacktick", x: []*pb.Stringer{{`multi\nline\nline\nline`}}, wantEqual: false, + reason: "stringer should use backtick quoting if more readable", }, { - label: label, + label: label + "/AvoidPanicAssignableConverter", x: struct{ I Iface2 }{}, y: struct{ I Iface2 }{}, opts: []cmp.Option{ @@ -529,8 +567,9 @@ func comparerTests() []test { }), }, wantEqual: true, + reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", }, { - label: label, + label: label + "/AvoidPanicAssignableTransformer", x: struct{ I Iface2 }{}, y: struct{ I Iface2 }{}, opts: []cmp.Option{ @@ -539,8 +578,9 @@ func comparerTests() []test { }), }, wantEqual: true, + reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", }, { - label: label, + label: label + "/AvoidPanicAssignableFilter", x: struct{ I Iface2 }{}, y: struct{ I Iface2 }{}, opts: []cmp.Option{ @@ -549,13 +589,15 @@ func comparerTests() []test { }, cmp.Ignore()), }, wantEqual: true, + reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", }, { - label: label, + label: label + "/DynamicMap", x: []interface{}{map[string]interface{}{"avg": 0.278, "hr": 65, "name": "Mark McGwire"}, map[string]interface{}{"avg": 0.288, "hr": 63, "name": "Sammy Sosa"}}, y: []interface{}{map[string]interface{}{"avg": 0.278, "hr": 65.0, "name": "Mark McGwire"}, map[string]interface{}{"avg": 0.288, "hr": 63.0, "name": "Sammy Sosa"}}, wantEqual: false, + reason: "dynamic map with differing types (but semantically equivalent values) should be inequal", }, { - label: label, + label: label + "/MapKeyPointer", x: map[*int]string{ new(int): "hello", }, @@ -563,8 +605,9 @@ func comparerTests() []test { new(int): "world", }, wantEqual: false, + reason: "map keys should use shallow (rather than deep) pointer comparison", }, { - label: label, + label: label + "/IgnoreSliceElements", x: [2][]int{ {0, 0, 0, 1, 2, 3, 0, 0, 4, 5, 6, 7, 8, 0, 9, 0, 0}, {0, 1, 0, 0, 0, 20}, @@ -588,7 +631,7 @@ func comparerTests() []test { wantEqual: false, reason: "all zero slice elements are ignored (even if missing)", }, { - label: label, + label: label + "/IgnoreMapEntries", x: [2]map[string]int{ {"ignore1": 0, "ignore2": 0, "keep1": 1, "keep2": 2, "KEEP3": 3, "IGNORE3": 0}, {"keep1": 1, "ignore1": 0}, @@ -612,19 +655,19 @@ func comparerTests() []test { wantEqual: false, reason: "all zero map entries are ignored (even if missing)", }, { - label: label, + label: label + "/PanicUnexportedNamed", x: namedWithUnexported{}, y: namedWithUnexported{}, wantPanic: strconv.Quote(reflect.TypeOf(namedWithUnexported{}).PkgPath()) + ".namedWithUnexported", reason: "panic on named struct type with unexported field", }, { - label: label, + label: label + "/PanicUnexportedUnnamed", x: struct{ a int }{}, y: struct{ a int }{}, wantPanic: strconv.Quote(reflect.TypeOf(namedWithUnexported{}).PkgPath()) + ".(struct { a int })", reason: "panic on unnamed struct type with unexported field", }, { - label: label, + label: label + "/UnaddressableStruct", x: struct{ s fmt.Stringer }{new(bytes.Buffer)}, y: struct{ s fmt.Stringer }{nil}, opts: []cmp.Option{ @@ -676,7 +719,7 @@ func transformerTests() []test { } return []test{{ - label: label, + label: label + "/Uints", x: uint8(0), y: uint8(1), opts: []cmp.Option{ @@ -685,8 +728,9 @@ func transformerTests() []test { cmp.Transformer("λ", func(in uint32) uint64 { return uint64(in) }), }, wantEqual: false, + reason: "transform uint8 -> uint16 -> uint32 -> uint64", }, { - label: label, + label: label + "/Ambiguous", x: 0, y: 1, opts: []cmp.Option{ @@ -694,8 +738,9 @@ func transformerTests() []test { cmp.Transformer("λ", func(in int) int { return in }), }, wantPanic: "ambiguous set of applicable options", + reason: "both transformers apply on int", }, { - label: label, + label: label + "/Filtered", x: []int{0, -5, 0, -1}, y: []int{1, 3, 0, -5}, opts: []cmp.Option{ @@ -709,8 +754,9 @@ func transformerTests() []test { ), }, wantEqual: false, + reason: "disjoint transformers filtered based on the values", }, { - label: label, + label: label + "/DisjointOutput", x: 0, y: 1, opts: []cmp.Option{ @@ -722,8 +768,9 @@ func transformerTests() []test { }), }, wantEqual: false, + reason: "output type differs based on input value", }, { - label: label, + label: label + "/JSON", x: `{ "firstName": "John", "lastName": "Smith", @@ -761,8 +808,9 @@ func transformerTests() []test { }), }, wantEqual: false, + reason: "transformer used to parse JSON input", }, { - label: label, + label: label + "/AcyclicString", x: StringBytes{String: "some\nmulti\nLine\nstring", Bytes: []byte("some\nmulti\nline\nbytes")}, y: StringBytes{String: "some\nmulti\nline\nstring", Bytes: []byte("some\nmulti\nline\nBytes")}, opts: []cmp.Option{ @@ -770,22 +818,27 @@ func transformerTests() []test { transformOnce("SplitBytes", func(b []byte) [][]byte { return bytes.Split(b, []byte("\n")) }), }, wantEqual: false, + reason: "string -> []string and []byte -> [][]byte transformer only applied once", }, { - x: "a\nb\nc\n", - y: "a\nb\nc\n", + label: label + "/CyclicString", + x: "a\nb\nc\n", + y: "a\nb\nc\n", opts: []cmp.Option{ cmp.Transformer("SplitLines", func(s string) []string { return strings.Split(s, "\n") }), }, wantPanic: "recursive set of Transformers detected", + reason: "cyclic transformation from string -> []string -> string", }, { - x: complex64(0), - y: complex64(0), + label: label + "/CyclicComplex", + x: complex64(0), + y: complex64(0), opts: []cmp.Option{ cmp.Transformer("T1", func(x complex64) complex128 { return complex128(x) }), cmp.Transformer("T2", func(x complex128) [2]float64 { return [2]float64{real(x), imag(x)} }), cmp.Transformer("T3", func(x float64) complex64 { return complex64(complex(x, 0)) }), }, wantPanic: "recursive set of Transformers detected", + reason: "cyclic transformation from complex64 -> complex128 -> [2]float64 -> complex64", }} } @@ -915,18 +968,18 @@ func reporterTests() []test { wantEqual: false, reason: "reporter should call String as there is no ambiguity between the two map keys", }, { - label: "/InvalidUTF8", + label: label + "/InvalidUTF8", x: MyString("\xed\xa0\x80"), wantEqual: false, reason: "invalid UTF-8 should format as quoted string", }, { - label: label, + label: label + "/UnbatchedSlice", x: MyComposite{IntsA: []int8{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, y: MyComposite{IntsA: []int8{10, 11, 21, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, wantEqual: false, reason: "unbatched diffing desired since few elements differ", }, { - label: label, + label: label + "/BatchedSlice", x: MyComposite{IntsA: []int8{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, y: MyComposite{IntsA: []int8{12, 29, 13, 27, 22, 23, 17, 18, 19, 20, 21, 10, 26, 16, 25, 28, 11, 15, 24, 14}}, wantEqual: false, @@ -946,7 +999,7 @@ func reporterTests() []test { wantEqual: false, reason: "batched output desired for a single slice of primitives unique to one of the inputs", }, { - label: label, + label: label + "/BatchedNamedAndUnnamed", x: MyComposite{ BytesA: []byte{1, 2, 3}, BytesB: []MyByte{4, 5, 6}, @@ -978,19 +1031,19 @@ func reporterTests() []test { wantEqual: false, reason: "batched diffing available for both named and unnamed slices", }, { - label: label, + label: label + "/BinaryHexdump", x: MyComposite{BytesA: []byte("\xf3\x0f\x8a\xa4\xd3\x12R\t$\xbeX\x95A\xfd$fX\x8byT\xac\r\xd8qwp\x20j\\s\u007f\x8c\x17U\xc04\xcen\xf7\xaaG\xee2\x9d\xc5\xca\x1eX\xaf\x8f'\xf3\x02J\x90\xedi.p2\xb4\xab0 \xb6\xbd\\b4\x17\xb0\x00\xbbO~'G\x06\xf4.f\xfdc\xd7\x04ݷ0\xb7\xd1U~{\xf6\xb3~\x1dWi \x9e\xbc\xdf\xe1M\xa9\xef\xa2\xd2\xed\xb4Gx\xc9\xc9'\xa4\xc6\xce\xecDp]")}, y: MyComposite{BytesA: []byte("\xf3\x0f\x8a\xa4\xd3\x12R\t$\xbeT\xac\r\xd8qwp\x20j\\s\u007f\x8c\x17U\xc04\xcen\xf7\xaaG\xee2\x9d\xc5\xca\x1eX\xaf\x8f'\xf3\x02J\x90\xedi.p2\xb4\xab0 \xb6\xbd\\b4\x17\xb0\x00\xbbO~'G\x06\xf4.f\xfdc\xd7\x04ݷ0\xb7\xd1u-[]]\xf6\xb3haha~\x1dWI \x9e\xbc\xdf\xe1M\xa9\xef\xa2\xd2\xed\xb4Gx\xc9\xc9'\xa4\xc6\xce\xecDp]")}, wantEqual: false, reason: "binary diff in hexdump form since data is binary data", }, { - label: label, + label: label + "/StringHexdump", x: MyComposite{StringB: MyString("readme.txt\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000600\x000000000\x000000000\x0000000000046\x0000000000000\x00011173\x00 0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ustar\x0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000000\x000000000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")}, y: MyComposite{StringB: MyString("gopher.txt\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000600\x000000000\x000000000\x0000000000043\x0000000000000\x00011217\x00 0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ustar\x0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000000\x000000000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")}, wantEqual: false, reason: "binary diff desired since string looks like binary data", }, { - label: label, + label: label + "/BinaryString", x: MyComposite{BytesA: []byte(`{"firstName":"John","lastName":"Smith","isAlive":true,"age":27,"address":{"streetAddress":"314 54th Avenue","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`)}, y: MyComposite{BytesA: []byte(`{"firstName":"John","lastName":"Smith","isAlive":true,"age":27,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`)}, wantEqual: false, @@ -1096,7 +1149,7 @@ func reporterTests() []test { wantEqual: false, reason: "total slice difference output is truncated due to excessive number of differences", }, { - label: label, + label: label + "/MultilineString", x: MyComposite{ StringA: strings.TrimPrefix(` Package cmp determines equality of values. @@ -1147,7 +1200,7 @@ using the AllowUnexported option.`, "\n"), wantEqual: false, reason: "batched per-line diff desired since string looks like multi-line textual data", }, { - label: label, + label: label + "/Slices", x: MyComposite{ BytesA: []byte{1, 2, 3}, BytesB: []MyByte{4, 5, 6}, @@ -1166,7 +1219,7 @@ using the AllowUnexported option.`, "\n"), wantEqual: false, reason: "batched diffing for non-nil slices and nil slices", }, { - label: label, + label: label + "/EmptySlices", x: MyComposite{ BytesA: []byte{}, BytesB: []MyByte{}, @@ -1188,7 +1241,7 @@ using the AllowUnexported option.`, "\n"), } func embeddedTests() []test { - const label = "EmbeddedStruct/" + const label = "EmbeddedStruct" privateStruct := *new(ts.ParentStructA).PrivateStruct() @@ -1289,52 +1342,58 @@ func embeddedTests() []test { } return []test{{ - label: label + "ParentStructA", + label: label + "/ParentStructA/PanicUnexported1", x: ts.ParentStructA{}, y: ts.ParentStructA{}, wantPanic: "cannot handle unexported field", + reason: "ParentStructA has an unexported field", }, { - label: label + "ParentStructA", + label: label + "/ParentStructA/Ignored", x: ts.ParentStructA{}, y: ts.ParentStructA{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructA{}), }, wantEqual: true, + reason: "the only field (which is unexported) of ParentStructA is ignored", }, { - label: label + "ParentStructA", + label: label + "/ParentStructA/PanicUnexported2", x: createStructA(0), y: createStructA(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructA{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructA", + label: label + "/ParentStructA/Equal", x: createStructA(0), y: createStructA(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructA{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructA and privateStruct are allowed", }, { - label: label + "ParentStructA", + label: label + "/ParentStructA/Inequal", x: createStructA(0), y: createStructA(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructA{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructB", + label: label + "/ParentStructB/PanicUnexported1", x: ts.ParentStructB{}, y: ts.ParentStructB{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructB{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct has an unexported field", }, { - label: label + "ParentStructB", + label: label + "/ParentStructB/Ignored", x: ts.ParentStructB{}, y: ts.ParentStructB{}, opts: []cmp.Option{ @@ -1342,77 +1401,87 @@ func embeddedTests() []test { cmpopts.IgnoreUnexported(ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of both ParentStructB and PublicStruct are ignored", }, { - label: label + "ParentStructB", + label: label + "/ParentStructB/PanicUnexported2", x: createStructB(0), y: createStructB(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructB{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct also has unexported fields", }, { - label: label + "ParentStructB", + label: label + "/ParentStructB/Equal", x: createStructB(0), y: createStructB(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructB{}, ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of both ParentStructB and PublicStruct are allowed", }, { - label: label + "ParentStructB", + label: label + "/ParentStructB/Inequal", x: createStructB(0), y: createStructB(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructB{}, ts.PublicStruct{}), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructC", + label: label + "/ParentStructC/PanicUnexported1", x: ts.ParentStructC{}, y: ts.ParentStructC{}, wantPanic: "cannot handle unexported field", + reason: "ParentStructC has unexported fields", }, { - label: label + "ParentStructC", + label: label + "/ParentStructC/Ignored", x: ts.ParentStructC{}, y: ts.ParentStructC{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructC{}), }, wantEqual: true, + reason: "unexported fields of ParentStructC are ignored", }, { - label: label + "ParentStructC", + label: label + "/ParentStructC/PanicUnexported2", x: createStructC(0), y: createStructC(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructC{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructC", + label: label + "/ParentStructC/Equal", x: createStructC(0), y: createStructC(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructC{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructC and privateStruct are allowed", }, { - label: label + "ParentStructC", + label: label + "/ParentStructC/Inequal", x: createStructC(0), y: createStructC(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructC{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructD", + label: label + "/ParentStructD/PanicUnexported1", x: ts.ParentStructD{}, y: ts.ParentStructD{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructD{}), }, wantPanic: "cannot handle unexported field", + reason: "ParentStructD has unexported fields", }, { - label: label + "ParentStructD", + label: label + "/ParentStructD/Ignored", x: ts.ParentStructD{}, y: ts.ParentStructD{}, opts: []cmp.Option{ @@ -1420,40 +1489,45 @@ func embeddedTests() []test { cmpopts.IgnoreUnexported(ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of ParentStructD and PublicStruct are ignored", }, { - label: label + "ParentStructD", + label: label + "/ParentStructD/PanicUnexported2", x: createStructD(0), y: createStructD(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructD{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct also has unexported fields", }, { - label: label + "ParentStructD", + label: label + "/ParentStructD/Equal", x: createStructD(0), y: createStructD(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructD{}, ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of both ParentStructD and PublicStruct are allowed", }, { - label: label + "ParentStructD", + label: label + "/ParentStructD/Inequal", x: createStructD(0), y: createStructD(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructD{}, ts.PublicStruct{}), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/PanicUnexported1", x: ts.ParentStructE{}, y: ts.ParentStructE{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructE{}), }, wantPanic: "cannot handle unexported field", + reason: "ParentStructE has unexported fields", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/Ignored", x: ts.ParentStructE{}, y: ts.ParentStructE{}, opts: []cmp.Option{ @@ -1461,48 +1535,54 @@ func embeddedTests() []test { cmpopts.IgnoreUnexported(ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of ParentStructE and PublicStruct are ignored", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/PanicUnexported2", x: createStructE(0), y: createStructE(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructE{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct and privateStruct also has unexported fields", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/PanicUnexported3", x: createStructE(0), y: createStructE(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/Equal", x: createStructE(0), y: createStructE(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructE, PublicStruct, and privateStruct are allowed", }, { - label: label + "ParentStructE", + label: label + "/ParentStructE/Inequal", x: createStructE(0), y: createStructE(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/PanicUnexported1", x: ts.ParentStructF{}, y: ts.ParentStructF{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructF{}), }, wantPanic: "cannot handle unexported field", + reason: "ParentStructF has unexported fields", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/Ignored", x: ts.ParentStructF{}, y: ts.ParentStructF{}, opts: []cmp.Option{ @@ -1510,227 +1590,256 @@ func embeddedTests() []test { cmpopts.IgnoreUnexported(ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of ParentStructF and PublicStruct are ignored", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/PanicUnexported2", x: createStructF(0), y: createStructF(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructF{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct and privateStruct also has unexported fields", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/PanicUnexported3", x: createStructF(0), y: createStructF(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/Equal", x: createStructF(0), y: createStructF(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructF, PublicStruct, and privateStruct are allowed", }, { - label: label + "ParentStructF", + label: label + "/ParentStructF/Inequal", x: createStructF(0), y: createStructF(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructG", + label: label + "/ParentStructG/PanicUnexported1", x: ts.ParentStructG{}, y: ts.ParentStructG{}, wantPanic: wantPanicNotGo110("cannot handle unexported field"), wantEqual: !flags.AtLeastGo110, + reason: "ParentStructG has unexported fields", }, { - label: label + "ParentStructG", + label: label + "/ParentStructG/Ignored", x: ts.ParentStructG{}, y: ts.ParentStructG{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructG{}), }, wantEqual: true, + reason: "unexported fields of ParentStructG are ignored", }, { - label: label + "ParentStructG", + label: label + "/ParentStructG/PanicUnexported2", x: createStructG(0), y: createStructG(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructG{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructG", + label: label + "/ParentStructG/Equal", x: createStructG(0), y: createStructG(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructG{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructG and privateStruct are allowed", }, { - label: label + "ParentStructG", + label: label + "/ParentStructG/Inequal", x: createStructG(0), y: createStructG(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructG{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/EqualNil", x: ts.ParentStructH{}, y: ts.ParentStructH{}, wantEqual: true, + reason: "PublicStruct is not compared because the pointer is nil", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/PanicUnexported1", x: createStructH(0), y: createStructH(0), wantPanic: "cannot handle unexported field", + reason: "PublicStruct has unexported fields", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/Ignored", x: ts.ParentStructH{}, y: ts.ParentStructH{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructH{}), }, wantEqual: true, + reason: "unexported fields of ParentStructH are ignored (it has none)", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/PanicUnexported2", x: createStructH(0), y: createStructH(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructH{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct also has unexported fields", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/Equal", x: createStructH(0), y: createStructH(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructH{}, ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of both ParentStructH and PublicStruct are allowed", }, { - label: label + "ParentStructH", + label: label + "/ParentStructH/Inequal", x: createStructH(0), y: createStructH(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructH{}, ts.PublicStruct{}), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/PanicUnexported1", x: ts.ParentStructI{}, y: ts.ParentStructI{}, wantPanic: wantPanicNotGo110("cannot handle unexported field"), wantEqual: !flags.AtLeastGo110, + reason: "ParentStructI has unexported fields", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/Ignored1", x: ts.ParentStructI{}, y: ts.ParentStructI{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructI{}), }, wantEqual: true, + reason: "unexported fields of ParentStructI are ignored", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/PanicUnexported2", x: createStructI(0), y: createStructI(0), opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructI{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct and privateStruct also has unexported fields", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/Ignored2", x: createStructI(0), y: createStructI(0), opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructI{}, ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of ParentStructI and PublicStruct are ignored", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/PanicUnexported3", x: createStructI(0), y: createStructI(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructI{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct and privateStruct also has unexported fields", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/Equal", x: createStructI(0), y: createStructI(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructI{}, ts.PublicStruct{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructI, PublicStruct, and privateStruct are allowed", }, { - label: label + "ParentStructI", + label: label + "/ParentStructI/Inequal", x: createStructI(0), y: createStructI(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructI{}, ts.PublicStruct{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/PanicUnexported1", x: ts.ParentStructJ{}, y: ts.ParentStructJ{}, wantPanic: "cannot handle unexported field", + reason: "ParentStructJ has unexported fields", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/PanicUnexported2", x: ts.ParentStructJ{}, y: ts.ParentStructJ{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructJ{}), }, wantPanic: "cannot handle unexported field", + reason: "PublicStruct and privateStruct also has unexported fields", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/Ignored", x: ts.ParentStructJ{}, y: ts.ParentStructJ{}, opts: []cmp.Option{ cmpopts.IgnoreUnexported(ts.ParentStructJ{}, ts.PublicStruct{}), }, wantEqual: true, + reason: "unexported fields of ParentStructJ and PublicStruct are ignored", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/PanicUnexported3", x: createStructJ(0), y: createStructJ(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}), }, wantPanic: "cannot handle unexported field", + reason: "privateStruct also has unexported fields", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/Equal", x: createStructJ(0), y: createStructJ(0), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}, privateStruct), }, wantEqual: true, + reason: "unexported fields of both ParentStructJ, PublicStruct, and privateStruct are allowed", }, { - label: label + "ParentStructJ", + label: label + "/ParentStructJ/Inequal", x: createStructJ(0), y: createStructJ(1), opts: []cmp.Option{ cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}, privateStruct), }, wantEqual: false, + reason: "the two values differ on some fields", }} } func methodTests() []test { - const label = "EqualMethod/" + const label = "EqualMethod" // A common mistake that the Equal method is on a pointer receiver, // but only a non-pointer value is present in the struct. // A transform can be used to forcibly reference the value. - derefTransform := cmp.FilterPath(func(p cmp.Path) bool { + addrTransform := cmp.FilterPath(func(p cmp.Path) bool { if len(p) == 0 { return false } @@ -1744,7 +1853,7 @@ func methodTests() []test { tf.In(0).AssignableTo(tf.In(1)) && tf.Out(0) == reflect.TypeOf(true) } return false - }, cmp.Transformer("Ref", func(x interface{}) interface{} { + }, cmp.Transformer("Addr", func(x interface{}) interface{} { v := reflect.ValueOf(x) vp := reflect.New(v.Type()) vp.Elem().Set(v) @@ -1755,284 +1864,338 @@ func methodTests() []test { // returns true, while the underlying data are fundamentally different. // Since the method should be called, these are expected to be equal. return []test{{ - label: label + "StructA", + label: label + "/StructA/ValueEqual", x: ts.StructA{X: "NotEqual"}, y: ts.StructA{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructA value called", }, { - label: label + "StructA", + label: label + "/StructA/PointerEqual", x: &ts.StructA{X: "NotEqual"}, y: &ts.StructA{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructA pointer called", }, { - label: label + "StructB", + label: label + "/StructB/ValueInequal", x: ts.StructB{X: "NotEqual"}, y: ts.StructB{X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructB value not called", }, { - label: label + "StructB", + label: label + "/StructB/ValueAddrEqual", x: ts.StructB{X: "NotEqual"}, y: ts.StructB{X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructB pointer called due to shallow copy transform", }, { - label: label + "StructB", + label: label + "/StructB/PointerEqual", x: &ts.StructB{X: "NotEqual"}, y: &ts.StructB{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructB pointer called", }, { - label: label + "StructC", + label: label + "/StructC/ValueEqual", x: ts.StructC{X: "NotEqual"}, y: ts.StructC{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructC value called", }, { - label: label + "StructC", + label: label + "/StructC/PointerEqual", x: &ts.StructC{X: "NotEqual"}, y: &ts.StructC{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructC pointer called", }, { - label: label + "StructD", + label: label + "/StructD/ValueInequal", x: ts.StructD{X: "NotEqual"}, y: ts.StructD{X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructD value not called", }, { - label: label + "StructD", + label: label + "/StructD/ValueAddrEqual", x: ts.StructD{X: "NotEqual"}, y: ts.StructD{X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructD pointer called due to shallow copy transform", }, { - label: label + "StructD", + label: label + "/StructD/PointerEqual", x: &ts.StructD{X: "NotEqual"}, y: &ts.StructD{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructD pointer called", }, { - label: label + "StructE", + label: label + "/StructE/ValueInequal", x: ts.StructE{X: "NotEqual"}, y: ts.StructE{X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructE value not called", }, { - label: label + "StructE", + label: label + "/StructE/ValueAddrEqual", x: ts.StructE{X: "NotEqual"}, y: ts.StructE{X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructE pointer called due to shallow copy transform", }, { - label: label + "StructE", + label: label + "/StructE/PointerEqual", x: &ts.StructE{X: "NotEqual"}, y: &ts.StructE{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructE pointer called", }, { - label: label + "StructF", + label: label + "/StructF/ValueInequal", x: ts.StructF{X: "NotEqual"}, y: ts.StructF{X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructF value not called", }, { - label: label + "StructF", + label: label + "/StructF/PointerEqual", x: &ts.StructF{X: "NotEqual"}, y: &ts.StructF{X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructF pointer called", }, { - label: label + "StructA1", + label: label + "/StructA1/ValueEqual", x: ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "equal"}, y: ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructA value called with equal X field", }, { - label: label + "StructA1", + label: label + "/StructA1/ValueInequal", x: ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructA value called, but inequal X field", }, { - label: label + "StructA1", + label: label + "/StructA1/PointerEqual", x: &ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "equal"}, y: &ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructA value called with equal X field", }, { - label: label + "StructA1", + label: label + "/StructA1/PointerInequal", x: &ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructA value called, but inequal X field", }, { - label: label + "StructB1", + label: label + "/StructB1/ValueEqual", x: ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "equal"}, y: ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructB pointer called due to shallow copy transform with equal X field", }, { - label: label + "StructB1", + label: label + "/StructB1/ValueInequal", x: ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: false, + reason: "Equal method on StructB pointer called due to shallow copy transform, but inequal X field", }, { - label: label + "StructB1", + label: label + "/StructB1/PointerEqual", x: &ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "equal"}, y: &ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructB pointer called due to shallow copy transform with equal X field", }, { - label: label + "StructB1", + label: label + "/StructB1/PointerInequal", x: &ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: false, + reason: "Equal method on StructB pointer called due to shallow copy transform, but inequal X field", }, { - label: label + "StructC1", + label: label + "/StructC1/ValueEqual", x: ts.StructC1{StructC: ts.StructC{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructC1{StructC: ts.StructC{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructC1 value called", }, { - label: label + "StructC1", + label: label + "/StructC1/PointerEqual", x: &ts.StructC1{StructC: ts.StructC{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructC1{StructC: ts.StructC{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructC1 pointer called", }, { - label: label + "StructD1", + label: label + "/StructD1/ValueInequal", x: ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructD1 value not called", }, { - label: label + "StructD1", + label: label + "/StructD1/PointerAddrEqual", x: ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructD1 pointer called due to shallow copy transform", }, { - label: label + "StructD1", + label: label + "/StructD1/PointerEqual", x: &ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructD1 pointer called", }, { - label: label + "StructE1", + label: label + "/StructE1/ValueInequal", x: ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructE1 value not called", }, { - label: label + "StructE1", + label: label + "/StructE1/ValueAddrEqual", x: ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, - opts: []cmp.Option{derefTransform}, + opts: []cmp.Option{addrTransform}, wantEqual: true, + reason: "Equal method on StructE1 pointer called due to shallow copy transform", }, { - label: label + "StructE1", + label: label + "/StructE1/PointerEqual", x: &ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructE1 pointer called", }, { - label: label + "StructF1", + label: label + "/StructF1/ValueInequal", x: ts.StructF1{StructF: ts.StructF{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructF1{StructF: ts.StructF{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructF1 value not called", }, { - label: label + "StructF1", + label: label + "/StructF1/PointerEqual", x: &ts.StructF1{StructF: ts.StructF{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructF1{StructF: ts.StructF{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method on StructF1 pointer called", }, { - label: label + "StructA2", + label: label + "/StructA2/ValueEqual", x: ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "equal"}, y: ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructA pointer called with equal X field", }, { - label: label + "StructA2", + label: label + "/StructA2/ValueInequal", x: ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructA pointer called, but inequal X field", }, { - label: label + "StructA2", + label: label + "/StructA2/PointerEqual", x: &ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "equal"}, y: &ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructA pointer called with equal X field", }, { - label: label + "StructA2", + label: label + "/StructA2/PointerInequal", x: &ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructA pointer called, but inequal X field", }, { - label: label + "StructB2", + label: label + "/StructB2/ValueEqual", x: ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "equal"}, y: ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructB pointer called with equal X field", }, { - label: label + "StructB2", + label: label + "/StructB2/ValueInequal", x: ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructB pointer called, but inequal X field", }, { - label: label + "StructB2", + label: label + "/StructB2/PointerEqual", x: &ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "equal"}, y: &ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "equal"}, wantEqual: true, + reason: "Equal method on StructB pointer called with equal X field", }, { - label: label + "StructB2", + label: label + "/StructB2/PointerInequal", x: &ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "not_equal"}, wantEqual: false, + reason: "Equal method on StructB pointer called, but inequal X field", }, { - label: label + "StructC2", + label: label + "/StructC2/ValueEqual", x: ts.StructC2{StructC: &ts.StructC{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructC2{StructC: &ts.StructC{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructC2 value due to forwarded StructC pointer", }, { - label: label + "StructC2", + label: label + "/StructC2/PointerEqual", x: &ts.StructC2{StructC: &ts.StructC{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructC2{StructC: &ts.StructC{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructC2 pointer due to forwarded StructC pointer", }, { - label: label + "StructD2", + label: label + "/StructD2/ValueEqual", x: ts.StructD2{StructD: &ts.StructD{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructD2{StructD: &ts.StructD{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructD2 value due to forwarded StructD pointer", }, { - label: label + "StructD2", + label: label + "/StructD2/PointerEqual", x: &ts.StructD2{StructD: &ts.StructD{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructD2{StructD: &ts.StructD{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructD2 pointer due to forwarded StructD pointer", }, { - label: label + "StructE2", + label: label + "/StructE2/ValueEqual", x: ts.StructE2{StructE: &ts.StructE{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructE2{StructE: &ts.StructE{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructE2 value due to forwarded StructE pointer", }, { - label: label + "StructE2", + label: label + "/StructE2/PointerEqual", x: &ts.StructE2{StructE: &ts.StructE{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructE2{StructE: &ts.StructE{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructE2 pointer due to forwarded StructE pointer", }, { - label: label + "StructF2", + label: label + "/StructF2/ValueEqual", x: ts.StructF2{StructF: &ts.StructF{X: "NotEqual"}, X: "NotEqual"}, y: ts.StructF2{StructF: &ts.StructF{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructF2 value due to forwarded StructF pointer", }, { - label: label + "StructF2", + label: label + "/StructF2/PointerEqual", x: &ts.StructF2{StructF: &ts.StructF{X: "NotEqual"}, X: "NotEqual"}, y: &ts.StructF2{StructF: &ts.StructF{X: "not_equal"}, X: "not_equal"}, wantEqual: true, + reason: "Equal method called on StructF2 pointer due to forwarded StructF pointer", }, { - label: label + "StructNo", + label: label + "/StructNo/Inequal", x: ts.StructNo{X: "NotEqual"}, y: ts.StructNo{X: "not_equal"}, wantEqual: false, + reason: "Equal method not called since StructNo is not assignable to InterfaceA", }, { - label: label + "AssignA", + label: label + "/AssignA/Equal", x: ts.AssignA(func() int { return 0 }), y: ts.AssignA(func() int { return 1 }), wantEqual: true, + reason: "Equal method called since named func is assignable to unnamed func", }, { - label: label + "AssignB", + label: label + "/AssignB/Equal", x: ts.AssignB(struct{ A int }{0}), y: ts.AssignB(struct{ A int }{1}), wantEqual: true, + reason: "Equal method called since named struct is assignable to unnamed struct", }, { - label: label + "AssignC", + label: label + "/AssignC/Equal", x: ts.AssignC(make(chan bool)), y: ts.AssignC(make(chan bool)), wantEqual: true, + reason: "Equal method called since named channel is assignable to unnamed channel", }, { - label: label + "AssignD", + label: label + "/AssignD/Equal", x: ts.AssignD(make(chan bool)), y: ts.AssignD(make(chan bool)), wantEqual: true, + reason: "Equal method called since named channel is assignable to unnamed channel", }} } @@ -2117,10 +2280,12 @@ func cycleTests() []test { var tests []test type XY struct{ x, y interface{} } for _, tt := range []struct { + label string in XY wantEqual bool reason string }{{ + label: "PointersEqual", in: func() XY { x := new(P) *x = x @@ -2129,7 +2294,9 @@ func cycleTests() []test { return XY{x, y} }(), wantEqual: true, + reason: "equal pair of single-node pointers", }, { + label: "PointersInequal", in: func() XY { x := new(P) *x = x @@ -2139,7 +2306,9 @@ func cycleTests() []test { return XY{x, y1} }(), wantEqual: false, + reason: "inequal pair of single-node and double-node pointers", }, { + label: "SlicesEqual", in: func() XY { x := S{nil} x[0] = x @@ -2148,7 +2317,9 @@ func cycleTests() []test { return XY{x, y} }(), wantEqual: true, + reason: "equal pair of single-node slices", }, { + label: "SlicesInequal", in: func() XY { x := S{nil} x[0] = x @@ -2158,7 +2329,9 @@ func cycleTests() []test { return XY{x, y1} }(), wantEqual: false, + reason: "inequal pair of single-node and double node slices", }, { + label: "MapsEqual", in: func() XY { x := M{0: nil} x[0] = x @@ -2167,7 +2340,9 @@ func cycleTests() []test { return XY{x, y} }(), wantEqual: true, + reason: "equal pair of single-node maps", }, { + label: "MapsInequal", in: func() XY { x := M{0: nil} x[0] = x @@ -2177,10 +2352,14 @@ func cycleTests() []test { return XY{x, y1} }(), wantEqual: false, + reason: "inequal pair of single-node and double-node maps", }, { + label: "GraphEqual", in: XY{makeGraph(), makeGraph()}, wantEqual: true, + reason: "graphs are equal since they have identical forms", }, { + label: "GraphInequalZeroed", in: func() XY { x := makeGraph() y := makeGraph() @@ -2190,7 +2369,9 @@ func cycleTests() []test { return XY{x, y} }(), wantEqual: false, + reason: "graphs are inequal because the ID fields are different", }, { + label: "GraphInequalStruct", in: func() XY { x := makeGraph() y := makeGraph() @@ -2201,9 +2382,10 @@ func cycleTests() []test { return XY{x, y} }(), wantEqual: false, + reason: "graphs are inequal because they differ on a map element", }} { tests = append(tests, test{ - label: label, + label: label + "/" + tt.label, x: tt.in.x, y: tt.in.y, wantEqual: tt.wantEqual, @@ -2273,7 +2455,7 @@ func project1Tests() []test { } return []test{{ - label: label, + label: label + "/PanicUnexported", x: ts.Eagle{Slaps: []ts.Slap{{ Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, }}}, @@ -2281,8 +2463,9 @@ func project1Tests() []test { Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, }}}, wantPanic: "cannot handle unexported field", + reason: "struct contains unexported fields", }, { - label: label, + label: label + "/ProtoEqual", x: ts.Eagle{Slaps: []ts.Slap{{ Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, }}}, @@ -2291,8 +2474,9 @@ func project1Tests() []test { }}}, opts: []cmp.Option{cmp.Comparer(pb.Equal)}, wantEqual: true, + reason: "simulated protobuf messages contain the same values", }, { - label: label, + label: label + "/ProtoInequal", x: ts.Eagle{Slaps: []ts.Slap{{}, {}, {}, {}, { Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, }}}, @@ -2301,14 +2485,16 @@ func project1Tests() []test { }}}, opts: []cmp.Option{cmp.Comparer(pb.Equal)}, wantEqual: false, + reason: "simulated protobuf messages contain different values", }, { - label: label, + label: label + "/Equal", x: createEagle(), y: createEagle(), opts: []cmp.Option{ignoreUnexported, cmp.Comparer(pb.Equal)}, wantEqual: true, + reason: "equal because values are the same", }, { - label: label, + label: label + "/Inequal", x: func() ts.Eagle { eg := createEagle() eg.Dreamers[1].Animal[0].(ts.Goat).Immutable.ID = "southbay2" @@ -2324,6 +2510,7 @@ func project1Tests() []test { }(), opts: []cmp.Option{ignoreUnexported, cmp.Comparer(pb.Equal)}, wantEqual: false, + reason: "inequal because some values are different", }} } @@ -2383,18 +2570,20 @@ func project2Tests() []test { } return []test{{ - label: label, + label: label + "/PanicUnexported", x: createBatch(), y: createBatch(), wantPanic: "cannot handle unexported field", + reason: "struct contains unexported fields", }, { - label: label, + label: label + "/Equal", x: createBatch(), y: createBatch(), opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, wantEqual: true, + reason: "equal because identical values are compared", }, { - label: label, + label: label + "/InequalOrder", x: createBatch(), y: func() ts.GermBatch { gb := createBatch() @@ -2404,8 +2593,9 @@ func project2Tests() []test { }(), opts: []cmp.Option{cmp.Comparer(pb.Equal), equalDish}, wantEqual: false, + reason: "inequal because slice contains elements in differing order", }, { - label: label, + label: label + "/EqualOrder", x: createBatch(), y: func() ts.GermBatch { gb := createBatch() @@ -2415,8 +2605,9 @@ func project2Tests() []test { }(), opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, wantEqual: true, + reason: "equal because unordered slice is sorted using transformer", }, { - label: label, + label: label + "/Inequal", x: func() ts.GermBatch { gb := createBatch() delete(gb.DirtyGerms, 17) @@ -2431,6 +2622,7 @@ func project2Tests() []test { }(), opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, wantEqual: false, + reason: "inequal because some values are different", }} } @@ -2468,24 +2660,27 @@ func project3Tests() []test { } return []test{{ - label: label, + label: label + "/PanicUnexported1", x: createDirt(), y: createDirt(), wantPanic: "cannot handle unexported field", + reason: "struct contains unexported fields", }, { - label: label, + label: label + "/PanicUnexported2", x: createDirt(), y: createDirt(), opts: []cmp.Option{allowVisibility, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, wantPanic: "cannot handle unexported field", + reason: "struct contains references to simulated protobuf types with unexported fields", }, { - label: label, + label: label + "/Equal", x: createDirt(), y: createDirt(), opts: []cmp.Option{allowVisibility, transformProtos, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, wantEqual: true, + reason: "transformer used to create reference to protobuf message so it works with pb.Equal", }, { - label: label, + label: label + "/Inequal", x: func() ts.Dirt { d := createDirt() d.SetTable(ts.CreateMockTable([]string{"a", "c"})) @@ -2502,6 +2697,7 @@ func project3Tests() []test { }(), opts: []cmp.Option{allowVisibility, transformProtos, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, wantEqual: false, + reason: "inequal because some values are different", }} } @@ -2544,24 +2740,27 @@ func project4Tests() []test { } return []test{{ - label: label, + label: label + "/PanicUnexported1", x: createCartel(), y: createCartel(), wantPanic: "cannot handle unexported field", + reason: "struct contains unexported fields", }, { - label: label, + label: label + "/PanicUnexported2", x: createCartel(), y: createCartel(), opts: []cmp.Option{allowVisibility, cmp.Comparer(pb.Equal)}, wantPanic: "cannot handle unexported field", + reason: "struct contains references to simulated protobuf types with unexported fields", }, { - label: label, + label: label + "/Equal", x: createCartel(), y: createCartel(), opts: []cmp.Option{allowVisibility, transformProtos, cmp.Comparer(pb.Equal)}, wantEqual: true, + reason: "transformer used to create reference to protobuf message so it works with pb.Equal", }, { - label: label, + label: label + "/Inequal", x: func() ts.Cartel { d := createCartel() var p1, p2 ts.Poison @@ -2581,6 +2780,7 @@ func project4Tests() []test { }(), opts: []cmp.Option{allowVisibility, transformProtos, cmp.Comparer(pb.Equal)}, wantEqual: false, + reason: "inequal because some values are different", }} } diff --git a/cmp/testdata/diffs b/cmp/testdata/diffs index c161591..baec97d 100644 --- a/cmp/testdata/diffs +++ b/cmp/testdata/diffs @@ -1,54 +1,54 @@ -<<< TestDiff/Comparer#09 +<<< TestDiff/Comparer/StructInequal struct{ A int; B int; C int }{ A: 1, B: 2, - C: 3, + C: 4, } ->>> TestDiff/Comparer#09 -<<< TestDiff/Comparer#12 +>>> TestDiff/Comparer/StructInequal +<<< TestDiff/Comparer/PointerStructInequal &struct{ A *int }{ - A: &4, + A: &5, } ->>> TestDiff/Comparer#12 -<<< TestDiff/Comparer#16 +>>> TestDiff/Comparer/PointerStructInequal +<<< TestDiff/Comparer/StructNestedPointerInequal &struct{ R *bytes.Buffer }{ - R: s"", + R: nil, } ->>> TestDiff/Comparer#16 -<<< TestDiff/Comparer#23 +>>> TestDiff/Comparer/StructNestedPointerInequal +<<< TestDiff/Comparer/RegexpInequal []*regexp.Regexp{ nil, - s"a*b*c*", + s"a*b*d*", } ->>> TestDiff/Comparer#23 -<<< TestDiff/Comparer#25 +>>> TestDiff/Comparer/RegexpInequal +<<< TestDiff/Comparer/TriplePointerInequal &&&int( - 0, + 1, ) ->>> TestDiff/Comparer#25 -<<< TestDiff/Comparer#28 +>>> TestDiff/Comparer/TriplePointerInequal +<<< TestDiff/Comparer/StringerInequal struct{ fmt.Stringer }( - s"hello", + s"hello2", ) ->>> TestDiff/Comparer#28 -<<< TestDiff/Comparer#29 +>>> TestDiff/Comparer/StringerInequal +<<< TestDiff/Comparer/DifferingHash [16]uint8{ - 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61, + 0x92, 0xeb, 0x5f, 0xfe, 0xe6, 0xae, 0x2f, 0xec, 0x3a, 0xd7, 0x1c, 0x77, 0x75, 0x31, 0x57, 0x8f, } ->>> TestDiff/Comparer#29 -<<< TestDiff/Comparer#30 +>>> TestDiff/Comparer/DifferingHash +<<< TestDiff/Comparer/NilStringer interface{}( - &fmt.Stringer(nil), ) ->>> TestDiff/Comparer#30 -<<< TestDiff/Comparer#31 +>>> TestDiff/Comparer/NilStringer +<<< TestDiff/Comparer/TarHeaders []cmp_test.tarHeader{ { ... // 4 identical fields @@ -101,8 +101,8 @@ ... // 6 identical fields }, } ->>> TestDiff/Comparer#31 -<<< TestDiff/Comparer#36 +>>> TestDiff/Comparer/TarHeaders +<<< TestDiff/Comparer/IrreflexiveComparison []int{ - Inverse(λ, float64(NaN)), + Inverse(λ, float64(NaN)), @@ -125,19 +125,19 @@ - Inverse(λ, float64(NaN)), + Inverse(λ, float64(NaN)), } ->>> TestDiff/Comparer#36 -<<< TestDiff/Comparer#37 +>>> TestDiff/Comparer/IrreflexiveComparison +<<< TestDiff/Comparer/StringerMapKey map[*testprotos.Stringer]*testprotos.Stringer( - {s"hello": s"world"}, + nil, ) ->>> TestDiff/Comparer#37 -<<< TestDiff/Comparer#38 +>>> TestDiff/Comparer/StringerMapKey +<<< TestDiff/Comparer/StringerBacktick interface{}( - []*testprotos.Stringer{s`multi\nline\nline\nline`}, ) ->>> TestDiff/Comparer#38 -<<< TestDiff/Comparer#42 +>>> TestDiff/Comparer/StringerBacktick +<<< TestDiff/Comparer/DynamicMap []interface{}{ map[string]interface{}{ "avg": float64(0.278), @@ -152,14 +152,14 @@ "name": string("Sammy Sosa"), }, } ->>> TestDiff/Comparer#42 -<<< TestDiff/Comparer#43 +>>> TestDiff/Comparer/DynamicMap +<<< TestDiff/Comparer/MapKeyPointer map[*int]string{ - &⟪0xdeadf00f⟫0: "hello", + &⟪0xdeadf00f⟫0: "world", } ->>> TestDiff/Comparer#43 -<<< TestDiff/Comparer#44 +>>> TestDiff/Comparer/MapKeyPointer +<<< TestDiff/Comparer/IgnoreSliceElements [2][]int{ {..., 1, 2, 3, ...}, { @@ -169,8 +169,8 @@ ... // 3 ignored elements }, } ->>> TestDiff/Comparer#44 -<<< TestDiff/Comparer#45 +>>> TestDiff/Comparer/IgnoreSliceElements +<<< TestDiff/Comparer/IgnoreMapEntries [2]map[string]int{ {"KEEP3": 3, "keep1": 1, "keep2": 2, ...}, { @@ -179,14 +179,14 @@ + "keep2": 2, }, } ->>> TestDiff/Comparer#45 -<<< TestDiff/Transformer +>>> TestDiff/Comparer/IgnoreMapEntries +<<< TestDiff/Transformer/Uints uint8(Inverse(λ, uint16(Inverse(λ, uint32(Inverse(λ, uint64( - 0, + 1, ))))))) ->>> TestDiff/Transformer -<<< TestDiff/Transformer#02 +>>> TestDiff/Transformer/Uints +<<< TestDiff/Transformer/Filtered []int{ Inverse(λ, int64(0)), - Inverse(λ, int64(-5)), @@ -195,14 +195,14 @@ - Inverse(λ, int64(-1)), + Inverse(λ, int64(-5)), } ->>> TestDiff/Transformer#02 -<<< TestDiff/Transformer#03 +>>> TestDiff/Transformer/Filtered +<<< TestDiff/Transformer/DisjointOutput int(Inverse(λ, interface{}( - string("zero"), + float64(1), ))) ->>> TestDiff/Transformer#03 -<<< TestDiff/Transformer#04 +>>> TestDiff/Transformer/DisjointOutput +<<< TestDiff/Transformer/JSON string(Inverse(ParseJSON, map[string]interface{}{ "address": map[string]interface{}{ - "city": string("Los Angeles"), @@ -228,8 +228,8 @@ }, + "spouse": nil, })) ->>> TestDiff/Transformer#04 -<<< TestDiff/Transformer#05 +>>> TestDiff/Transformer/JSON +<<< TestDiff/Transformer/AcyclicString cmp_test.StringBytes{ String: Inverse(SplitString, []string{ "some", @@ -251,7 +251,7 @@ }, })), } ->>> TestDiff/Transformer#05 +>>> TestDiff/Transformer/AcyclicString <<< TestDiff/Reporter/AmbiguousType interface{}( - "github.com/google/go-cmp/cmp/internal/teststructs/foo1".Bar{}, @@ -327,12 +327,12 @@ - s"hello": "goodbye", } >>> TestDiff/Reporter/NonAmbiguousStringerMapKey -<<< TestDiff//InvalidUTF8 +<<< TestDiff/Reporter/InvalidUTF8 interface{}( - cmp_test.MyString("\xed\xa0\x80"), ) ->>> TestDiff//InvalidUTF8 -<<< TestDiff/Reporter +>>> TestDiff/Reporter/InvalidUTF8 +<<< TestDiff/Reporter/UnbatchedSlice cmp_test.MyComposite{ ... // 3 identical fields BytesB: nil, @@ -350,8 +350,8 @@ IntsC: nil, ... // 6 identical fields } ->>> TestDiff/Reporter -<<< TestDiff/Reporter#01 +>>> TestDiff/Reporter/UnbatchedSlice +<<< TestDiff/Reporter/BatchedSlice cmp_test.MyComposite{ ... // 3 identical fields BytesB: nil, @@ -367,7 +367,7 @@ IntsC: nil, ... // 6 identical fields } ->>> TestDiff/Reporter#01 +>>> TestDiff/Reporter/BatchedSlice <<< TestDiff/Reporter/BatchedWithComparer cmp_test.MyComposite{ StringA: "", @@ -389,7 +389,7 @@ - cmp_test.MyComposite{IntsA: []int8{0, 1, 2, 3, 4, 5, 6, 7, ...}}, ) >>> TestDiff/Reporter/BatchedLong -<<< TestDiff/Reporter#02 +<<< TestDiff/Reporter/BatchedNamedAndUnnamed cmp_test.MyComposite{ StringA: "", StringB: "", @@ -442,8 +442,8 @@ + 9.5, 8.5, 7.5, }, } ->>> TestDiff/Reporter#02 -<<< TestDiff/Reporter#03 +>>> TestDiff/Reporter/BatchedNamedAndUnnamed +<<< TestDiff/Reporter/BinaryHexdump cmp_test.MyComposite{ StringA: "", StringB: "", @@ -464,8 +464,8 @@ BytesC: nil, ... // 9 identical fields } ->>> TestDiff/Reporter#03 -<<< TestDiff/Reporter#04 +>>> TestDiff/Reporter/BinaryHexdump +<<< TestDiff/Reporter/StringHexdump cmp_test.MyComposite{ StringA: "", StringB: cmp_test.MyString{ @@ -489,8 +489,8 @@ BytesB: nil, ... // 10 identical fields } ->>> TestDiff/Reporter#04 -<<< TestDiff/Reporter#05 +>>> TestDiff/Reporter/StringHexdump +<<< TestDiff/Reporter/BinaryString cmp_test.MyComposite{ StringA: "", StringB: "", @@ -507,7 +507,7 @@ BytesC: nil, ... // 9 identical fields } ->>> TestDiff/Reporter#05 +>>> TestDiff/Reporter/BinaryString <<< TestDiff/Reporter/TripleQuote cmp_test.MyComposite{ StringA: ( @@ -875,7 +875,7 @@ ... // 12 identical and 10 modified elements } >>> TestDiff/Reporter/LimitMaximumSliceDiffs -<<< TestDiff/Reporter#06 +<<< TestDiff/Reporter/MultilineString cmp_test.MyComposite{ StringA: ( """ @@ -902,8 +902,8 @@ BytesA: nil, ... // 11 identical fields } ->>> TestDiff/Reporter#06 -<<< TestDiff/Reporter#07 +>>> TestDiff/Reporter/MultilineString +<<< TestDiff/Reporter/Slices cmp_test.MyComposite{ StringA: "", StringB: "", @@ -932,8 +932,8 @@ - FloatsC: cmp_test.MyFloats{7.5, 8.5, 9.5}, + FloatsC: nil, } ->>> TestDiff/Reporter#07 -<<< TestDiff/Reporter#08 +>>> TestDiff/Reporter/Slices +<<< TestDiff/Reporter/EmptySlices cmp_test.MyComposite{ StringA: "", StringB: "", @@ -962,8 +962,8 @@ - FloatsC: cmp_test.MyFloats{}, + FloatsC: nil, } ->>> TestDiff/Reporter#08 -<<< TestDiff/EmbeddedStruct/ParentStructA#04 +>>> TestDiff/Reporter/EmptySlices +<<< TestDiff/EmbeddedStruct/ParentStructA/Inequal teststructs.ParentStructA{ privateStruct: teststructs.privateStruct{ - Public: 1, @@ -972,8 +972,8 @@ + private: 3, }, } ->>> TestDiff/EmbeddedStruct/ParentStructA#04 -<<< TestDiff/EmbeddedStruct/ParentStructB#04 +>>> TestDiff/EmbeddedStruct/ParentStructA/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructB/Inequal teststructs.ParentStructB{ PublicStruct: teststructs.PublicStruct{ - Public: 1, @@ -982,8 +982,8 @@ + private: 3, }, } ->>> TestDiff/EmbeddedStruct/ParentStructB#04 -<<< TestDiff/EmbeddedStruct/ParentStructC#04 +>>> TestDiff/EmbeddedStruct/ParentStructB/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructC/Inequal teststructs.ParentStructC{ privateStruct: teststructs.privateStruct{ - Public: 1, @@ -996,8 +996,8 @@ - private: 4, + private: 5, } ->>> TestDiff/EmbeddedStruct/ParentStructC#04 -<<< TestDiff/EmbeddedStruct/ParentStructD#04 +>>> TestDiff/EmbeddedStruct/ParentStructC/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructD/Inequal teststructs.ParentStructD{ PublicStruct: teststructs.PublicStruct{ - Public: 1, @@ -1010,8 +1010,8 @@ - private: 4, + private: 5, } ->>> TestDiff/EmbeddedStruct/ParentStructD#04 -<<< TestDiff/EmbeddedStruct/ParentStructE#05 +>>> TestDiff/EmbeddedStruct/ParentStructD/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructE/Inequal teststructs.ParentStructE{ privateStruct: teststructs.privateStruct{ - Public: 1, @@ -1026,8 +1026,8 @@ + private: 5, }, } ->>> TestDiff/EmbeddedStruct/ParentStructE#05 -<<< TestDiff/EmbeddedStruct/ParentStructF#05 +>>> TestDiff/EmbeddedStruct/ParentStructE/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructF/Inequal teststructs.ParentStructF{ privateStruct: teststructs.privateStruct{ - Public: 1, @@ -1046,8 +1046,8 @@ - private: 6, + private: 7, } ->>> TestDiff/EmbeddedStruct/ParentStructF#05 -<<< TestDiff/EmbeddedStruct/ParentStructG#04 +>>> TestDiff/EmbeddedStruct/ParentStructF/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructG/Inequal &teststructs.ParentStructG{ privateStruct: &teststructs.privateStruct{ - Public: 1, @@ -1056,8 +1056,8 @@ + private: 3, }, } ->>> TestDiff/EmbeddedStruct/ParentStructG#04 -<<< TestDiff/EmbeddedStruct/ParentStructH#05 +>>> TestDiff/EmbeddedStruct/ParentStructG/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructH/Inequal &teststructs.ParentStructH{ PublicStruct: &teststructs.PublicStruct{ - Public: 1, @@ -1066,8 +1066,8 @@ + private: 3, }, } ->>> TestDiff/EmbeddedStruct/ParentStructH#05 -<<< TestDiff/EmbeddedStruct/ParentStructI#06 +>>> TestDiff/EmbeddedStruct/ParentStructH/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructI/Inequal &teststructs.ParentStructI{ privateStruct: &teststructs.privateStruct{ - Public: 1, @@ -1082,8 +1082,8 @@ + private: 5, }, } ->>> TestDiff/EmbeddedStruct/ParentStructI#06 -<<< TestDiff/EmbeddedStruct/ParentStructJ#05 +>>> TestDiff/EmbeddedStruct/ParentStructI/Inequal +<<< TestDiff/EmbeddedStruct/ParentStructJ/Inequal &teststructs.ParentStructJ{ privateStruct: &teststructs.privateStruct{ - Public: 1, @@ -1110,136 +1110,136 @@ + private: 7, }, } ->>> TestDiff/EmbeddedStruct/ParentStructJ#05 -<<< TestDiff/EqualMethod/StructB +>>> TestDiff/EmbeddedStruct/ParentStructJ/Inequal +<<< TestDiff/EqualMethod/StructB/ValueInequal teststructs.StructB{ - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructB -<<< TestDiff/EqualMethod/StructD +>>> TestDiff/EqualMethod/StructB/ValueInequal +<<< TestDiff/EqualMethod/StructD/ValueInequal teststructs.StructD{ - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructD -<<< TestDiff/EqualMethod/StructE +>>> TestDiff/EqualMethod/StructD/ValueInequal +<<< TestDiff/EqualMethod/StructE/ValueInequal teststructs.StructE{ - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructE -<<< TestDiff/EqualMethod/StructF +>>> TestDiff/EqualMethod/StructE/ValueInequal +<<< TestDiff/EqualMethod/StructF/ValueInequal teststructs.StructF{ - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructF -<<< TestDiff/EqualMethod/StructA1#01 +>>> TestDiff/EqualMethod/StructF/ValueInequal +<<< TestDiff/EqualMethod/StructA1/ValueInequal teststructs.StructA1{ StructA: {X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructA1#01 -<<< TestDiff/EqualMethod/StructA1#03 +>>> TestDiff/EqualMethod/StructA1/ValueInequal +<<< TestDiff/EqualMethod/StructA1/PointerInequal &teststructs.StructA1{ StructA: {X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructA1#03 -<<< TestDiff/EqualMethod/StructB1#01 +>>> TestDiff/EqualMethod/StructA1/PointerInequal +<<< TestDiff/EqualMethod/StructB1/ValueInequal teststructs.StructB1{ - StructB: Inverse(Ref, &teststructs.StructB{X: "NotEqual"}), + StructB: Inverse(Addr, &teststructs.StructB{X: "NotEqual"}), - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructB1#01 -<<< TestDiff/EqualMethod/StructB1#03 +>>> TestDiff/EqualMethod/StructB1/ValueInequal +<<< TestDiff/EqualMethod/StructB1/PointerInequal &teststructs.StructB1{ - StructB: Inverse(Ref, &teststructs.StructB{X: "NotEqual"}), + StructB: Inverse(Addr, &teststructs.StructB{X: "NotEqual"}), - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructB1#03 -<<< TestDiff/EqualMethod/StructD1 +>>> TestDiff/EqualMethod/StructB1/PointerInequal +<<< TestDiff/EqualMethod/StructD1/ValueInequal teststructs.StructD1{ - StructD: teststructs.StructD{X: "NotEqual"}, + StructD: teststructs.StructD{X: "not_equal"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructD1 -<<< TestDiff/EqualMethod/StructE1 +>>> TestDiff/EqualMethod/StructD1/ValueInequal +<<< TestDiff/EqualMethod/StructE1/ValueInequal teststructs.StructE1{ - StructE: teststructs.StructE{X: "NotEqual"}, + StructE: teststructs.StructE{X: "not_equal"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructE1 -<<< TestDiff/EqualMethod/StructF1 +>>> TestDiff/EqualMethod/StructE1/ValueInequal +<<< TestDiff/EqualMethod/StructF1/ValueInequal teststructs.StructF1{ - StructF: teststructs.StructF{X: "NotEqual"}, + StructF: teststructs.StructF{X: "not_equal"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructF1 -<<< TestDiff/EqualMethod/StructA2#01 +>>> TestDiff/EqualMethod/StructF1/ValueInequal +<<< TestDiff/EqualMethod/StructA2/ValueInequal teststructs.StructA2{ StructA: &{X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructA2#01 -<<< TestDiff/EqualMethod/StructA2#03 +>>> TestDiff/EqualMethod/StructA2/ValueInequal +<<< TestDiff/EqualMethod/StructA2/PointerInequal &teststructs.StructA2{ StructA: &{X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructA2#03 -<<< TestDiff/EqualMethod/StructB2#01 +>>> TestDiff/EqualMethod/StructA2/PointerInequal +<<< TestDiff/EqualMethod/StructB2/ValueInequal teststructs.StructB2{ StructB: &{X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructB2#01 -<<< TestDiff/EqualMethod/StructB2#03 +>>> TestDiff/EqualMethod/StructB2/ValueInequal +<<< TestDiff/EqualMethod/StructB2/PointerInequal &teststructs.StructB2{ StructB: &{X: "NotEqual"}, - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructB2#03 -<<< TestDiff/EqualMethod/StructNo +>>> TestDiff/EqualMethod/StructB2/PointerInequal +<<< TestDiff/EqualMethod/StructNo/Inequal teststructs.StructNo{ - X: "NotEqual", + X: "not_equal", } ->>> TestDiff/EqualMethod/StructNo -<<< TestDiff/Cycle#01 +>>> TestDiff/EqualMethod/StructNo/Inequal +<<< TestDiff/Cycle/PointersInequal &&cmp_test.P( - &⟪0xdeadf00f⟫, + &&⟪0xdeadf00f⟫, ) ->>> TestDiff/Cycle#01 -<<< TestDiff/Cycle#03 +>>> TestDiff/Cycle/PointersInequal +<<< TestDiff/Cycle/SlicesInequal cmp_test.S{ - {{{*(*cmp_test.S)(⟪0xdeadf00f⟫)}}}, + {{{{*(*cmp_test.S)(⟪0xdeadf00f⟫)}}}}, } ->>> TestDiff/Cycle#03 -<<< TestDiff/Cycle#05 +>>> TestDiff/Cycle/SlicesInequal +<<< TestDiff/Cycle/MapsInequal cmp_test.M{ - 0: {0: ⟪0xdeadf00f⟫}, + 0: {0: {0: ⟪0xdeadf00f⟫}}, } ->>> TestDiff/Cycle#05 -<<< TestDiff/Cycle#07 +>>> TestDiff/Cycle/MapsInequal +<<< TestDiff/Cycle/GraphInequalZeroed map[string]*cmp_test.CycleAlpha{ "Bar": &{ Name: "Bar", @@ -1352,8 +1352,8 @@ }, }, } ->>> TestDiff/Cycle#07 -<<< TestDiff/Cycle#08 +>>> TestDiff/Cycle/GraphInequalZeroed +<<< TestDiff/Cycle/GraphInequalStruct map[string]*cmp_test.CycleAlpha{ "Bar": &{ Name: "Bar", @@ -1437,8 +1437,8 @@ }, "Foo": &{Name: "Foo", Bravos: {"FooBravo": &{ID: 101, Name: "FooBravo", Mods: 100, Alphas: {"Foo": &{Name: "Foo", Bravos: {...}}}}}}, } ->>> TestDiff/Cycle#08 -<<< TestDiff/Project1#02 +>>> TestDiff/Cycle/GraphInequalStruct +<<< TestDiff/Project1/ProtoInequal teststructs.Eagle{ ... // 4 identical fields Dreamers: nil, @@ -1462,8 +1462,8 @@ PrankRating: "", ... // 2 identical fields } ->>> TestDiff/Project1#02 -<<< TestDiff/Project1#04 +>>> TestDiff/Project1/ProtoInequal +<<< TestDiff/Project1/Inequal teststructs.Eagle{ ... // 2 identical fields Desc: "some description", @@ -1535,8 +1535,8 @@ PrankRating: "", ... // 2 identical fields } ->>> TestDiff/Project1#04 -<<< TestDiff/Project2#02 +>>> TestDiff/Project1/Inequal +<<< TestDiff/Project2/InequalOrder teststructs.GermBatch{ DirtyGerms: map[int32][]*testprotos.Germ{ 17: {s"germ1"}, @@ -1551,8 +1551,8 @@ GermMap: {13: s"germ13", 21: s"germ21"}, ... // 7 identical fields } ->>> TestDiff/Project2#02 -<<< TestDiff/Project2#04 +>>> TestDiff/Project2/InequalOrder +<<< TestDiff/Project2/Inequal teststructs.GermBatch{ DirtyGerms: map[int32][]*testprotos.Germ{ + 17: {s"germ1"}, @@ -1578,8 +1578,8 @@ TotalDirtyGerms: 0, InfectedAt: s"2009-11-10 23:00:00 +0000 UTC", } ->>> TestDiff/Project2#04 -<<< TestDiff/Project3#03 +>>> TestDiff/Project2/Inequal +<<< TestDiff/Project3/Inequal teststructs.Dirt{ - table: &teststructs.MockTable{state: []string{"a", "c"}}, + table: &teststructs.MockTable{state: []string{"a", "b", "c"}}, @@ -1597,8 +1597,8 @@ lastTime: 54321, ... // 1 ignored field } ->>> TestDiff/Project3#03 -<<< TestDiff/Project4#03 +>>> TestDiff/Project3/Inequal +<<< TestDiff/Project4/Inequal teststructs.Cartel{ Headquarter: teststructs.Headquarter{ id: 5, @@ -1639,4 +1639,4 @@ - &{poisonType: 2, manufacturer: "acme2"}, }, } ->>> TestDiff/Project4#03 +>>> TestDiff/Project4/Inequal