1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundakpackage cmp_test 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport ( 8*88d15eacSSasha Smundak "bytes" 9*88d15eacSSasha Smundak "crypto/sha256" 10*88d15eacSSasha Smundak "encoding/json" 11*88d15eacSSasha Smundak "errors" 12*88d15eacSSasha Smundak "flag" 13*88d15eacSSasha Smundak "fmt" 14*88d15eacSSasha Smundak "io" 15*88d15eacSSasha Smundak "io/ioutil" 16*88d15eacSSasha Smundak "math" 17*88d15eacSSasha Smundak "math/rand" 18*88d15eacSSasha Smundak "reflect" 19*88d15eacSSasha Smundak "regexp" 20*88d15eacSSasha Smundak "sort" 21*88d15eacSSasha Smundak "strconv" 22*88d15eacSSasha Smundak "strings" 23*88d15eacSSasha Smundak "sync" 24*88d15eacSSasha Smundak "testing" 25*88d15eacSSasha Smundak "time" 26*88d15eacSSasha Smundak 27*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp" 28*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp/cmpopts" 29*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp/internal/flags" 30*88d15eacSSasha Smundak 31*88d15eacSSasha Smundak pb "github.com/google/go-cmp/cmp/internal/testprotos" 32*88d15eacSSasha Smundak ts "github.com/google/go-cmp/cmp/internal/teststructs" 33*88d15eacSSasha Smundak foo1 "github.com/google/go-cmp/cmp/internal/teststructs/foo1" 34*88d15eacSSasha Smundak foo2 "github.com/google/go-cmp/cmp/internal/teststructs/foo2" 35*88d15eacSSasha Smundak) 36*88d15eacSSasha Smundak 37*88d15eacSSasha Smundakfunc init() { 38*88d15eacSSasha Smundak flags.Deterministic = true 39*88d15eacSSasha Smundak} 40*88d15eacSSasha Smundak 41*88d15eacSSasha Smundakvar update = flag.Bool("update", false, "update golden test files") 42*88d15eacSSasha Smundak 43*88d15eacSSasha Smundakconst goldenHeaderPrefix = "<<< " 44*88d15eacSSasha Smundakconst goldenFooterPrefix = ">>> " 45*88d15eacSSasha Smundak 46*88d15eacSSasha Smundak// mustParseGolden parses a file as a set of key-value pairs. 47*88d15eacSSasha Smundak// 48*88d15eacSSasha Smundak// The syntax is simple and looks something like: 49*88d15eacSSasha Smundak// 50*88d15eacSSasha Smundak// <<< Key1 51*88d15eacSSasha Smundak// value1a 52*88d15eacSSasha Smundak// value1b 53*88d15eacSSasha Smundak// >>> Key1 54*88d15eacSSasha Smundak// <<< Key2 55*88d15eacSSasha Smundak// value2 56*88d15eacSSasha Smundak// >>> Key2 57*88d15eacSSasha Smundak// 58*88d15eacSSasha Smundak// It is the user's responsibility to choose a sufficiently unique key name 59*88d15eacSSasha Smundak// such that it never appears in the body of the value itself. 60*88d15eacSSasha Smundakfunc mustParseGolden(path string) map[string]string { 61*88d15eacSSasha Smundak b, err := ioutil.ReadFile(path) 62*88d15eacSSasha Smundak if err != nil { 63*88d15eacSSasha Smundak panic(err) 64*88d15eacSSasha Smundak } 65*88d15eacSSasha Smundak s := string(b) 66*88d15eacSSasha Smundak 67*88d15eacSSasha Smundak out := map[string]string{} 68*88d15eacSSasha Smundak for len(s) > 0 { 69*88d15eacSSasha Smundak // Identify the next header. 70*88d15eacSSasha Smundak i := strings.Index(s, "\n") + len("\n") 71*88d15eacSSasha Smundak header := s[:i] 72*88d15eacSSasha Smundak if !strings.HasPrefix(header, goldenHeaderPrefix) { 73*88d15eacSSasha Smundak panic(fmt.Sprintf("invalid header: %q", header)) 74*88d15eacSSasha Smundak } 75*88d15eacSSasha Smundak 76*88d15eacSSasha Smundak // Locate the next footer. 77*88d15eacSSasha Smundak footer := goldenFooterPrefix + header[len(goldenHeaderPrefix):] 78*88d15eacSSasha Smundak j := strings.Index(s, footer) 79*88d15eacSSasha Smundak if j < 0 { 80*88d15eacSSasha Smundak panic(fmt.Sprintf("missing footer: %q", footer)) 81*88d15eacSSasha Smundak } 82*88d15eacSSasha Smundak 83*88d15eacSSasha Smundak // Store the name and data. 84*88d15eacSSasha Smundak name := header[len(goldenHeaderPrefix) : len(header)-len("\n")] 85*88d15eacSSasha Smundak if _, ok := out[name]; ok { 86*88d15eacSSasha Smundak panic(fmt.Sprintf("duplicate name: %q", name)) 87*88d15eacSSasha Smundak } 88*88d15eacSSasha Smundak out[name] = s[len(header):j] 89*88d15eacSSasha Smundak s = s[j+len(footer):] 90*88d15eacSSasha Smundak } 91*88d15eacSSasha Smundak return out 92*88d15eacSSasha Smundak} 93*88d15eacSSasha Smundakfunc mustFormatGolden(path string, in []struct{ Name, Data string }) { 94*88d15eacSSasha Smundak var b []byte 95*88d15eacSSasha Smundak for _, v := range in { 96*88d15eacSSasha Smundak b = append(b, goldenHeaderPrefix+v.Name+"\n"...) 97*88d15eacSSasha Smundak b = append(b, v.Data...) 98*88d15eacSSasha Smundak b = append(b, goldenFooterPrefix+v.Name+"\n"...) 99*88d15eacSSasha Smundak } 100*88d15eacSSasha Smundak if err := ioutil.WriteFile(path, b, 0664); err != nil { 101*88d15eacSSasha Smundak panic(err) 102*88d15eacSSasha Smundak } 103*88d15eacSSasha Smundak} 104*88d15eacSSasha Smundak 105*88d15eacSSasha Smundakvar now = time.Date(2009, time.November, 10, 23, 00, 00, 00, time.UTC) 106*88d15eacSSasha Smundak 107*88d15eacSSasha Smundak// TODO(≥go1.18): Define a generic function that boxes a value on the heap. 108*88d15eacSSasha Smundakfunc newInt(n int) *int { return &n } 109*88d15eacSSasha Smundak 110*88d15eacSSasha Smundaktype Stringer string 111*88d15eacSSasha Smundak 112*88d15eacSSasha Smundakfunc newStringer(s string) fmt.Stringer { return (*Stringer)(&s) } 113*88d15eacSSasha Smundakfunc (s Stringer) String() string { return string(s) } 114*88d15eacSSasha Smundak 115*88d15eacSSasha Smundaktype test struct { 116*88d15eacSSasha Smundak label string // Test name 117*88d15eacSSasha Smundak x, y interface{} // Input values to compare 118*88d15eacSSasha Smundak opts []cmp.Option // Input options 119*88d15eacSSasha Smundak wantEqual bool // Whether any difference is expected 120*88d15eacSSasha Smundak wantPanic string // Sub-string of an expected panic message 121*88d15eacSSasha Smundak reason string // The reason for the expected outcome 122*88d15eacSSasha Smundak} 123*88d15eacSSasha Smundak 124*88d15eacSSasha Smundakfunc TestDiff(t *testing.T) { 125*88d15eacSSasha Smundak var tests []test 126*88d15eacSSasha Smundak tests = append(tests, comparerTests()...) 127*88d15eacSSasha Smundak tests = append(tests, transformerTests()...) 128*88d15eacSSasha Smundak tests = append(tests, reporterTests()...) 129*88d15eacSSasha Smundak tests = append(tests, embeddedTests()...) 130*88d15eacSSasha Smundak tests = append(tests, methodTests()...) 131*88d15eacSSasha Smundak tests = append(tests, cycleTests()...) 132*88d15eacSSasha Smundak tests = append(tests, project1Tests()...) 133*88d15eacSSasha Smundak tests = append(tests, project2Tests()...) 134*88d15eacSSasha Smundak tests = append(tests, project3Tests()...) 135*88d15eacSSasha Smundak tests = append(tests, project4Tests()...) 136*88d15eacSSasha Smundak 137*88d15eacSSasha Smundak const goldenFile = "testdata/diffs" 138*88d15eacSSasha Smundak gotDiffs := []struct{ Name, Data string }{} 139*88d15eacSSasha Smundak wantDiffs := mustParseGolden(goldenFile) 140*88d15eacSSasha Smundak for _, tt := range tests { 141*88d15eacSSasha Smundak tt := tt 142*88d15eacSSasha Smundak t.Run(tt.label, func(t *testing.T) { 143*88d15eacSSasha Smundak if !*update { 144*88d15eacSSasha Smundak t.Parallel() 145*88d15eacSSasha Smundak } 146*88d15eacSSasha Smundak var gotDiff, gotPanic string 147*88d15eacSSasha Smundak func() { 148*88d15eacSSasha Smundak defer func() { 149*88d15eacSSasha Smundak if ex := recover(); ex != nil { 150*88d15eacSSasha Smundak if s, ok := ex.(string); ok { 151*88d15eacSSasha Smundak gotPanic = s 152*88d15eacSSasha Smundak } else { 153*88d15eacSSasha Smundak panic(ex) 154*88d15eacSSasha Smundak } 155*88d15eacSSasha Smundak } 156*88d15eacSSasha Smundak }() 157*88d15eacSSasha Smundak gotDiff = cmp.Diff(tt.x, tt.y, tt.opts...) 158*88d15eacSSasha Smundak }() 159*88d15eacSSasha Smundak 160*88d15eacSSasha Smundak switch { 161*88d15eacSSasha Smundak case strings.Contains(t.Name(), "#"): 162*88d15eacSSasha Smundak panic("unique test name must be provided") 163*88d15eacSSasha Smundak case tt.reason == "": 164*88d15eacSSasha Smundak panic("reason must be provided") 165*88d15eacSSasha Smundak case tt.wantPanic == "": 166*88d15eacSSasha Smundak if gotPanic != "" { 167*88d15eacSSasha Smundak t.Fatalf("unexpected panic message: %s\nreason: %v", gotPanic, tt.reason) 168*88d15eacSSasha Smundak } 169*88d15eacSSasha Smundak if *update { 170*88d15eacSSasha Smundak if gotDiff != "" { 171*88d15eacSSasha Smundak gotDiffs = append(gotDiffs, struct{ Name, Data string }{t.Name(), gotDiff}) 172*88d15eacSSasha Smundak } 173*88d15eacSSasha Smundak } else { 174*88d15eacSSasha Smundak wantDiff := wantDiffs[t.Name()] 175*88d15eacSSasha Smundak if diff := cmp.Diff(wantDiff, gotDiff); diff != "" { 176*88d15eacSSasha Smundak t.Fatalf("Diff:\ngot:\n%s\nwant:\n%s\ndiff: (-want +got)\n%s\nreason: %v", gotDiff, wantDiff, diff, tt.reason) 177*88d15eacSSasha Smundak } 178*88d15eacSSasha Smundak } 179*88d15eacSSasha Smundak gotEqual := gotDiff == "" 180*88d15eacSSasha Smundak if gotEqual != tt.wantEqual { 181*88d15eacSSasha Smundak t.Fatalf("Equal = %v, want %v\nreason: %v", gotEqual, tt.wantEqual, tt.reason) 182*88d15eacSSasha Smundak } 183*88d15eacSSasha Smundak default: 184*88d15eacSSasha Smundak if !strings.Contains(gotPanic, tt.wantPanic) { 185*88d15eacSSasha Smundak t.Fatalf("panic message:\ngot: %s\nwant: %s\nreason: %v", gotPanic, tt.wantPanic, tt.reason) 186*88d15eacSSasha Smundak } 187*88d15eacSSasha Smundak } 188*88d15eacSSasha Smundak }) 189*88d15eacSSasha Smundak } 190*88d15eacSSasha Smundak 191*88d15eacSSasha Smundak if *update { 192*88d15eacSSasha Smundak mustFormatGolden(goldenFile, gotDiffs) 193*88d15eacSSasha Smundak } 194*88d15eacSSasha Smundak} 195*88d15eacSSasha Smundak 196*88d15eacSSasha Smundakfunc comparerTests() []test { 197*88d15eacSSasha Smundak const label = "Comparer" 198*88d15eacSSasha Smundak 199*88d15eacSSasha Smundak type Iface1 interface { 200*88d15eacSSasha Smundak Method() 201*88d15eacSSasha Smundak } 202*88d15eacSSasha Smundak type Iface2 interface { 203*88d15eacSSasha Smundak Method() 204*88d15eacSSasha Smundak } 205*88d15eacSSasha Smundak 206*88d15eacSSasha Smundak type tarHeader struct { 207*88d15eacSSasha Smundak Name string 208*88d15eacSSasha Smundak Mode int64 209*88d15eacSSasha Smundak Uid int 210*88d15eacSSasha Smundak Gid int 211*88d15eacSSasha Smundak Size int64 212*88d15eacSSasha Smundak ModTime time.Time 213*88d15eacSSasha Smundak Typeflag byte 214*88d15eacSSasha Smundak Linkname string 215*88d15eacSSasha Smundak Uname string 216*88d15eacSSasha Smundak Gname string 217*88d15eacSSasha Smundak Devmajor int64 218*88d15eacSSasha Smundak Devminor int64 219*88d15eacSSasha Smundak AccessTime time.Time 220*88d15eacSSasha Smundak ChangeTime time.Time 221*88d15eacSSasha Smundak Xattrs map[string]string 222*88d15eacSSasha Smundak } 223*88d15eacSSasha Smundak 224*88d15eacSSasha Smundak type namedWithUnexported struct { 225*88d15eacSSasha Smundak unexported string 226*88d15eacSSasha Smundak } 227*88d15eacSSasha Smundak 228*88d15eacSSasha Smundak makeTarHeaders := func(tf byte) (hs []tarHeader) { 229*88d15eacSSasha Smundak for i := 0; i < 5; i++ { 230*88d15eacSSasha Smundak hs = append(hs, tarHeader{ 231*88d15eacSSasha Smundak Name: fmt.Sprintf("some/dummy/test/file%d", i), 232*88d15eacSSasha Smundak Mode: 0664, Uid: i * 1000, Gid: i * 1000, Size: 1 << uint(i), 233*88d15eacSSasha Smundak ModTime: now.Add(time.Duration(i) * time.Hour), 234*88d15eacSSasha Smundak Uname: "user", Gname: "group", 235*88d15eacSSasha Smundak Typeflag: tf, 236*88d15eacSSasha Smundak }) 237*88d15eacSSasha Smundak } 238*88d15eacSSasha Smundak return hs 239*88d15eacSSasha Smundak } 240*88d15eacSSasha Smundak 241*88d15eacSSasha Smundak return []test{{ 242*88d15eacSSasha Smundak label: label + "/Nil", 243*88d15eacSSasha Smundak x: nil, 244*88d15eacSSasha Smundak y: nil, 245*88d15eacSSasha Smundak wantEqual: true, 246*88d15eacSSasha Smundak reason: "nils are equal", 247*88d15eacSSasha Smundak }, { 248*88d15eacSSasha Smundak label: label + "/Integer", 249*88d15eacSSasha Smundak x: 1, 250*88d15eacSSasha Smundak y: 1, 251*88d15eacSSasha Smundak wantEqual: true, 252*88d15eacSSasha Smundak reason: "identical integers are equal", 253*88d15eacSSasha Smundak }, { 254*88d15eacSSasha Smundak label: label + "/UnfilteredIgnore", 255*88d15eacSSasha Smundak x: 1, 256*88d15eacSSasha Smundak y: 1, 257*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Ignore()}, 258*88d15eacSSasha Smundak wantPanic: "cannot use an unfiltered option", 259*88d15eacSSasha Smundak reason: "unfiltered options are functionally useless", 260*88d15eacSSasha Smundak }, { 261*88d15eacSSasha Smundak label: label + "/UnfilteredCompare", 262*88d15eacSSasha Smundak x: 1, 263*88d15eacSSasha Smundak y: 1, 264*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(_, _ interface{}) bool { return true })}, 265*88d15eacSSasha Smundak wantPanic: "cannot use an unfiltered option", 266*88d15eacSSasha Smundak reason: "unfiltered options are functionally useless", 267*88d15eacSSasha Smundak }, { 268*88d15eacSSasha Smundak label: label + "/UnfilteredTransform", 269*88d15eacSSasha Smundak x: 1, 270*88d15eacSSasha Smundak y: 1, 271*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Transformer("λ", func(x interface{}) interface{} { return x })}, 272*88d15eacSSasha Smundak wantPanic: "cannot use an unfiltered option", 273*88d15eacSSasha Smundak reason: "unfiltered options are functionally useless", 274*88d15eacSSasha Smundak }, { 275*88d15eacSSasha Smundak label: label + "/AmbiguousOptions", 276*88d15eacSSasha Smundak x: 1, 277*88d15eacSSasha Smundak y: 1, 278*88d15eacSSasha Smundak opts: []cmp.Option{ 279*88d15eacSSasha Smundak cmp.Comparer(func(x, y int) bool { return true }), 280*88d15eacSSasha Smundak cmp.Transformer("λ", func(x int) float64 { return float64(x) }), 281*88d15eacSSasha Smundak }, 282*88d15eacSSasha Smundak wantPanic: "ambiguous set of applicable options", 283*88d15eacSSasha Smundak reason: "both options apply on int, leading to ambiguity", 284*88d15eacSSasha Smundak }, { 285*88d15eacSSasha Smundak label: label + "/IgnorePrecedence", 286*88d15eacSSasha Smundak x: 1, 287*88d15eacSSasha Smundak y: 1, 288*88d15eacSSasha Smundak opts: []cmp.Option{ 289*88d15eacSSasha Smundak cmp.FilterPath(func(p cmp.Path) bool { 290*88d15eacSSasha Smundak return len(p) > 0 && p[len(p)-1].Type().Kind() == reflect.Int 291*88d15eacSSasha Smundak }, cmp.Options{cmp.Ignore(), cmp.Ignore(), cmp.Ignore()}), 292*88d15eacSSasha Smundak cmp.Comparer(func(x, y int) bool { return true }), 293*88d15eacSSasha Smundak cmp.Transformer("λ", func(x int) float64 { return float64(x) }), 294*88d15eacSSasha Smundak }, 295*88d15eacSSasha Smundak wantEqual: true, 296*88d15eacSSasha Smundak reason: "ignore takes precedence over other options", 297*88d15eacSSasha Smundak }, { 298*88d15eacSSasha Smundak label: label + "/UnknownOption", 299*88d15eacSSasha Smundak opts: []cmp.Option{struct{ cmp.Option }{}}, 300*88d15eacSSasha Smundak wantPanic: "unknown option", 301*88d15eacSSasha Smundak reason: "use of unknown option should panic", 302*88d15eacSSasha Smundak }, { 303*88d15eacSSasha Smundak label: label + "/StructEqual", 304*88d15eacSSasha Smundak x: struct{ A, B, C int }{1, 2, 3}, 305*88d15eacSSasha Smundak y: struct{ A, B, C int }{1, 2, 3}, 306*88d15eacSSasha Smundak wantEqual: true, 307*88d15eacSSasha Smundak reason: "struct comparison with all equal fields", 308*88d15eacSSasha Smundak }, { 309*88d15eacSSasha Smundak label: label + "/StructInequal", 310*88d15eacSSasha Smundak x: struct{ A, B, C int }{1, 2, 3}, 311*88d15eacSSasha Smundak y: struct{ A, B, C int }{1, 2, 4}, 312*88d15eacSSasha Smundak wantEqual: false, 313*88d15eacSSasha Smundak reason: "struct comparison with inequal C field", 314*88d15eacSSasha Smundak }, { 315*88d15eacSSasha Smundak label: label + "/StructUnexported", 316*88d15eacSSasha Smundak x: struct{ a, b, c int }{1, 2, 3}, 317*88d15eacSSasha Smundak y: struct{ a, b, c int }{1, 2, 4}, 318*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 319*88d15eacSSasha Smundak reason: "unexported fields result in a panic by default", 320*88d15eacSSasha Smundak }, { 321*88d15eacSSasha Smundak label: label + "/PointerStructEqual", 322*88d15eacSSasha Smundak x: &struct{ A *int }{newInt(4)}, 323*88d15eacSSasha Smundak y: &struct{ A *int }{newInt(4)}, 324*88d15eacSSasha Smundak wantEqual: true, 325*88d15eacSSasha Smundak reason: "comparison of pointer to struct with equal A field", 326*88d15eacSSasha Smundak }, { 327*88d15eacSSasha Smundak label: label + "/PointerStructInequal", 328*88d15eacSSasha Smundak x: &struct{ A *int }{newInt(4)}, 329*88d15eacSSasha Smundak y: &struct{ A *int }{newInt(5)}, 330*88d15eacSSasha Smundak wantEqual: false, 331*88d15eacSSasha Smundak reason: "comparison of pointer to struct with inequal A field", 332*88d15eacSSasha Smundak }, { 333*88d15eacSSasha Smundak label: label + "/PointerStructTrueComparer", 334*88d15eacSSasha Smundak x: &struct{ A *int }{newInt(4)}, 335*88d15eacSSasha Smundak y: &struct{ A *int }{newInt(5)}, 336*88d15eacSSasha Smundak opts: []cmp.Option{ 337*88d15eacSSasha Smundak cmp.Comparer(func(x, y int) bool { return true }), 338*88d15eacSSasha Smundak }, 339*88d15eacSSasha Smundak wantEqual: true, 340*88d15eacSSasha Smundak reason: "comparison of pointer to struct with inequal A field, but treated as equal with always equal comparer", 341*88d15eacSSasha Smundak }, { 342*88d15eacSSasha Smundak label: label + "/PointerStructNonNilComparer", 343*88d15eacSSasha Smundak x: &struct{ A *int }{newInt(4)}, 344*88d15eacSSasha Smundak y: &struct{ A *int }{newInt(5)}, 345*88d15eacSSasha Smundak opts: []cmp.Option{ 346*88d15eacSSasha Smundak cmp.Comparer(func(x, y *int) bool { return x != nil && y != nil }), 347*88d15eacSSasha Smundak }, 348*88d15eacSSasha Smundak wantEqual: true, 349*88d15eacSSasha Smundak reason: "comparison of pointer to struct with inequal A field, but treated as equal with comparer checking pointers for nilness", 350*88d15eacSSasha Smundak }, { 351*88d15eacSSasha Smundak label: label + "/StructNestedPointerEqual", 352*88d15eacSSasha Smundak x: &struct{ R *bytes.Buffer }{}, 353*88d15eacSSasha Smundak y: &struct{ R *bytes.Buffer }{}, 354*88d15eacSSasha Smundak wantEqual: true, 355*88d15eacSSasha Smundak reason: "equal since both pointers in R field are nil", 356*88d15eacSSasha Smundak }, { 357*88d15eacSSasha Smundak label: label + "/StructNestedPointerInequal", 358*88d15eacSSasha Smundak x: &struct{ R *bytes.Buffer }{new(bytes.Buffer)}, 359*88d15eacSSasha Smundak y: &struct{ R *bytes.Buffer }{}, 360*88d15eacSSasha Smundak wantEqual: false, 361*88d15eacSSasha Smundak reason: "inequal since R field is inequal", 362*88d15eacSSasha Smundak }, { 363*88d15eacSSasha Smundak label: label + "/StructNestedPointerTrueComparer", 364*88d15eacSSasha Smundak x: &struct{ R *bytes.Buffer }{new(bytes.Buffer)}, 365*88d15eacSSasha Smundak y: &struct{ R *bytes.Buffer }{}, 366*88d15eacSSasha Smundak opts: []cmp.Option{ 367*88d15eacSSasha Smundak cmp.Comparer(func(x, y io.Reader) bool { return true }), 368*88d15eacSSasha Smundak }, 369*88d15eacSSasha Smundak wantEqual: true, 370*88d15eacSSasha Smundak reason: "equal despite inequal R field values since the comparer always reports true", 371*88d15eacSSasha Smundak }, { 372*88d15eacSSasha Smundak label: label + "/StructNestedValueUnexportedPanic1", 373*88d15eacSSasha Smundak x: &struct{ R bytes.Buffer }{}, 374*88d15eacSSasha Smundak y: &struct{ R bytes.Buffer }{}, 375*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 376*88d15eacSSasha Smundak reason: "bytes.Buffer contains unexported fields", 377*88d15eacSSasha Smundak }, { 378*88d15eacSSasha Smundak label: label + "/StructNestedValueUnexportedPanic2", 379*88d15eacSSasha Smundak x: &struct{ R bytes.Buffer }{}, 380*88d15eacSSasha Smundak y: &struct{ R bytes.Buffer }{}, 381*88d15eacSSasha Smundak opts: []cmp.Option{ 382*88d15eacSSasha Smundak cmp.Comparer(func(x, y io.Reader) bool { return true }), 383*88d15eacSSasha Smundak }, 384*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 385*88d15eacSSasha Smundak reason: "bytes.Buffer value does not implement io.Reader", 386*88d15eacSSasha Smundak }, { 387*88d15eacSSasha Smundak label: label + "/StructNestedValueEqual", 388*88d15eacSSasha Smundak x: &struct{ R bytes.Buffer }{}, 389*88d15eacSSasha Smundak y: &struct{ R bytes.Buffer }{}, 390*88d15eacSSasha Smundak opts: []cmp.Option{ 391*88d15eacSSasha Smundak cmp.Transformer("Ref", func(x bytes.Buffer) *bytes.Buffer { return &x }), 392*88d15eacSSasha Smundak cmp.Comparer(func(x, y io.Reader) bool { return true }), 393*88d15eacSSasha Smundak }, 394*88d15eacSSasha Smundak wantEqual: true, 395*88d15eacSSasha Smundak reason: "bytes.Buffer pointer due to shallow copy does implement io.Reader", 396*88d15eacSSasha Smundak }, { 397*88d15eacSSasha Smundak label: label + "/RegexpUnexportedPanic", 398*88d15eacSSasha Smundak x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, 399*88d15eacSSasha Smundak y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, 400*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 401*88d15eacSSasha Smundak reason: "regexp.Regexp contains unexported fields", 402*88d15eacSSasha Smundak }, { 403*88d15eacSSasha Smundak label: label + "/RegexpEqual", 404*88d15eacSSasha Smundak x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, 405*88d15eacSSasha Smundak y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, 406*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(x, y *regexp.Regexp) bool { 407*88d15eacSSasha Smundak if x == nil || y == nil { 408*88d15eacSSasha Smundak return x == nil && y == nil 409*88d15eacSSasha Smundak } 410*88d15eacSSasha Smundak return x.String() == y.String() 411*88d15eacSSasha Smundak })}, 412*88d15eacSSasha Smundak wantEqual: true, 413*88d15eacSSasha Smundak reason: "comparer for *regexp.Regexp applied with equal regexp strings", 414*88d15eacSSasha Smundak }, { 415*88d15eacSSasha Smundak label: label + "/RegexpInequal", 416*88d15eacSSasha Smundak x: []*regexp.Regexp{nil, regexp.MustCompile("a*b*c*")}, 417*88d15eacSSasha Smundak y: []*regexp.Regexp{nil, regexp.MustCompile("a*b*d*")}, 418*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(x, y *regexp.Regexp) bool { 419*88d15eacSSasha Smundak if x == nil || y == nil { 420*88d15eacSSasha Smundak return x == nil && y == nil 421*88d15eacSSasha Smundak } 422*88d15eacSSasha Smundak return x.String() == y.String() 423*88d15eacSSasha Smundak })}, 424*88d15eacSSasha Smundak wantEqual: false, 425*88d15eacSSasha Smundak reason: "comparer for *regexp.Regexp applied with inequal regexp strings", 426*88d15eacSSasha Smundak }, { 427*88d15eacSSasha Smundak label: label + "/TriplePointerEqual", 428*88d15eacSSasha Smundak x: func() ***int { 429*88d15eacSSasha Smundak a := 0 430*88d15eacSSasha Smundak b := &a 431*88d15eacSSasha Smundak c := &b 432*88d15eacSSasha Smundak return &c 433*88d15eacSSasha Smundak }(), 434*88d15eacSSasha Smundak y: func() ***int { 435*88d15eacSSasha Smundak a := 0 436*88d15eacSSasha Smundak b := &a 437*88d15eacSSasha Smundak c := &b 438*88d15eacSSasha Smundak return &c 439*88d15eacSSasha Smundak }(), 440*88d15eacSSasha Smundak wantEqual: true, 441*88d15eacSSasha Smundak reason: "three layers of pointers to the same value", 442*88d15eacSSasha Smundak }, { 443*88d15eacSSasha Smundak label: label + "/TriplePointerInequal", 444*88d15eacSSasha Smundak x: func() ***int { 445*88d15eacSSasha Smundak a := 0 446*88d15eacSSasha Smundak b := &a 447*88d15eacSSasha Smundak c := &b 448*88d15eacSSasha Smundak return &c 449*88d15eacSSasha Smundak }(), 450*88d15eacSSasha Smundak y: func() ***int { 451*88d15eacSSasha Smundak a := 1 452*88d15eacSSasha Smundak b := &a 453*88d15eacSSasha Smundak c := &b 454*88d15eacSSasha Smundak return &c 455*88d15eacSSasha Smundak }(), 456*88d15eacSSasha Smundak wantEqual: false, 457*88d15eacSSasha Smundak reason: "three layers of pointers to different values", 458*88d15eacSSasha Smundak }, { 459*88d15eacSSasha Smundak label: label + "/SliceWithDifferingCapacity", 460*88d15eacSSasha Smundak x: []int{1, 2, 3, 4, 5}[:3], 461*88d15eacSSasha Smundak y: []int{1, 2, 3}, 462*88d15eacSSasha Smundak wantEqual: true, 463*88d15eacSSasha Smundak reason: "elements past the slice length are not compared", 464*88d15eacSSasha Smundak }, { 465*88d15eacSSasha Smundak label: label + "/StringerEqual", 466*88d15eacSSasha Smundak x: struct{ fmt.Stringer }{bytes.NewBufferString("hello")}, 467*88d15eacSSasha Smundak y: struct{ fmt.Stringer }{regexp.MustCompile("hello")}, 468*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(x, y fmt.Stringer) bool { return x.String() == y.String() })}, 469*88d15eacSSasha Smundak wantEqual: true, 470*88d15eacSSasha Smundak reason: "comparer for fmt.Stringer used to compare differing types with same string", 471*88d15eacSSasha Smundak }, { 472*88d15eacSSasha Smundak label: label + "/StringerInequal", 473*88d15eacSSasha Smundak x: struct{ fmt.Stringer }{bytes.NewBufferString("hello")}, 474*88d15eacSSasha Smundak y: struct{ fmt.Stringer }{regexp.MustCompile("hello2")}, 475*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(x, y fmt.Stringer) bool { return x.String() == y.String() })}, 476*88d15eacSSasha Smundak wantEqual: false, 477*88d15eacSSasha Smundak reason: "comparer for fmt.Stringer used to compare differing types with different strings", 478*88d15eacSSasha Smundak }, { 479*88d15eacSSasha Smundak label: label + "/DifferingHash", 480*88d15eacSSasha Smundak x: sha256.Sum256([]byte{'a'}), 481*88d15eacSSasha Smundak y: sha256.Sum256([]byte{'b'}), 482*88d15eacSSasha Smundak wantEqual: false, 483*88d15eacSSasha Smundak reason: "hash differs", 484*88d15eacSSasha Smundak }, { 485*88d15eacSSasha Smundak label: label + "/NilStringer", 486*88d15eacSSasha Smundak x: new(fmt.Stringer), 487*88d15eacSSasha Smundak y: nil, 488*88d15eacSSasha Smundak wantEqual: false, 489*88d15eacSSasha Smundak reason: "by default differing types are always inequal", 490*88d15eacSSasha Smundak }, { 491*88d15eacSSasha Smundak label: label + "/TarHeaders", 492*88d15eacSSasha Smundak x: makeTarHeaders('0'), 493*88d15eacSSasha Smundak y: makeTarHeaders('\x00'), 494*88d15eacSSasha Smundak wantEqual: false, 495*88d15eacSSasha Smundak reason: "type flag differs between the headers", 496*88d15eacSSasha Smundak }, { 497*88d15eacSSasha Smundak label: label + "/NonDeterministicComparer", 498*88d15eacSSasha Smundak x: make([]int, 1000), 499*88d15eacSSasha Smundak y: make([]int, 1000), 500*88d15eacSSasha Smundak opts: []cmp.Option{ 501*88d15eacSSasha Smundak cmp.Comparer(func(_, _ int) bool { 502*88d15eacSSasha Smundak return rand.Intn(2) == 0 503*88d15eacSSasha Smundak }), 504*88d15eacSSasha Smundak }, 505*88d15eacSSasha Smundak wantPanic: "non-deterministic or non-symmetric function detected", 506*88d15eacSSasha Smundak reason: "non-deterministic comparer", 507*88d15eacSSasha Smundak }, { 508*88d15eacSSasha Smundak label: label + "/NonDeterministicFilter", 509*88d15eacSSasha Smundak x: make([]int, 1000), 510*88d15eacSSasha Smundak y: make([]int, 1000), 511*88d15eacSSasha Smundak opts: []cmp.Option{ 512*88d15eacSSasha Smundak cmp.FilterValues(func(_, _ int) bool { 513*88d15eacSSasha Smundak return rand.Intn(2) == 0 514*88d15eacSSasha Smundak }, cmp.Ignore()), 515*88d15eacSSasha Smundak }, 516*88d15eacSSasha Smundak wantPanic: "non-deterministic or non-symmetric function detected", 517*88d15eacSSasha Smundak reason: "non-deterministic filter", 518*88d15eacSSasha Smundak }, { 519*88d15eacSSasha Smundak label: label + "/AsymmetricComparer", 520*88d15eacSSasha Smundak x: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 521*88d15eacSSasha Smundak y: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 522*88d15eacSSasha Smundak opts: []cmp.Option{ 523*88d15eacSSasha Smundak cmp.Comparer(func(x, y int) bool { 524*88d15eacSSasha Smundak return x < y 525*88d15eacSSasha Smundak }), 526*88d15eacSSasha Smundak }, 527*88d15eacSSasha Smundak wantPanic: "non-deterministic or non-symmetric function detected", 528*88d15eacSSasha Smundak reason: "asymmetric comparer", 529*88d15eacSSasha Smundak }, { 530*88d15eacSSasha Smundak label: label + "/NonDeterministicTransformer", 531*88d15eacSSasha Smundak x: make([]string, 1000), 532*88d15eacSSasha Smundak y: make([]string, 1000), 533*88d15eacSSasha Smundak opts: []cmp.Option{ 534*88d15eacSSasha Smundak cmp.Transformer("λ", func(x string) int { 535*88d15eacSSasha Smundak return rand.Int() 536*88d15eacSSasha Smundak }), 537*88d15eacSSasha Smundak }, 538*88d15eacSSasha Smundak wantPanic: "non-deterministic function detected", 539*88d15eacSSasha Smundak reason: "non-deterministic transformer", 540*88d15eacSSasha Smundak }, { 541*88d15eacSSasha Smundak label: label + "/IrreflexiveComparison", 542*88d15eacSSasha Smundak x: make([]int, 10), 543*88d15eacSSasha Smundak y: make([]int, 10), 544*88d15eacSSasha Smundak opts: []cmp.Option{ 545*88d15eacSSasha Smundak cmp.Transformer("λ", func(x int) float64 { 546*88d15eacSSasha Smundak return math.NaN() 547*88d15eacSSasha Smundak }), 548*88d15eacSSasha Smundak }, 549*88d15eacSSasha Smundak wantEqual: false, 550*88d15eacSSasha Smundak reason: "dynamic checks should not panic for non-reflexive comparisons", 551*88d15eacSSasha Smundak }, { 552*88d15eacSSasha Smundak label: label + "/StringerMapKey", 553*88d15eacSSasha Smundak x: map[*pb.Stringer]*pb.Stringer{{"hello"}: {"world"}}, 554*88d15eacSSasha Smundak y: map[*pb.Stringer]*pb.Stringer(nil), 555*88d15eacSSasha Smundak wantEqual: false, 556*88d15eacSSasha Smundak reason: "stringer should be used to format the map key", 557*88d15eacSSasha Smundak }, { 558*88d15eacSSasha Smundak label: label + "/StringerBacktick", 559*88d15eacSSasha Smundak x: []*pb.Stringer{{`multi\nline\nline\nline`}}, 560*88d15eacSSasha Smundak wantEqual: false, 561*88d15eacSSasha Smundak reason: "stringer should use backtick quoting if more readable", 562*88d15eacSSasha Smundak }, { 563*88d15eacSSasha Smundak label: label + "/AvoidPanicAssignableConverter", 564*88d15eacSSasha Smundak x: struct{ I Iface2 }{}, 565*88d15eacSSasha Smundak y: struct{ I Iface2 }{}, 566*88d15eacSSasha Smundak opts: []cmp.Option{ 567*88d15eacSSasha Smundak cmp.Comparer(func(x, y Iface1) bool { 568*88d15eacSSasha Smundak return x == nil && y == nil 569*88d15eacSSasha Smundak }), 570*88d15eacSSasha Smundak }, 571*88d15eacSSasha Smundak wantEqual: true, 572*88d15eacSSasha Smundak reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", 573*88d15eacSSasha Smundak }, { 574*88d15eacSSasha Smundak label: label + "/AvoidPanicAssignableTransformer", 575*88d15eacSSasha Smundak x: struct{ I Iface2 }{}, 576*88d15eacSSasha Smundak y: struct{ I Iface2 }{}, 577*88d15eacSSasha Smundak opts: []cmp.Option{ 578*88d15eacSSasha Smundak cmp.Transformer("λ", func(v Iface1) bool { 579*88d15eacSSasha Smundak return v == nil 580*88d15eacSSasha Smundak }), 581*88d15eacSSasha Smundak }, 582*88d15eacSSasha Smundak wantEqual: true, 583*88d15eacSSasha Smundak reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", 584*88d15eacSSasha Smundak }, { 585*88d15eacSSasha Smundak label: label + "/AvoidPanicAssignableFilter", 586*88d15eacSSasha Smundak x: struct{ I Iface2 }{}, 587*88d15eacSSasha Smundak y: struct{ I Iface2 }{}, 588*88d15eacSSasha Smundak opts: []cmp.Option{ 589*88d15eacSSasha Smundak cmp.FilterValues(func(x, y Iface1) bool { 590*88d15eacSSasha Smundak return x == nil && y == nil 591*88d15eacSSasha Smundak }, cmp.Ignore()), 592*88d15eacSSasha Smundak }, 593*88d15eacSSasha Smundak wantEqual: true, 594*88d15eacSSasha Smundak reason: "function call using Go reflection should automatically convert assignable interfaces; see https://golang.org/issues/22143", 595*88d15eacSSasha Smundak }, { 596*88d15eacSSasha Smundak label: label + "/DynamicMap", 597*88d15eacSSasha Smundak x: []interface{}{map[string]interface{}{"avg": 0.278, "hr": 65, "name": "Mark McGwire"}, map[string]interface{}{"avg": 0.288, "hr": 63, "name": "Sammy Sosa"}}, 598*88d15eacSSasha Smundak 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"}}, 599*88d15eacSSasha Smundak wantEqual: false, 600*88d15eacSSasha Smundak reason: "dynamic map with differing types (but semantically equivalent values) should be inequal", 601*88d15eacSSasha Smundak }, { 602*88d15eacSSasha Smundak label: label + "/MapKeyPointer", 603*88d15eacSSasha Smundak x: map[*int]string{ 604*88d15eacSSasha Smundak new(int): "hello", 605*88d15eacSSasha Smundak }, 606*88d15eacSSasha Smundak y: map[*int]string{ 607*88d15eacSSasha Smundak new(int): "world", 608*88d15eacSSasha Smundak }, 609*88d15eacSSasha Smundak wantEqual: false, 610*88d15eacSSasha Smundak reason: "map keys should use shallow (rather than deep) pointer comparison", 611*88d15eacSSasha Smundak }, { 612*88d15eacSSasha Smundak label: label + "/IgnoreSliceElements", 613*88d15eacSSasha Smundak x: [2][]int{ 614*88d15eacSSasha Smundak {0, 0, 0, 1, 2, 3, 0, 0, 4, 5, 6, 7, 8, 0, 9, 0, 0}, 615*88d15eacSSasha Smundak {0, 1, 0, 0, 0, 20}, 616*88d15eacSSasha Smundak }, 617*88d15eacSSasha Smundak y: [2][]int{ 618*88d15eacSSasha Smundak {1, 2, 3, 0, 4, 5, 6, 7, 0, 8, 9, 0, 0, 0}, 619*88d15eacSSasha Smundak {0, 0, 1, 2, 0, 0, 0}, 620*88d15eacSSasha Smundak }, 621*88d15eacSSasha Smundak opts: []cmp.Option{ 622*88d15eacSSasha Smundak cmp.FilterPath(func(p cmp.Path) bool { 623*88d15eacSSasha Smundak vx, vy := p.Last().Values() 624*88d15eacSSasha Smundak if vx.IsValid() && vx.Kind() == reflect.Int && vx.Int() == 0 { 625*88d15eacSSasha Smundak return true 626*88d15eacSSasha Smundak } 627*88d15eacSSasha Smundak if vy.IsValid() && vy.Kind() == reflect.Int && vy.Int() == 0 { 628*88d15eacSSasha Smundak return true 629*88d15eacSSasha Smundak } 630*88d15eacSSasha Smundak return false 631*88d15eacSSasha Smundak }, cmp.Ignore()), 632*88d15eacSSasha Smundak }, 633*88d15eacSSasha Smundak wantEqual: false, 634*88d15eacSSasha Smundak reason: "all zero slice elements are ignored (even if missing)", 635*88d15eacSSasha Smundak }, { 636*88d15eacSSasha Smundak label: label + "/IgnoreMapEntries", 637*88d15eacSSasha Smundak x: [2]map[string]int{ 638*88d15eacSSasha Smundak {"ignore1": 0, "ignore2": 0, "keep1": 1, "keep2": 2, "KEEP3": 3, "IGNORE3": 0}, 639*88d15eacSSasha Smundak {"keep1": 1, "ignore1": 0}, 640*88d15eacSSasha Smundak }, 641*88d15eacSSasha Smundak y: [2]map[string]int{ 642*88d15eacSSasha Smundak {"ignore1": 0, "ignore3": 0, "ignore4": 0, "keep1": 1, "keep2": 2, "KEEP3": 3}, 643*88d15eacSSasha Smundak {"keep1": 1, "keep2": 2, "ignore2": 0}, 644*88d15eacSSasha Smundak }, 645*88d15eacSSasha Smundak opts: []cmp.Option{ 646*88d15eacSSasha Smundak cmp.FilterPath(func(p cmp.Path) bool { 647*88d15eacSSasha Smundak vx, vy := p.Last().Values() 648*88d15eacSSasha Smundak if vx.IsValid() && vx.Kind() == reflect.Int && vx.Int() == 0 { 649*88d15eacSSasha Smundak return true 650*88d15eacSSasha Smundak } 651*88d15eacSSasha Smundak if vy.IsValid() && vy.Kind() == reflect.Int && vy.Int() == 0 { 652*88d15eacSSasha Smundak return true 653*88d15eacSSasha Smundak } 654*88d15eacSSasha Smundak return false 655*88d15eacSSasha Smundak }, cmp.Ignore()), 656*88d15eacSSasha Smundak }, 657*88d15eacSSasha Smundak wantEqual: false, 658*88d15eacSSasha Smundak reason: "all zero map entries are ignored (even if missing)", 659*88d15eacSSasha Smundak }, { 660*88d15eacSSasha Smundak label: label + "/PanicUnexportedNamed", 661*88d15eacSSasha Smundak x: namedWithUnexported{unexported: "x"}, 662*88d15eacSSasha Smundak y: namedWithUnexported{unexported: "y"}, 663*88d15eacSSasha Smundak wantPanic: strconv.Quote(reflect.TypeOf(namedWithUnexported{}).PkgPath()) + ".namedWithUnexported", 664*88d15eacSSasha Smundak reason: "panic on named struct type with unexported field", 665*88d15eacSSasha Smundak }, { 666*88d15eacSSasha Smundak label: label + "/PanicUnexportedUnnamed", 667*88d15eacSSasha Smundak x: struct{ a int }{}, 668*88d15eacSSasha Smundak y: struct{ a int }{}, 669*88d15eacSSasha Smundak wantPanic: strconv.Quote(reflect.TypeOf(namedWithUnexported{}).PkgPath()) + ".(struct { a int })", 670*88d15eacSSasha Smundak reason: "panic on unnamed struct type with unexported field", 671*88d15eacSSasha Smundak }, { 672*88d15eacSSasha Smundak label: label + "/UnaddressableStruct", 673*88d15eacSSasha Smundak x: struct{ s fmt.Stringer }{new(bytes.Buffer)}, 674*88d15eacSSasha Smundak y: struct{ s fmt.Stringer }{nil}, 675*88d15eacSSasha Smundak opts: []cmp.Option{ 676*88d15eacSSasha Smundak cmp.AllowUnexported(struct{ s fmt.Stringer }{}), 677*88d15eacSSasha Smundak cmp.FilterPath(func(p cmp.Path) bool { 678*88d15eacSSasha Smundak if _, ok := p.Last().(cmp.StructField); !ok { 679*88d15eacSSasha Smundak return false 680*88d15eacSSasha Smundak } 681*88d15eacSSasha Smundak 682*88d15eacSSasha Smundak t := p.Index(-1).Type() 683*88d15eacSSasha Smundak vx, vy := p.Index(-1).Values() 684*88d15eacSSasha Smundak pvx, pvy := p.Index(-2).Values() 685*88d15eacSSasha Smundak switch { 686*88d15eacSSasha Smundak case vx.Type() != t: 687*88d15eacSSasha Smundak panic(fmt.Sprintf("inconsistent type: %v != %v", vx.Type(), t)) 688*88d15eacSSasha Smundak case vy.Type() != t: 689*88d15eacSSasha Smundak panic(fmt.Sprintf("inconsistent type: %v != %v", vy.Type(), t)) 690*88d15eacSSasha Smundak case vx.CanAddr() != pvx.CanAddr(): 691*88d15eacSSasha Smundak panic(fmt.Sprintf("inconsistent addressability: %v != %v", vx.CanAddr(), pvx.CanAddr())) 692*88d15eacSSasha Smundak case vy.CanAddr() != pvy.CanAddr(): 693*88d15eacSSasha Smundak panic(fmt.Sprintf("inconsistent addressability: %v != %v", vy.CanAddr(), pvy.CanAddr())) 694*88d15eacSSasha Smundak } 695*88d15eacSSasha Smundak return true 696*88d15eacSSasha Smundak }, cmp.Ignore()), 697*88d15eacSSasha Smundak }, 698*88d15eacSSasha Smundak wantEqual: true, 699*88d15eacSSasha Smundak reason: "verify that exporter does not leak implementation details", 700*88d15eacSSasha Smundak }, { 701*88d15eacSSasha Smundak label: label + "/ErrorPanic", 702*88d15eacSSasha Smundak x: io.EOF, 703*88d15eacSSasha Smundak y: io.EOF, 704*88d15eacSSasha Smundak wantPanic: "consider using cmpopts.EquateErrors", 705*88d15eacSSasha Smundak reason: "suggest cmpopts.EquateErrors when accessing unexported fields of error types", 706*88d15eacSSasha Smundak }, { 707*88d15eacSSasha Smundak label: label + "/ErrorEqual", 708*88d15eacSSasha Smundak x: io.EOF, 709*88d15eacSSasha Smundak y: io.EOF, 710*88d15eacSSasha Smundak opts: []cmp.Option{cmpopts.EquateErrors()}, 711*88d15eacSSasha Smundak wantEqual: true, 712*88d15eacSSasha Smundak reason: "cmpopts.EquateErrors should equate these two errors as sentinel values", 713*88d15eacSSasha Smundak }} 714*88d15eacSSasha Smundak} 715*88d15eacSSasha Smundak 716*88d15eacSSasha Smundakfunc transformerTests() []test { 717*88d15eacSSasha Smundak type StringBytes struct { 718*88d15eacSSasha Smundak String string 719*88d15eacSSasha Smundak Bytes []byte 720*88d15eacSSasha Smundak } 721*88d15eacSSasha Smundak 722*88d15eacSSasha Smundak const label = "Transformer" 723*88d15eacSSasha Smundak 724*88d15eacSSasha Smundak transformOnce := func(name string, f interface{}) cmp.Option { 725*88d15eacSSasha Smundak xform := cmp.Transformer(name, f) 726*88d15eacSSasha Smundak return cmp.FilterPath(func(p cmp.Path) bool { 727*88d15eacSSasha Smundak for _, ps := range p { 728*88d15eacSSasha Smundak if tr, ok := ps.(cmp.Transform); ok && tr.Option() == xform { 729*88d15eacSSasha Smundak return false 730*88d15eacSSasha Smundak } 731*88d15eacSSasha Smundak } 732*88d15eacSSasha Smundak return true 733*88d15eacSSasha Smundak }, xform) 734*88d15eacSSasha Smundak } 735*88d15eacSSasha Smundak 736*88d15eacSSasha Smundak return []test{{ 737*88d15eacSSasha Smundak label: label + "/Uints", 738*88d15eacSSasha Smundak x: uint8(0), 739*88d15eacSSasha Smundak y: uint8(1), 740*88d15eacSSasha Smundak opts: []cmp.Option{ 741*88d15eacSSasha Smundak cmp.Transformer("λ", func(in uint8) uint16 { return uint16(in) }), 742*88d15eacSSasha Smundak cmp.Transformer("λ", func(in uint16) uint32 { return uint32(in) }), 743*88d15eacSSasha Smundak cmp.Transformer("λ", func(in uint32) uint64 { return uint64(in) }), 744*88d15eacSSasha Smundak }, 745*88d15eacSSasha Smundak wantEqual: false, 746*88d15eacSSasha Smundak reason: "transform uint8 -> uint16 -> uint32 -> uint64", 747*88d15eacSSasha Smundak }, { 748*88d15eacSSasha Smundak label: label + "/Ambiguous", 749*88d15eacSSasha Smundak x: 0, 750*88d15eacSSasha Smundak y: 1, 751*88d15eacSSasha Smundak opts: []cmp.Option{ 752*88d15eacSSasha Smundak cmp.Transformer("λ", func(in int) int { return in / 2 }), 753*88d15eacSSasha Smundak cmp.Transformer("λ", func(in int) int { return in }), 754*88d15eacSSasha Smundak }, 755*88d15eacSSasha Smundak wantPanic: "ambiguous set of applicable options", 756*88d15eacSSasha Smundak reason: "both transformers apply on int", 757*88d15eacSSasha Smundak }, { 758*88d15eacSSasha Smundak label: label + "/Filtered", 759*88d15eacSSasha Smundak x: []int{0, -5, 0, -1}, 760*88d15eacSSasha Smundak y: []int{1, 3, 0, -5}, 761*88d15eacSSasha Smundak opts: []cmp.Option{ 762*88d15eacSSasha Smundak cmp.FilterValues( 763*88d15eacSSasha Smundak func(x, y int) bool { return x+y >= 0 }, 764*88d15eacSSasha Smundak cmp.Transformer("λ", func(in int) int64 { return int64(in / 2) }), 765*88d15eacSSasha Smundak ), 766*88d15eacSSasha Smundak cmp.FilterValues( 767*88d15eacSSasha Smundak func(x, y int) bool { return x+y < 0 }, 768*88d15eacSSasha Smundak cmp.Transformer("λ", func(in int) int64 { return int64(in) }), 769*88d15eacSSasha Smundak ), 770*88d15eacSSasha Smundak }, 771*88d15eacSSasha Smundak wantEqual: false, 772*88d15eacSSasha Smundak reason: "disjoint transformers filtered based on the values", 773*88d15eacSSasha Smundak }, { 774*88d15eacSSasha Smundak label: label + "/DisjointOutput", 775*88d15eacSSasha Smundak x: 0, 776*88d15eacSSasha Smundak y: 1, 777*88d15eacSSasha Smundak opts: []cmp.Option{ 778*88d15eacSSasha Smundak cmp.Transformer("λ", func(in int) interface{} { 779*88d15eacSSasha Smundak if in == 0 { 780*88d15eacSSasha Smundak return "zero" 781*88d15eacSSasha Smundak } 782*88d15eacSSasha Smundak return float64(in) 783*88d15eacSSasha Smundak }), 784*88d15eacSSasha Smundak }, 785*88d15eacSSasha Smundak wantEqual: false, 786*88d15eacSSasha Smundak reason: "output type differs based on input value", 787*88d15eacSSasha Smundak }, { 788*88d15eacSSasha Smundak label: label + "/JSON", 789*88d15eacSSasha Smundak x: `{ 790*88d15eacSSasha Smundak "firstName": "John", 791*88d15eacSSasha Smundak "lastName": "Smith", 792*88d15eacSSasha Smundak "age": 25, 793*88d15eacSSasha Smundak "isAlive": true, 794*88d15eacSSasha Smundak "address": { 795*88d15eacSSasha Smundak "city": "Los Angeles", 796*88d15eacSSasha Smundak "postalCode": "10021-3100", 797*88d15eacSSasha Smundak "state": "CA", 798*88d15eacSSasha Smundak "streetAddress": "21 2nd Street" 799*88d15eacSSasha Smundak }, 800*88d15eacSSasha Smundak "phoneNumbers": [{ 801*88d15eacSSasha Smundak "type": "home", 802*88d15eacSSasha Smundak "number": "212 555-4321" 803*88d15eacSSasha Smundak },{ 804*88d15eacSSasha Smundak "type": "office", 805*88d15eacSSasha Smundak "number": "646 555-4567" 806*88d15eacSSasha Smundak },{ 807*88d15eacSSasha Smundak "number": "123 456-7890", 808*88d15eacSSasha Smundak "type": "mobile" 809*88d15eacSSasha Smundak }], 810*88d15eacSSasha Smundak "children": [] 811*88d15eacSSasha Smundak }`, 812*88d15eacSSasha Smundak y: `{"firstName":"John","lastName":"Smith","isAlive":true,"age":25, 813*88d15eacSSasha Smundak "address":{"streetAddress":"21 2nd Street","city":"New York", 814*88d15eacSSasha Smundak "state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home", 815*88d15eacSSasha Smundak "number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{ 816*88d15eacSSasha Smundak "type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`, 817*88d15eacSSasha Smundak opts: []cmp.Option{ 818*88d15eacSSasha Smundak transformOnce("ParseJSON", func(s string) (m map[string]interface{}) { 819*88d15eacSSasha Smundak if err := json.Unmarshal([]byte(s), &m); err != nil { 820*88d15eacSSasha Smundak panic(err) 821*88d15eacSSasha Smundak } 822*88d15eacSSasha Smundak return m 823*88d15eacSSasha Smundak }), 824*88d15eacSSasha Smundak }, 825*88d15eacSSasha Smundak wantEqual: false, 826*88d15eacSSasha Smundak reason: "transformer used to parse JSON input", 827*88d15eacSSasha Smundak }, { 828*88d15eacSSasha Smundak label: label + "/AcyclicString", 829*88d15eacSSasha Smundak x: StringBytes{String: "some\nmulti\nLine\nstring", Bytes: []byte("some\nmulti\nline\nbytes")}, 830*88d15eacSSasha Smundak y: StringBytes{String: "some\nmulti\nline\nstring", Bytes: []byte("some\nmulti\nline\nBytes")}, 831*88d15eacSSasha Smundak opts: []cmp.Option{ 832*88d15eacSSasha Smundak transformOnce("SplitString", func(s string) []string { return strings.Split(s, "\n") }), 833*88d15eacSSasha Smundak transformOnce("SplitBytes", func(b []byte) [][]byte { return bytes.Split(b, []byte("\n")) }), 834*88d15eacSSasha Smundak }, 835*88d15eacSSasha Smundak wantEqual: false, 836*88d15eacSSasha Smundak reason: "string -> []string and []byte -> [][]byte transformer only applied once", 837*88d15eacSSasha Smundak }, { 838*88d15eacSSasha Smundak label: label + "/CyclicString", 839*88d15eacSSasha Smundak x: "a\nb\nc\n", 840*88d15eacSSasha Smundak y: "a\nb\nc\n", 841*88d15eacSSasha Smundak opts: []cmp.Option{ 842*88d15eacSSasha Smundak cmp.Transformer("SplitLines", func(s string) []string { return strings.Split(s, "\n") }), 843*88d15eacSSasha Smundak }, 844*88d15eacSSasha Smundak wantPanic: "recursive set of Transformers detected", 845*88d15eacSSasha Smundak reason: "cyclic transformation from string -> []string -> string", 846*88d15eacSSasha Smundak }, { 847*88d15eacSSasha Smundak label: label + "/CyclicComplex", 848*88d15eacSSasha Smundak x: complex64(0), 849*88d15eacSSasha Smundak y: complex64(0), 850*88d15eacSSasha Smundak opts: []cmp.Option{ 851*88d15eacSSasha Smundak cmp.Transformer("T1", func(x complex64) complex128 { return complex128(x) }), 852*88d15eacSSasha Smundak cmp.Transformer("T2", func(x complex128) [2]float64 { return [2]float64{real(x), imag(x)} }), 853*88d15eacSSasha Smundak cmp.Transformer("T3", func(x float64) complex64 { return complex64(complex(x, 0)) }), 854*88d15eacSSasha Smundak }, 855*88d15eacSSasha Smundak wantPanic: "recursive set of Transformers detected", 856*88d15eacSSasha Smundak reason: "cyclic transformation from complex64 -> complex128 -> [2]float64 -> complex64", 857*88d15eacSSasha Smundak }} 858*88d15eacSSasha Smundak} 859*88d15eacSSasha Smundak 860*88d15eacSSasha Smundakfunc reporterTests() []test { 861*88d15eacSSasha Smundak const label = "Reporter" 862*88d15eacSSasha Smundak 863*88d15eacSSasha Smundak type ( 864*88d15eacSSasha Smundak MyString string 865*88d15eacSSasha Smundak MyByte byte 866*88d15eacSSasha Smundak MyBytes []byte 867*88d15eacSSasha Smundak MyInt int8 868*88d15eacSSasha Smundak MyInts []int8 869*88d15eacSSasha Smundak MyUint int16 870*88d15eacSSasha Smundak MyUints []int16 871*88d15eacSSasha Smundak MyFloat float32 872*88d15eacSSasha Smundak MyFloats []float32 873*88d15eacSSasha Smundak MyComposite struct { 874*88d15eacSSasha Smundak StringA string 875*88d15eacSSasha Smundak StringB MyString 876*88d15eacSSasha Smundak BytesA []byte 877*88d15eacSSasha Smundak BytesB []MyByte 878*88d15eacSSasha Smundak BytesC MyBytes 879*88d15eacSSasha Smundak IntsA []int8 880*88d15eacSSasha Smundak IntsB []MyInt 881*88d15eacSSasha Smundak IntsC MyInts 882*88d15eacSSasha Smundak UintsA []uint16 883*88d15eacSSasha Smundak UintsB []MyUint 884*88d15eacSSasha Smundak UintsC MyUints 885*88d15eacSSasha Smundak FloatsA []float32 886*88d15eacSSasha Smundak FloatsB []MyFloat 887*88d15eacSSasha Smundak FloatsC MyFloats 888*88d15eacSSasha Smundak } 889*88d15eacSSasha Smundak PointerString *string 890*88d15eacSSasha Smundak ) 891*88d15eacSSasha Smundak 892*88d15eacSSasha Smundak return []test{{ 893*88d15eacSSasha Smundak label: label + "/PanicStringer", 894*88d15eacSSasha Smundak x: struct{ X fmt.Stringer }{struct{ fmt.Stringer }{nil}}, 895*88d15eacSSasha Smundak y: struct{ X fmt.Stringer }{bytes.NewBuffer(nil)}, 896*88d15eacSSasha Smundak wantEqual: false, 897*88d15eacSSasha Smundak reason: "panic from fmt.Stringer should not crash the reporter", 898*88d15eacSSasha Smundak }, { 899*88d15eacSSasha Smundak label: label + "/PanicError", 900*88d15eacSSasha Smundak x: struct{ X error }{struct{ error }{nil}}, 901*88d15eacSSasha Smundak y: struct{ X error }{errors.New("")}, 902*88d15eacSSasha Smundak wantEqual: false, 903*88d15eacSSasha Smundak reason: "panic from error should not crash the reporter", 904*88d15eacSSasha Smundak }, { 905*88d15eacSSasha Smundak label: label + "/AmbiguousType", 906*88d15eacSSasha Smundak x: foo1.Bar{}, 907*88d15eacSSasha Smundak y: foo2.Bar{}, 908*88d15eacSSasha Smundak wantEqual: false, 909*88d15eacSSasha Smundak reason: "reporter should display the qualified type name to disambiguate between the two values", 910*88d15eacSSasha Smundak }, { 911*88d15eacSSasha Smundak label: label + "/AmbiguousPointer", 912*88d15eacSSasha Smundak x: newInt(0), 913*88d15eacSSasha Smundak y: newInt(0), 914*88d15eacSSasha Smundak opts: []cmp.Option{ 915*88d15eacSSasha Smundak cmp.Comparer(func(x, y *int) bool { return x == y }), 916*88d15eacSSasha Smundak }, 917*88d15eacSSasha Smundak wantEqual: false, 918*88d15eacSSasha Smundak reason: "reporter should display the address to disambiguate between the two values", 919*88d15eacSSasha Smundak }, { 920*88d15eacSSasha Smundak label: label + "/AmbiguousPointerStruct", 921*88d15eacSSasha Smundak x: struct{ I *int }{newInt(0)}, 922*88d15eacSSasha Smundak y: struct{ I *int }{newInt(0)}, 923*88d15eacSSasha Smundak opts: []cmp.Option{ 924*88d15eacSSasha Smundak cmp.Comparer(func(x, y *int) bool { return x == y }), 925*88d15eacSSasha Smundak }, 926*88d15eacSSasha Smundak wantEqual: false, 927*88d15eacSSasha Smundak reason: "reporter should display the address to disambiguate between the two struct fields", 928*88d15eacSSasha Smundak }, { 929*88d15eacSSasha Smundak label: label + "/AmbiguousPointerSlice", 930*88d15eacSSasha Smundak x: []*int{newInt(0)}, 931*88d15eacSSasha Smundak y: []*int{newInt(0)}, 932*88d15eacSSasha Smundak opts: []cmp.Option{ 933*88d15eacSSasha Smundak cmp.Comparer(func(x, y *int) bool { return x == y }), 934*88d15eacSSasha Smundak }, 935*88d15eacSSasha Smundak wantEqual: false, 936*88d15eacSSasha Smundak reason: "reporter should display the address to disambiguate between the two slice elements", 937*88d15eacSSasha Smundak }, { 938*88d15eacSSasha Smundak label: label + "/AmbiguousPointerMap", 939*88d15eacSSasha Smundak x: map[string]*int{"zero": newInt(0)}, 940*88d15eacSSasha Smundak y: map[string]*int{"zero": newInt(0)}, 941*88d15eacSSasha Smundak opts: []cmp.Option{ 942*88d15eacSSasha Smundak cmp.Comparer(func(x, y *int) bool { return x == y }), 943*88d15eacSSasha Smundak }, 944*88d15eacSSasha Smundak wantEqual: false, 945*88d15eacSSasha Smundak reason: "reporter should display the address to disambiguate between the two map values", 946*88d15eacSSasha Smundak }, { 947*88d15eacSSasha Smundak label: label + "/AmbiguousStringer", 948*88d15eacSSasha Smundak x: Stringer("hello"), 949*88d15eacSSasha Smundak y: newStringer("hello"), 950*88d15eacSSasha Smundak wantEqual: false, 951*88d15eacSSasha Smundak reason: "reporter should avoid calling String to disambiguate between the two values", 952*88d15eacSSasha Smundak }, { 953*88d15eacSSasha Smundak label: label + "/AmbiguousStringerStruct", 954*88d15eacSSasha Smundak x: struct{ S fmt.Stringer }{Stringer("hello")}, 955*88d15eacSSasha Smundak y: struct{ S fmt.Stringer }{newStringer("hello")}, 956*88d15eacSSasha Smundak wantEqual: false, 957*88d15eacSSasha Smundak reason: "reporter should avoid calling String to disambiguate between the two struct fields", 958*88d15eacSSasha Smundak }, { 959*88d15eacSSasha Smundak label: label + "/AmbiguousStringerSlice", 960*88d15eacSSasha Smundak x: []fmt.Stringer{Stringer("hello")}, 961*88d15eacSSasha Smundak y: []fmt.Stringer{newStringer("hello")}, 962*88d15eacSSasha Smundak wantEqual: false, 963*88d15eacSSasha Smundak reason: "reporter should avoid calling String to disambiguate between the two slice elements", 964*88d15eacSSasha Smundak }, { 965*88d15eacSSasha Smundak label: label + "/AmbiguousStringerMap", 966*88d15eacSSasha Smundak x: map[string]fmt.Stringer{"zero": Stringer("hello")}, 967*88d15eacSSasha Smundak y: map[string]fmt.Stringer{"zero": newStringer("hello")}, 968*88d15eacSSasha Smundak wantEqual: false, 969*88d15eacSSasha Smundak reason: "reporter should avoid calling String to disambiguate between the two map values", 970*88d15eacSSasha Smundak }, { 971*88d15eacSSasha Smundak label: label + "/AmbiguousSliceHeader", 972*88d15eacSSasha Smundak x: make([]int, 0, 5), 973*88d15eacSSasha Smundak y: make([]int, 0, 1000), 974*88d15eacSSasha Smundak opts: []cmp.Option{ 975*88d15eacSSasha Smundak cmp.Comparer(func(x, y []int) bool { return cap(x) == cap(y) }), 976*88d15eacSSasha Smundak }, 977*88d15eacSSasha Smundak wantEqual: false, 978*88d15eacSSasha Smundak reason: "reporter should display the slice header to disambiguate between the two slice values", 979*88d15eacSSasha Smundak }, { 980*88d15eacSSasha Smundak label: label + "/AmbiguousStringerMapKey", 981*88d15eacSSasha Smundak x: map[interface{}]string{ 982*88d15eacSSasha Smundak nil: "nil", 983*88d15eacSSasha Smundak Stringer("hello"): "goodbye", 984*88d15eacSSasha Smundak foo1.Bar{"fizz"}: "buzz", 985*88d15eacSSasha Smundak }, 986*88d15eacSSasha Smundak y: map[interface{}]string{ 987*88d15eacSSasha Smundak newStringer("hello"): "goodbye", 988*88d15eacSSasha Smundak foo2.Bar{"fizz"}: "buzz", 989*88d15eacSSasha Smundak }, 990*88d15eacSSasha Smundak wantEqual: false, 991*88d15eacSSasha Smundak reason: "reporter should avoid calling String to disambiguate between the two map keys", 992*88d15eacSSasha Smundak }, { 993*88d15eacSSasha Smundak label: label + "/NonAmbiguousStringerMapKey", 994*88d15eacSSasha Smundak x: map[interface{}]string{Stringer("hello"): "goodbye"}, 995*88d15eacSSasha Smundak y: map[interface{}]string{newStringer("fizz"): "buzz"}, 996*88d15eacSSasha Smundak wantEqual: false, 997*88d15eacSSasha Smundak reason: "reporter should call String as there is no ambiguity between the two map keys", 998*88d15eacSSasha Smundak }, { 999*88d15eacSSasha Smundak label: label + "/InvalidUTF8", 1000*88d15eacSSasha Smundak x: MyString("\xed\xa0\x80"), 1001*88d15eacSSasha Smundak wantEqual: false, 1002*88d15eacSSasha Smundak reason: "invalid UTF-8 should format as quoted string", 1003*88d15eacSSasha Smundak }, { 1004*88d15eacSSasha Smundak label: label + "/UnbatchedSlice", 1005*88d15eacSSasha Smundak x: MyComposite{IntsA: []int8{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, 1006*88d15eacSSasha Smundak y: MyComposite{IntsA: []int8{10, 11, 21, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, 1007*88d15eacSSasha Smundak wantEqual: false, 1008*88d15eacSSasha Smundak reason: "unbatched diffing desired since few elements differ", 1009*88d15eacSSasha Smundak }, { 1010*88d15eacSSasha Smundak label: label + "/BatchedSlice", 1011*88d15eacSSasha Smundak x: MyComposite{IntsA: []int8{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, 1012*88d15eacSSasha Smundak y: MyComposite{IntsA: []int8{12, 29, 13, 27, 22, 23, 17, 18, 19, 20, 21, 10, 26, 16, 25, 28, 11, 15, 24, 14}}, 1013*88d15eacSSasha Smundak wantEqual: false, 1014*88d15eacSSasha Smundak reason: "batched diffing desired since many elements differ", 1015*88d15eacSSasha Smundak }, { 1016*88d15eacSSasha Smundak label: label + "/BatchedWithComparer", 1017*88d15eacSSasha Smundak x: MyComposite{BytesA: []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}}, 1018*88d15eacSSasha Smundak y: MyComposite{BytesA: []byte{12, 29, 13, 27, 22, 23, 17, 18, 19, 20, 21, 10, 26, 16, 25, 28, 11, 15, 24, 14}}, 1019*88d15eacSSasha Smundak wantEqual: false, 1020*88d15eacSSasha Smundak opts: []cmp.Option{ 1021*88d15eacSSasha Smundak cmp.Comparer(bytes.Equal), 1022*88d15eacSSasha Smundak }, 1023*88d15eacSSasha Smundak reason: "batched diffing desired since many elements differ", 1024*88d15eacSSasha Smundak }, { 1025*88d15eacSSasha Smundak label: label + "/BatchedLong", 1026*88d15eacSSasha Smundak x: MyComposite{IntsA: []int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}}, 1027*88d15eacSSasha Smundak wantEqual: false, 1028*88d15eacSSasha Smundak reason: "batched output desired for a single slice of primitives unique to one of the inputs", 1029*88d15eacSSasha Smundak }, { 1030*88d15eacSSasha Smundak label: label + "/BatchedNamedAndUnnamed", 1031*88d15eacSSasha Smundak x: MyComposite{ 1032*88d15eacSSasha Smundak BytesA: []byte{1, 2, 3}, 1033*88d15eacSSasha Smundak BytesB: []MyByte{4, 5, 6}, 1034*88d15eacSSasha Smundak BytesC: MyBytes{7, 8, 9}, 1035*88d15eacSSasha Smundak IntsA: []int8{-1, -2, -3}, 1036*88d15eacSSasha Smundak IntsB: []MyInt{-4, -5, -6}, 1037*88d15eacSSasha Smundak IntsC: MyInts{-7, -8, -9}, 1038*88d15eacSSasha Smundak UintsA: []uint16{1000, 2000, 3000}, 1039*88d15eacSSasha Smundak UintsB: []MyUint{4000, 5000, 6000}, 1040*88d15eacSSasha Smundak UintsC: MyUints{7000, 8000, 9000}, 1041*88d15eacSSasha Smundak FloatsA: []float32{1.5, 2.5, 3.5}, 1042*88d15eacSSasha Smundak FloatsB: []MyFloat{4.5, 5.5, 6.5}, 1043*88d15eacSSasha Smundak FloatsC: MyFloats{7.5, 8.5, 9.5}, 1044*88d15eacSSasha Smundak }, 1045*88d15eacSSasha Smundak y: MyComposite{ 1046*88d15eacSSasha Smundak BytesA: []byte{3, 2, 1}, 1047*88d15eacSSasha Smundak BytesB: []MyByte{6, 5, 4}, 1048*88d15eacSSasha Smundak BytesC: MyBytes{9, 8, 7}, 1049*88d15eacSSasha Smundak IntsA: []int8{-3, -2, -1}, 1050*88d15eacSSasha Smundak IntsB: []MyInt{-6, -5, -4}, 1051*88d15eacSSasha Smundak IntsC: MyInts{-9, -8, -7}, 1052*88d15eacSSasha Smundak UintsA: []uint16{3000, 2000, 1000}, 1053*88d15eacSSasha Smundak UintsB: []MyUint{6000, 5000, 4000}, 1054*88d15eacSSasha Smundak UintsC: MyUints{9000, 8000, 7000}, 1055*88d15eacSSasha Smundak FloatsA: []float32{3.5, 2.5, 1.5}, 1056*88d15eacSSasha Smundak FloatsB: []MyFloat{6.5, 5.5, 4.5}, 1057*88d15eacSSasha Smundak FloatsC: MyFloats{9.5, 8.5, 7.5}, 1058*88d15eacSSasha Smundak }, 1059*88d15eacSSasha Smundak wantEqual: false, 1060*88d15eacSSasha Smundak reason: "batched diffing available for both named and unnamed slices", 1061*88d15eacSSasha Smundak }, { 1062*88d15eacSSasha Smundak label: label + "/BinaryHexdump", 1063*88d15eacSSasha Smundak 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]")}, 1064*88d15eacSSasha Smundak 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]")}, 1065*88d15eacSSasha Smundak wantEqual: false, 1066*88d15eacSSasha Smundak reason: "binary diff in hexdump form since data is binary data", 1067*88d15eacSSasha Smundak }, { 1068*88d15eacSSasha Smundak label: label + "/StringHexdump", 1069*88d15eacSSasha Smundak 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")}, 1070*88d15eacSSasha Smundak 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")}, 1071*88d15eacSSasha Smundak wantEqual: false, 1072*88d15eacSSasha Smundak reason: "binary diff desired since string looks like binary data", 1073*88d15eacSSasha Smundak }, { 1074*88d15eacSSasha Smundak label: label + "/BinaryString", 1075*88d15eacSSasha Smundak 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}`)}, 1076*88d15eacSSasha Smundak 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}`)}, 1077*88d15eacSSasha Smundak wantEqual: false, 1078*88d15eacSSasha Smundak reason: "batched textual diff desired since bytes looks like textual data", 1079*88d15eacSSasha Smundak }, { 1080*88d15eacSSasha Smundak label: label + "/TripleQuote", 1081*88d15eacSSasha Smundak x: MyComposite{StringA: "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n"}, 1082*88d15eacSSasha Smundak y: MyComposite{StringA: "aaa\nbbb\nCCC\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nSSS\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n"}, 1083*88d15eacSSasha Smundak wantEqual: false, 1084*88d15eacSSasha Smundak reason: "use triple-quote syntax", 1085*88d15eacSSasha Smundak }, { 1086*88d15eacSSasha Smundak label: label + "/TripleQuoteSlice", 1087*88d15eacSSasha Smundak x: []string{ 1088*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1089*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1090*88d15eacSSasha Smundak }, 1091*88d15eacSSasha Smundak y: []string{ 1092*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\n", 1093*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1094*88d15eacSSasha Smundak }, 1095*88d15eacSSasha Smundak wantEqual: false, 1096*88d15eacSSasha Smundak reason: "use triple-quote syntax for slices of strings", 1097*88d15eacSSasha Smundak }, { 1098*88d15eacSSasha Smundak label: label + "/TripleQuoteNamedTypes", 1099*88d15eacSSasha Smundak x: MyComposite{ 1100*88d15eacSSasha Smundak StringB: MyString("aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz"), 1101*88d15eacSSasha Smundak BytesC: MyBytes("aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz"), 1102*88d15eacSSasha Smundak }, 1103*88d15eacSSasha Smundak y: MyComposite{ 1104*88d15eacSSasha Smundak StringB: MyString("aaa\nbbb\nCCC\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nSSS\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz"), 1105*88d15eacSSasha Smundak BytesC: MyBytes("aaa\nbbb\nCCC\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nSSS\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz"), 1106*88d15eacSSasha Smundak }, 1107*88d15eacSSasha Smundak wantEqual: false, 1108*88d15eacSSasha Smundak reason: "use triple-quote syntax for named types", 1109*88d15eacSSasha Smundak }, { 1110*88d15eacSSasha Smundak label: label + "/TripleQuoteSliceNamedTypes", 1111*88d15eacSSasha Smundak x: []MyString{ 1112*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1113*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1114*88d15eacSSasha Smundak }, 1115*88d15eacSSasha Smundak y: []MyString{ 1116*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\n", 1117*88d15eacSSasha Smundak "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1118*88d15eacSSasha Smundak }, 1119*88d15eacSSasha Smundak wantEqual: false, 1120*88d15eacSSasha Smundak reason: "use triple-quote syntax for slices of named strings", 1121*88d15eacSSasha Smundak }, { 1122*88d15eacSSasha Smundak label: label + "/TripleQuoteEndlines", 1123*88d15eacSSasha Smundak x: "aaa\nbbb\nccc\nddd\neee\nfff\nggg\r\nhhh\n\riii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n\r", 1124*88d15eacSSasha Smundak y: "aaa\nbbb\nCCC\nddd\neee\nfff\nggg\r\nhhh\n\riii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz", 1125*88d15eacSSasha Smundak wantEqual: false, 1126*88d15eacSSasha Smundak reason: "use triple-quote syntax", 1127*88d15eacSSasha Smundak }, { 1128*88d15eacSSasha Smundak label: label + "/AvoidTripleQuoteAmbiguousQuotes", 1129*88d15eacSSasha Smundak x: "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1130*88d15eacSSasha Smundak y: "aaa\nbbb\nCCC\nddd\neee\n\"\"\"\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1131*88d15eacSSasha Smundak wantEqual: false, 1132*88d15eacSSasha Smundak reason: "avoid triple-quote syntax due to presence of ambiguous triple quotes", 1133*88d15eacSSasha Smundak }, { 1134*88d15eacSSasha Smundak label: label + "/AvoidTripleQuoteAmbiguousEllipsis", 1135*88d15eacSSasha Smundak x: "aaa\nbbb\nccc\n...\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1136*88d15eacSSasha Smundak y: "aaa\nbbb\nCCC\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1137*88d15eacSSasha Smundak wantEqual: false, 1138*88d15eacSSasha Smundak reason: "avoid triple-quote syntax due to presence of ambiguous ellipsis", 1139*88d15eacSSasha Smundak }, { 1140*88d15eacSSasha Smundak label: label + "/AvoidTripleQuoteNonPrintable", 1141*88d15eacSSasha Smundak x: "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1142*88d15eacSSasha Smundak y: "aaa\nbbb\nCCC\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\no\roo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1143*88d15eacSSasha Smundak wantEqual: false, 1144*88d15eacSSasha Smundak reason: "use triple-quote syntax", 1145*88d15eacSSasha Smundak }, { 1146*88d15eacSSasha Smundak label: label + "/AvoidTripleQuoteIdenticalWhitespace", 1147*88d15eacSSasha Smundak x: "aaa\nbbb\nccc\n ddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nRRR\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1148*88d15eacSSasha Smundak y: "aaa\nbbb\nccc \nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz\n", 1149*88d15eacSSasha Smundak wantEqual: false, 1150*88d15eacSSasha Smundak reason: "avoid triple-quote syntax due to visual equivalence of differences", 1151*88d15eacSSasha Smundak }, { 1152*88d15eacSSasha Smundak label: label + "/TripleQuoteStringer", 1153*88d15eacSSasha Smundak x: []fmt.Stringer{ 1154*88d15eacSSasha Smundak bytes.NewBuffer([]byte("package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tfmt.Println(\"Hello, playground\")\n}\n")), 1155*88d15eacSSasha Smundak bytes.NewBuffer([]byte("package main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n)\n\nfunc main() {\n\tfmt.Println(\"My favorite number is\", rand.Intn(10))\n}\n")), 1156*88d15eacSSasha Smundak }, 1157*88d15eacSSasha Smundak y: []fmt.Stringer{ 1158*88d15eacSSasha Smundak bytes.NewBuffer([]byte("package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tfmt.Println(\"Hello, playground\")\n}\n")), 1159*88d15eacSSasha Smundak bytes.NewBuffer([]byte("package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\nfunc main() {\n\tfmt.Printf(\"Now you have %g problems.\\n\", math.Sqrt(7))\n}\n")), 1160*88d15eacSSasha Smundak }, 1161*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(func(x, y fmt.Stringer) bool { return x.String() == y.String() })}, 1162*88d15eacSSasha Smundak wantEqual: false, 1163*88d15eacSSasha Smundak reason: "multi-line String output should be formatted with triple quote", 1164*88d15eacSSasha Smundak }, { 1165*88d15eacSSasha Smundak label: label + "/LimitMaximumBytesDiffs", 1166*88d15eacSSasha Smundak x: []byte("\xcd====\x06\x1f\xc2\xcc\xc2-S=====\x1d\xdfa\xae\x98\x9fH======ǰ\xb7=======\xef====:\\\x94\xe6J\xc7=====\xb4======\n\n\xf7\x94===========\xf2\x9c\xc0f=====4\xf6\xf1\xc3\x17\x82======n\x16`\x91D\xc6\x06=======\x1cE====.===========\xc4\x18=======\x8a\x8d\x0e====\x87\xb1\xa5\x8e\xc3=====z\x0f1\xaeU======G,=======5\xe75\xee\x82\xf4\xce====\x11r===========\xaf]=======z\x05\xb3\x91\x88%\xd2====\n1\x89=====i\xb7\x055\xe6\x81\xd2=============\x883=@̾====\x14\x05\x96%^t\x04=====\xe7Ȉ\x90\x1d============="), 1167*88d15eacSSasha Smundak y: []byte("\\====|\x96\xe7SB\xa0\xab=====\xf0\xbd\xa5q\xab\x17;======\xabP\x00=======\xeb====\xa5\x14\xe6O(\xe4=====(======/c@?===========\xd9x\xed\x13=====J\xfc\x918B\x8d======a8A\xebs\x04\xae=======\aC====\x1c===========\x91\"=======uؾ====s\xec\x845\a=====;\xabS9t======\x1f\x1b=======\x80\xab/\xed+:;====\xeaI===========\xabl=======\xb9\xe9\xfdH\x93\x8e\u007f====ח\xe5=====Ig\x88m\xf5\x01V=============\xf7+4\xb0\x92E====\x9fj\xf8&\xd0h\xf9=====\xeeΨ\r\xbf============="), 1168*88d15eacSSasha Smundak wantEqual: false, 1169*88d15eacSSasha Smundak reason: "total bytes difference output is truncated due to excessive number of differences", 1170*88d15eacSSasha Smundak }, { 1171*88d15eacSSasha Smundak label: label + "/LimitMaximumStringDiffs", 1172*88d15eacSSasha Smundak x: "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n", 1173*88d15eacSSasha Smundak y: "aa\nb\ncc\nd\nee\nf\ngg\nh\nii\nj\nkk\nl\nmm\nn\noo\np\nqq\nr\nss\nt\nuu\nv\nww\nx\nyy\nz\nAA\nB\nCC\nD\nEE\nF\nGG\nH\nII\nJ\nKK\nL\nMM\nN\nOO\nP\nQQ\nR\nSS\nT\nUU\nV\nWW\nX\nYY\nZ\n", 1174*88d15eacSSasha Smundak wantEqual: false, 1175*88d15eacSSasha Smundak reason: "total string difference output is truncated due to excessive number of differences", 1176*88d15eacSSasha Smundak }, { 1177*88d15eacSSasha Smundak label: label + "/LimitMaximumSliceDiffs", 1178*88d15eacSSasha Smundak x: func() (out []struct{ S string }) { 1179*88d15eacSSasha Smundak for _, s := range strings.Split("a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n", "\n") { 1180*88d15eacSSasha Smundak out = append(out, struct{ S string }{s}) 1181*88d15eacSSasha Smundak } 1182*88d15eacSSasha Smundak return out 1183*88d15eacSSasha Smundak }(), 1184*88d15eacSSasha Smundak y: func() (out []struct{ S string }) { 1185*88d15eacSSasha Smundak for _, s := range strings.Split("aa\nb\ncc\nd\nee\nf\ngg\nh\nii\nj\nkk\nl\nmm\nn\noo\np\nqq\nr\nss\nt\nuu\nv\nww\nx\nyy\nz\nAA\nB\nCC\nD\nEE\nF\nGG\nH\nII\nJ\nKK\nL\nMM\nN\nOO\nP\nQQ\nR\nSS\nT\nUU\nV\nWW\nX\nYY\nZ\n", "\n") { 1186*88d15eacSSasha Smundak out = append(out, struct{ S string }{s}) 1187*88d15eacSSasha Smundak } 1188*88d15eacSSasha Smundak return out 1189*88d15eacSSasha Smundak }(), 1190*88d15eacSSasha Smundak wantEqual: false, 1191*88d15eacSSasha Smundak reason: "total slice difference output is truncated due to excessive number of differences", 1192*88d15eacSSasha Smundak }, { 1193*88d15eacSSasha Smundak label: label + "/MultilineString", 1194*88d15eacSSasha Smundak x: MyComposite{ 1195*88d15eacSSasha Smundak StringA: strings.TrimPrefix(` 1196*88d15eacSSasha SmundakPackage cmp determines equality of values. 1197*88d15eacSSasha Smundak 1198*88d15eacSSasha SmundakThis package is intended to be a more powerful and safer alternative to 1199*88d15eacSSasha Smundakreflect.DeepEqual for comparing whether two values are semantically equal. 1200*88d15eacSSasha Smundak 1201*88d15eacSSasha SmundakThe primary features of cmp are: 1202*88d15eacSSasha Smundak 1203*88d15eacSSasha Smundak• When the default behavior of equality does not suit the needs of the test, 1204*88d15eacSSasha Smundakcustom equality functions can override the equality operation. 1205*88d15eacSSasha SmundakFor example, an equality function may report floats as equal so long as they 1206*88d15eacSSasha Smundakare within some tolerance of each other. 1207*88d15eacSSasha Smundak 1208*88d15eacSSasha Smundak• Types that have an Equal method may use that method to determine equality. 1209*88d15eacSSasha SmundakThis allows package authors to determine the equality operation for the types 1210*88d15eacSSasha Smundakthat they define. 1211*88d15eacSSasha Smundak 1212*88d15eacSSasha Smundak• If no custom equality functions are used and no Equal method is defined, 1213*88d15eacSSasha Smundakequality is determined by recursively comparing the primitive kinds on both 1214*88d15eacSSasha Smundakvalues, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported 1215*88d15eacSSasha Smundakfields are not compared by default; they result in panics unless suppressed 1216*88d15eacSSasha Smundakby using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared 1217*88d15eacSSasha Smundakusing the AllowUnexported option. 1218*88d15eacSSasha Smundak`, "\n"), 1219*88d15eacSSasha Smundak }, 1220*88d15eacSSasha Smundak y: MyComposite{ 1221*88d15eacSSasha Smundak StringA: strings.TrimPrefix(` 1222*88d15eacSSasha SmundakPackage cmp determines equality of value. 1223*88d15eacSSasha Smundak 1224*88d15eacSSasha SmundakThis package is intended to be a more powerful and safer alternative to 1225*88d15eacSSasha Smundakreflect.DeepEqual for comparing whether two values are semantically equal. 1226*88d15eacSSasha Smundak 1227*88d15eacSSasha SmundakThe primary features of cmp are: 1228*88d15eacSSasha Smundak 1229*88d15eacSSasha Smundak• When the default behavior of equality does not suit the needs of the test, 1230*88d15eacSSasha Smundakcustom equality functions can override the equality operation. 1231*88d15eacSSasha SmundakFor example, an equality function may report floats as equal so long as they 1232*88d15eacSSasha Smundakare within some tolerance of each other. 1233*88d15eacSSasha Smundak 1234*88d15eacSSasha Smundak• If no custom equality functions are used and no Equal method is defined, 1235*88d15eacSSasha Smundakequality is determined by recursively comparing the primitive kinds on both 1236*88d15eacSSasha Smundakvalues, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported 1237*88d15eacSSasha Smundakfields are not compared by default; they result in panics unless suppressed 1238*88d15eacSSasha Smundakby using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared 1239*88d15eacSSasha Smundakusing the AllowUnexported option.`, "\n"), 1240*88d15eacSSasha Smundak }, 1241*88d15eacSSasha Smundak wantEqual: false, 1242*88d15eacSSasha Smundak reason: "batched per-line diff desired since string looks like multi-line textual data", 1243*88d15eacSSasha Smundak }, { 1244*88d15eacSSasha Smundak label: label + "/Slices", 1245*88d15eacSSasha Smundak x: MyComposite{ 1246*88d15eacSSasha Smundak BytesA: []byte{1, 2, 3}, 1247*88d15eacSSasha Smundak BytesB: []MyByte{4, 5, 6}, 1248*88d15eacSSasha Smundak BytesC: MyBytes{7, 8, 9}, 1249*88d15eacSSasha Smundak IntsA: []int8{-1, -2, -3}, 1250*88d15eacSSasha Smundak IntsB: []MyInt{-4, -5, -6}, 1251*88d15eacSSasha Smundak IntsC: MyInts{-7, -8, -9}, 1252*88d15eacSSasha Smundak UintsA: []uint16{1000, 2000, 3000}, 1253*88d15eacSSasha Smundak UintsB: []MyUint{4000, 5000, 6000}, 1254*88d15eacSSasha Smundak UintsC: MyUints{7000, 8000, 9000}, 1255*88d15eacSSasha Smundak FloatsA: []float32{1.5, 2.5, 3.5}, 1256*88d15eacSSasha Smundak FloatsB: []MyFloat{4.5, 5.5, 6.5}, 1257*88d15eacSSasha Smundak FloatsC: MyFloats{7.5, 8.5, 9.5}, 1258*88d15eacSSasha Smundak }, 1259*88d15eacSSasha Smundak y: MyComposite{}, 1260*88d15eacSSasha Smundak wantEqual: false, 1261*88d15eacSSasha Smundak reason: "batched diffing for non-nil slices and nil slices", 1262*88d15eacSSasha Smundak }, { 1263*88d15eacSSasha Smundak label: label + "/EmptySlices", 1264*88d15eacSSasha Smundak x: MyComposite{ 1265*88d15eacSSasha Smundak BytesA: []byte{}, 1266*88d15eacSSasha Smundak BytesB: []MyByte{}, 1267*88d15eacSSasha Smundak BytesC: MyBytes{}, 1268*88d15eacSSasha Smundak IntsA: []int8{}, 1269*88d15eacSSasha Smundak IntsB: []MyInt{}, 1270*88d15eacSSasha Smundak IntsC: MyInts{}, 1271*88d15eacSSasha Smundak UintsA: []uint16{}, 1272*88d15eacSSasha Smundak UintsB: []MyUint{}, 1273*88d15eacSSasha Smundak UintsC: MyUints{}, 1274*88d15eacSSasha Smundak FloatsA: []float32{}, 1275*88d15eacSSasha Smundak FloatsB: []MyFloat{}, 1276*88d15eacSSasha Smundak FloatsC: MyFloats{}, 1277*88d15eacSSasha Smundak }, 1278*88d15eacSSasha Smundak y: MyComposite{}, 1279*88d15eacSSasha Smundak wantEqual: false, 1280*88d15eacSSasha Smundak reason: "batched diffing for empty slices and nil slices", 1281*88d15eacSSasha Smundak }, { 1282*88d15eacSSasha Smundak label: label + "/LargeMapKey", 1283*88d15eacSSasha Smundak x: map[*[]byte]int{func() *[]byte { 1284*88d15eacSSasha Smundak b := make([]byte, 1<<20) 1285*88d15eacSSasha Smundak return &b 1286*88d15eacSSasha Smundak }(): 0}, 1287*88d15eacSSasha Smundak y: map[*[]byte]int{func() *[]byte { 1288*88d15eacSSasha Smundak b := make([]byte, 1<<20) 1289*88d15eacSSasha Smundak return &b 1290*88d15eacSSasha Smundak }(): 0}, 1291*88d15eacSSasha Smundak reason: "printing map keys should have some verbosity limit imposed", 1292*88d15eacSSasha Smundak }, { 1293*88d15eacSSasha Smundak label: label + "/LargeStringInInterface", 1294*88d15eacSSasha Smundak x: struct{ X interface{} }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}, 1295*88d15eacSSasha Smundak 1296*88d15eacSSasha Smundak y: struct{ X interface{} }{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}, 1297*88d15eacSSasha Smundak reason: "strings within an interface should benefit from specialized diffing", 1298*88d15eacSSasha Smundak }, { 1299*88d15eacSSasha Smundak label: label + "/LargeBytesInInterface", 1300*88d15eacSSasha Smundak x: struct{ X interface{} }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis.")}, 1301*88d15eacSSasha Smundak y: struct{ X interface{} }{[]byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,")}, 1302*88d15eacSSasha Smundak reason: "bytes slice within an interface should benefit from specialized diffing", 1303*88d15eacSSasha Smundak }, { 1304*88d15eacSSasha Smundak label: label + "/LargeStandaloneString", 1305*88d15eacSSasha Smundak x: struct{ X interface{} }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis."}}, 1306*88d15eacSSasha Smundak y: struct{ X interface{} }{[1]string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet pretium ligula, at gravida quam. Integer iaculis, velit at sagittis ultricies, lacus metus scelerisque turpis, ornare feugiat nulla nisl ac erat. Maecenas elementum ultricies libero, sed efficitur lacus molestie non. Nulla ac pretium dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque mi lorem, consectetur id porttitor id, sollicitudin sit amet enim. Duis eu dolor magna. Nunc ut augue turpis,"}}, 1307*88d15eacSSasha Smundak reason: "printing a large standalone string that is different should print enough context to see the difference", 1308*88d15eacSSasha Smundak }, { 1309*88d15eacSSasha Smundak label: label + "/SurroundingEqualElements", 1310*88d15eacSSasha Smundak x: "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa,#=_value _value=2 11\torg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=bb,#=_value _value=2 21\torg-4747474747474747,bucket-4242424242424242:m,tag1=b,tag2=cc,#=_value _value=1 21\torg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=dd,#=_value _value=3 31\torg-4747474747474747,bucket-4242424242424242:m,tag1=c,#=_value _value=4 41\t", 1311*88d15eacSSasha Smundak y: "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa _value=2 11\torg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=bb _value=2 21\torg-4747474747474747,bucket-4242424242424242:m,tag1=b,tag2=cc _value=1 21\torg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=dd _value=3 31\torg-4747474747474747,bucket-4242424242424242:m,tag1=c _value=4 41\t", 1312*88d15eacSSasha Smundak reason: "leading/trailing equal spans should not appear in diff lines", 1313*88d15eacSSasha Smundak }, { 1314*88d15eacSSasha Smundak label: label + "/MostlyTextString", 1315*88d15eacSSasha Smundak x: "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa,\xff=_value _value=2 11\norg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=bb,\xff=_value _value=2 21\norg-4747474747474747,bucket-4242424242424242:m,tag1=b,tag2=cc,\xff=_value _value=1 21\norg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=dd,\xff=_value _value=3 31\norg-4747474747474747,bucket-4242424242424242:m,tag1=c,\xff=_value _value=4 41\n", 1316*88d15eacSSasha Smundak y: "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa _value=2 11\norg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=bb _value=2 21\norg-4747474747474747,bucket-4242424242424242:m,tag1=b,tag2=cc _value=1 21\norg-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=dd _value=3 31\norg-4747474747474747,bucket-4242424242424242:m,tag1=c _value=4 41\n", 1317*88d15eacSSasha Smundak reason: "the presence of a few invalid UTF-8 characters should not prevent printing this as text", 1318*88d15eacSSasha Smundak }, { 1319*88d15eacSSasha Smundak label: label + "/AllLinesDiffer", 1320*88d15eacSSasha Smundak x: "d5c14bdf6bac81c27afc5429500ed750\n25483503b557c606dad4f144d27ae10b\n90bdbcdbb6ea7156068e3dcfb7459244\n978f480a6e3cced51e297fbff9a506b7\n", 1321*88d15eacSSasha Smundak y: "Xd5c14bdf6bac81c27afc5429500ed750\nX25483503b557c606dad4f144d27ae10b\nX90bdbcdbb6ea7156068e3dcfb7459244\nX978f480a6e3cced51e297fbff9a506b7\n", 1322*88d15eacSSasha Smundak reason: "all lines are different, so diffing based on lines is pointless", 1323*88d15eacSSasha Smundak }, { 1324*88d15eacSSasha Smundak label: label + "/StringifiedBytes", 1325*88d15eacSSasha Smundak x: struct{ X []byte }{[]byte("hello, world!")}, 1326*88d15eacSSasha Smundak y: struct{ X []byte }{}, 1327*88d15eacSSasha Smundak reason: "[]byte should be printed as text since it is printable text", 1328*88d15eacSSasha Smundak }, { 1329*88d15eacSSasha Smundak label: label + "/NonStringifiedBytes", 1330*88d15eacSSasha Smundak x: struct{ X []byte }{[]byte("\xde\xad\xbe\xef")}, 1331*88d15eacSSasha Smundak y: struct{ X []byte }{}, 1332*88d15eacSSasha Smundak reason: "[]byte should not be printed as text since it is binary data", 1333*88d15eacSSasha Smundak }, { 1334*88d15eacSSasha Smundak label: label + "/StringifiedNamedBytes", 1335*88d15eacSSasha Smundak x: struct{ X MyBytes }{MyBytes("hello, world!")}, 1336*88d15eacSSasha Smundak y: struct{ X MyBytes }{}, 1337*88d15eacSSasha Smundak reason: "MyBytes should be printed as text since it is printable text", 1338*88d15eacSSasha Smundak }, { 1339*88d15eacSSasha Smundak label: label + "/NonStringifiedNamedBytes", 1340*88d15eacSSasha Smundak x: struct{ X MyBytes }{MyBytes("\xde\xad\xbe\xef")}, 1341*88d15eacSSasha Smundak y: struct{ X MyBytes }{}, 1342*88d15eacSSasha Smundak reason: "MyBytes should not be printed as text since it is binary data", 1343*88d15eacSSasha Smundak }, { 1344*88d15eacSSasha Smundak label: label + "/ShortJSON", 1345*88d15eacSSasha Smundak x: `{ 1346*88d15eacSSasha Smundak "id": 1, 1347*88d15eacSSasha Smundak "foo": true, 1348*88d15eacSSasha Smundak "bar": true, 1349*88d15eacSSasha Smundak}`, 1350*88d15eacSSasha Smundak y: `{ 1351*88d15eacSSasha Smundak "id": 1434180, 1352*88d15eacSSasha Smundak "foo": true, 1353*88d15eacSSasha Smundak "bar": true, 1354*88d15eacSSasha Smundak}`, 1355*88d15eacSSasha Smundak reason: "short multiline JSON should prefer triple-quoted string diff as it is more readable", 1356*88d15eacSSasha Smundak }, { 1357*88d15eacSSasha Smundak label: label + "/PointerToStringOrAny", 1358*88d15eacSSasha Smundak x: func() *string { 1359*88d15eacSSasha Smundak var v string = "hello" 1360*88d15eacSSasha Smundak return &v 1361*88d15eacSSasha Smundak }(), 1362*88d15eacSSasha Smundak y: func() *interface{} { 1363*88d15eacSSasha Smundak var v interface{} = "hello" 1364*88d15eacSSasha Smundak return &v 1365*88d15eacSSasha Smundak }(), 1366*88d15eacSSasha Smundak reason: "mismatched types between any and *any should print differently", 1367*88d15eacSSasha Smundak }, { 1368*88d15eacSSasha Smundak label: label + "/NamedPointer", 1369*88d15eacSSasha Smundak x: func() *string { 1370*88d15eacSSasha Smundak v := "hello" 1371*88d15eacSSasha Smundak return &v 1372*88d15eacSSasha Smundak }(), 1373*88d15eacSSasha Smundak y: func() PointerString { 1374*88d15eacSSasha Smundak v := "hello" 1375*88d15eacSSasha Smundak return &v 1376*88d15eacSSasha Smundak }(), 1377*88d15eacSSasha Smundak reason: "mismatched pointer types should print differently", 1378*88d15eacSSasha Smundak }, { 1379*88d15eacSSasha Smundak label: label + "/MapStringAny", 1380*88d15eacSSasha Smundak x: map[string]interface{}{"key": int(0)}, 1381*88d15eacSSasha Smundak y: map[string]interface{}{"key": uint(0)}, 1382*88d15eacSSasha Smundak reason: "mismatched underlying value within interface", 1383*88d15eacSSasha Smundak }, { 1384*88d15eacSSasha Smundak label: label + "/StructFieldAny", 1385*88d15eacSSasha Smundak x: struct{ X interface{} }{int(0)}, 1386*88d15eacSSasha Smundak y: struct{ X interface{} }{uint(0)}, 1387*88d15eacSSasha Smundak reason: "mismatched underlying value within interface", 1388*88d15eacSSasha Smundak }, { 1389*88d15eacSSasha Smundak label: label + "/SliceOfBytesText", 1390*88d15eacSSasha Smundak x: [][]byte{ 1391*88d15eacSSasha Smundak []byte("hello"), []byte("foo"), []byte("barbaz"), []byte("blahdieblah"), 1392*88d15eacSSasha Smundak }, 1393*88d15eacSSasha Smundak y: [][]byte{ 1394*88d15eacSSasha Smundak []byte("foo"), []byte("foo"), []byte("barbaz"), []byte("added"), []byte("here"), []byte("hrmph"), 1395*88d15eacSSasha Smundak }, 1396*88d15eacSSasha Smundak reason: "should print text byte slices as strings", 1397*88d15eacSSasha Smundak }, { 1398*88d15eacSSasha Smundak label: label + "/SliceOfBytesBinary", 1399*88d15eacSSasha Smundak x: [][]byte{ 1400*88d15eacSSasha Smundak []byte("\xde\xad\xbe\xef"), []byte("\xffoo"), []byte("barbaz"), []byte("blahdieblah"), 1401*88d15eacSSasha Smundak }, 1402*88d15eacSSasha Smundak y: [][]byte{ 1403*88d15eacSSasha Smundak []byte("\xffoo"), []byte("foo"), []byte("barbaz"), []byte("added"), []byte("here"), []byte("hrmph\xff"), 1404*88d15eacSSasha Smundak }, 1405*88d15eacSSasha Smundak reason: "should print text byte slices as strings except those with binary", 1406*88d15eacSSasha Smundak }, { 1407*88d15eacSSasha Smundak label: label + "/ManyEscapeCharacters", 1408*88d15eacSSasha Smundak x: `[ 1409*88d15eacSSasha Smundak {"Base32": "NA======"}, 1410*88d15eacSSasha Smundak {"Base32": "NBSQ===="}, 1411*88d15eacSSasha Smundak {"Base32": "NBSWY==="}, 1412*88d15eacSSasha Smundak {"Base32": "NBSWY3A="}, 1413*88d15eacSSasha Smundak {"Base32": "NBSWY3DP"} 1414*88d15eacSSasha Smundak]`, 1415*88d15eacSSasha Smundak y: `[ 1416*88d15eacSSasha Smundak {"Base32": "NB======"}, 1417*88d15eacSSasha Smundak {"Base32": "NBSQ===="}, 1418*88d15eacSSasha Smundak {"Base32": "NBSWY==="}, 1419*88d15eacSSasha Smundak {"Base32": "NBSWY3A="}, 1420*88d15eacSSasha Smundak {"Base32": "NBSWY3DP"} 1421*88d15eacSSasha Smundak]`, 1422*88d15eacSSasha Smundak reason: "should use line-based diffing since byte-based diffing is unreadable due to heavy amounts of escaping", 1423*88d15eacSSasha Smundak }} 1424*88d15eacSSasha Smundak} 1425*88d15eacSSasha Smundak 1426*88d15eacSSasha Smundakfunc embeddedTests() []test { 1427*88d15eacSSasha Smundak const label = "EmbeddedStruct" 1428*88d15eacSSasha Smundak 1429*88d15eacSSasha Smundak privateStruct := *new(ts.ParentStructA).PrivateStruct() 1430*88d15eacSSasha Smundak 1431*88d15eacSSasha Smundak createStructA := func(i int) ts.ParentStructA { 1432*88d15eacSSasha Smundak s := ts.ParentStructA{} 1433*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1434*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1435*88d15eacSSasha Smundak return s 1436*88d15eacSSasha Smundak } 1437*88d15eacSSasha Smundak 1438*88d15eacSSasha Smundak createStructB := func(i int) ts.ParentStructB { 1439*88d15eacSSasha Smundak s := ts.ParentStructB{} 1440*88d15eacSSasha Smundak s.PublicStruct.Public = 1 + i 1441*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(2 + i) 1442*88d15eacSSasha Smundak return s 1443*88d15eacSSasha Smundak } 1444*88d15eacSSasha Smundak 1445*88d15eacSSasha Smundak createStructC := func(i int) ts.ParentStructC { 1446*88d15eacSSasha Smundak s := ts.ParentStructC{} 1447*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1448*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1449*88d15eacSSasha Smundak s.Public = 3 + i 1450*88d15eacSSasha Smundak s.SetPrivate(4 + i) 1451*88d15eacSSasha Smundak return s 1452*88d15eacSSasha Smundak } 1453*88d15eacSSasha Smundak 1454*88d15eacSSasha Smundak createStructD := func(i int) ts.ParentStructD { 1455*88d15eacSSasha Smundak s := ts.ParentStructD{} 1456*88d15eacSSasha Smundak s.PublicStruct.Public = 1 + i 1457*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(2 + i) 1458*88d15eacSSasha Smundak s.Public = 3 + i 1459*88d15eacSSasha Smundak s.SetPrivate(4 + i) 1460*88d15eacSSasha Smundak return s 1461*88d15eacSSasha Smundak } 1462*88d15eacSSasha Smundak 1463*88d15eacSSasha Smundak createStructE := func(i int) ts.ParentStructE { 1464*88d15eacSSasha Smundak s := ts.ParentStructE{} 1465*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1466*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1467*88d15eacSSasha Smundak s.PublicStruct.Public = 3 + i 1468*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(4 + i) 1469*88d15eacSSasha Smundak return s 1470*88d15eacSSasha Smundak } 1471*88d15eacSSasha Smundak 1472*88d15eacSSasha Smundak createStructF := func(i int) ts.ParentStructF { 1473*88d15eacSSasha Smundak s := ts.ParentStructF{} 1474*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1475*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1476*88d15eacSSasha Smundak s.PublicStruct.Public = 3 + i 1477*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(4 + i) 1478*88d15eacSSasha Smundak s.Public = 5 + i 1479*88d15eacSSasha Smundak s.SetPrivate(6 + i) 1480*88d15eacSSasha Smundak return s 1481*88d15eacSSasha Smundak } 1482*88d15eacSSasha Smundak 1483*88d15eacSSasha Smundak createStructG := func(i int) *ts.ParentStructG { 1484*88d15eacSSasha Smundak s := ts.NewParentStructG() 1485*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1486*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1487*88d15eacSSasha Smundak return s 1488*88d15eacSSasha Smundak } 1489*88d15eacSSasha Smundak 1490*88d15eacSSasha Smundak createStructH := func(i int) *ts.ParentStructH { 1491*88d15eacSSasha Smundak s := ts.NewParentStructH() 1492*88d15eacSSasha Smundak s.PublicStruct.Public = 1 + i 1493*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(2 + i) 1494*88d15eacSSasha Smundak return s 1495*88d15eacSSasha Smundak } 1496*88d15eacSSasha Smundak 1497*88d15eacSSasha Smundak createStructI := func(i int) *ts.ParentStructI { 1498*88d15eacSSasha Smundak s := ts.NewParentStructI() 1499*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1500*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1501*88d15eacSSasha Smundak s.PublicStruct.Public = 3 + i 1502*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(4 + i) 1503*88d15eacSSasha Smundak return s 1504*88d15eacSSasha Smundak } 1505*88d15eacSSasha Smundak 1506*88d15eacSSasha Smundak createStructJ := func(i int) *ts.ParentStructJ { 1507*88d15eacSSasha Smundak s := ts.NewParentStructJ() 1508*88d15eacSSasha Smundak s.PrivateStruct().Public = 1 + i 1509*88d15eacSSasha Smundak s.PrivateStruct().SetPrivate(2 + i) 1510*88d15eacSSasha Smundak s.PublicStruct.Public = 3 + i 1511*88d15eacSSasha Smundak s.PublicStruct.SetPrivate(4 + i) 1512*88d15eacSSasha Smundak s.Private().Public = 5 + i 1513*88d15eacSSasha Smundak s.Private().SetPrivate(6 + i) 1514*88d15eacSSasha Smundak s.Public.Public = 7 + i 1515*88d15eacSSasha Smundak s.Public.SetPrivate(8 + i) 1516*88d15eacSSasha Smundak return s 1517*88d15eacSSasha Smundak } 1518*88d15eacSSasha Smundak 1519*88d15eacSSasha Smundak return []test{{ 1520*88d15eacSSasha Smundak label: label + "/ParentStructA/PanicUnexported1", 1521*88d15eacSSasha Smundak x: ts.ParentStructA{}, 1522*88d15eacSSasha Smundak y: ts.ParentStructA{}, 1523*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1524*88d15eacSSasha Smundak reason: "ParentStructA has an unexported field", 1525*88d15eacSSasha Smundak }, { 1526*88d15eacSSasha Smundak label: label + "/ParentStructA/Ignored", 1527*88d15eacSSasha Smundak x: ts.ParentStructA{}, 1528*88d15eacSSasha Smundak y: ts.ParentStructA{}, 1529*88d15eacSSasha Smundak opts: []cmp.Option{ 1530*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructA{}), 1531*88d15eacSSasha Smundak }, 1532*88d15eacSSasha Smundak wantEqual: true, 1533*88d15eacSSasha Smundak reason: "the only field (which is unexported) of ParentStructA is ignored", 1534*88d15eacSSasha Smundak }, { 1535*88d15eacSSasha Smundak label: label + "/ParentStructA/PanicUnexported2", 1536*88d15eacSSasha Smundak x: createStructA(0), 1537*88d15eacSSasha Smundak y: createStructA(0), 1538*88d15eacSSasha Smundak opts: []cmp.Option{ 1539*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructA{}), 1540*88d15eacSSasha Smundak }, 1541*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1542*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1543*88d15eacSSasha Smundak }, { 1544*88d15eacSSasha Smundak label: label + "/ParentStructA/Equal", 1545*88d15eacSSasha Smundak x: createStructA(0), 1546*88d15eacSSasha Smundak y: createStructA(0), 1547*88d15eacSSasha Smundak opts: []cmp.Option{ 1548*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructA{}, privateStruct), 1549*88d15eacSSasha Smundak }, 1550*88d15eacSSasha Smundak wantEqual: true, 1551*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructA and privateStruct are allowed", 1552*88d15eacSSasha Smundak }, { 1553*88d15eacSSasha Smundak label: label + "/ParentStructA/Inequal", 1554*88d15eacSSasha Smundak x: createStructA(0), 1555*88d15eacSSasha Smundak y: createStructA(1), 1556*88d15eacSSasha Smundak opts: []cmp.Option{ 1557*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructA{}, privateStruct), 1558*88d15eacSSasha Smundak }, 1559*88d15eacSSasha Smundak wantEqual: false, 1560*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1561*88d15eacSSasha Smundak }, { 1562*88d15eacSSasha Smundak label: label + "/ParentStructB/PanicUnexported1", 1563*88d15eacSSasha Smundak x: ts.ParentStructB{}, 1564*88d15eacSSasha Smundak y: ts.ParentStructB{}, 1565*88d15eacSSasha Smundak opts: []cmp.Option{ 1566*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructB{}), 1567*88d15eacSSasha Smundak }, 1568*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1569*88d15eacSSasha Smundak reason: "PublicStruct has an unexported field", 1570*88d15eacSSasha Smundak }, { 1571*88d15eacSSasha Smundak label: label + "/ParentStructB/Ignored", 1572*88d15eacSSasha Smundak x: ts.ParentStructB{}, 1573*88d15eacSSasha Smundak y: ts.ParentStructB{}, 1574*88d15eacSSasha Smundak opts: []cmp.Option{ 1575*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructB{}), 1576*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.PublicStruct{}), 1577*88d15eacSSasha Smundak }, 1578*88d15eacSSasha Smundak wantEqual: true, 1579*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructB and PublicStruct are ignored", 1580*88d15eacSSasha Smundak }, { 1581*88d15eacSSasha Smundak label: label + "/ParentStructB/PanicUnexported2", 1582*88d15eacSSasha Smundak x: createStructB(0), 1583*88d15eacSSasha Smundak y: createStructB(0), 1584*88d15eacSSasha Smundak opts: []cmp.Option{ 1585*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructB{}), 1586*88d15eacSSasha Smundak }, 1587*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1588*88d15eacSSasha Smundak reason: "PublicStruct also has unexported fields", 1589*88d15eacSSasha Smundak }, { 1590*88d15eacSSasha Smundak label: label + "/ParentStructB/Equal", 1591*88d15eacSSasha Smundak x: createStructB(0), 1592*88d15eacSSasha Smundak y: createStructB(0), 1593*88d15eacSSasha Smundak opts: []cmp.Option{ 1594*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructB{}, ts.PublicStruct{}), 1595*88d15eacSSasha Smundak }, 1596*88d15eacSSasha Smundak wantEqual: true, 1597*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructB and PublicStruct are allowed", 1598*88d15eacSSasha Smundak }, { 1599*88d15eacSSasha Smundak label: label + "/ParentStructB/Inequal", 1600*88d15eacSSasha Smundak x: createStructB(0), 1601*88d15eacSSasha Smundak y: createStructB(1), 1602*88d15eacSSasha Smundak opts: []cmp.Option{ 1603*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructB{}, ts.PublicStruct{}), 1604*88d15eacSSasha Smundak }, 1605*88d15eacSSasha Smundak wantEqual: false, 1606*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1607*88d15eacSSasha Smundak }, { 1608*88d15eacSSasha Smundak label: label + "/ParentStructC/PanicUnexported1", 1609*88d15eacSSasha Smundak x: ts.ParentStructC{}, 1610*88d15eacSSasha Smundak y: ts.ParentStructC{}, 1611*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1612*88d15eacSSasha Smundak reason: "ParentStructC has unexported fields", 1613*88d15eacSSasha Smundak }, { 1614*88d15eacSSasha Smundak label: label + "/ParentStructC/Ignored", 1615*88d15eacSSasha Smundak x: ts.ParentStructC{}, 1616*88d15eacSSasha Smundak y: ts.ParentStructC{}, 1617*88d15eacSSasha Smundak opts: []cmp.Option{ 1618*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructC{}), 1619*88d15eacSSasha Smundak }, 1620*88d15eacSSasha Smundak wantEqual: true, 1621*88d15eacSSasha Smundak reason: "unexported fields of ParentStructC are ignored", 1622*88d15eacSSasha Smundak }, { 1623*88d15eacSSasha Smundak label: label + "/ParentStructC/PanicUnexported2", 1624*88d15eacSSasha Smundak x: createStructC(0), 1625*88d15eacSSasha Smundak y: createStructC(0), 1626*88d15eacSSasha Smundak opts: []cmp.Option{ 1627*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructC{}), 1628*88d15eacSSasha Smundak }, 1629*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1630*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1631*88d15eacSSasha Smundak }, { 1632*88d15eacSSasha Smundak label: label + "/ParentStructC/Equal", 1633*88d15eacSSasha Smundak x: createStructC(0), 1634*88d15eacSSasha Smundak y: createStructC(0), 1635*88d15eacSSasha Smundak opts: []cmp.Option{ 1636*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructC{}, privateStruct), 1637*88d15eacSSasha Smundak }, 1638*88d15eacSSasha Smundak wantEqual: true, 1639*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructC and privateStruct are allowed", 1640*88d15eacSSasha Smundak }, { 1641*88d15eacSSasha Smundak label: label + "/ParentStructC/Inequal", 1642*88d15eacSSasha Smundak x: createStructC(0), 1643*88d15eacSSasha Smundak y: createStructC(1), 1644*88d15eacSSasha Smundak opts: []cmp.Option{ 1645*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructC{}, privateStruct), 1646*88d15eacSSasha Smundak }, 1647*88d15eacSSasha Smundak wantEqual: false, 1648*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1649*88d15eacSSasha Smundak }, { 1650*88d15eacSSasha Smundak label: label + "/ParentStructD/PanicUnexported1", 1651*88d15eacSSasha Smundak x: ts.ParentStructD{}, 1652*88d15eacSSasha Smundak y: ts.ParentStructD{}, 1653*88d15eacSSasha Smundak opts: []cmp.Option{ 1654*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructD{}), 1655*88d15eacSSasha Smundak }, 1656*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1657*88d15eacSSasha Smundak reason: "ParentStructD has unexported fields", 1658*88d15eacSSasha Smundak }, { 1659*88d15eacSSasha Smundak label: label + "/ParentStructD/Ignored", 1660*88d15eacSSasha Smundak x: ts.ParentStructD{}, 1661*88d15eacSSasha Smundak y: ts.ParentStructD{}, 1662*88d15eacSSasha Smundak opts: []cmp.Option{ 1663*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructD{}), 1664*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.PublicStruct{}), 1665*88d15eacSSasha Smundak }, 1666*88d15eacSSasha Smundak wantEqual: true, 1667*88d15eacSSasha Smundak reason: "unexported fields of ParentStructD and PublicStruct are ignored", 1668*88d15eacSSasha Smundak }, { 1669*88d15eacSSasha Smundak label: label + "/ParentStructD/PanicUnexported2", 1670*88d15eacSSasha Smundak x: createStructD(0), 1671*88d15eacSSasha Smundak y: createStructD(0), 1672*88d15eacSSasha Smundak opts: []cmp.Option{ 1673*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructD{}), 1674*88d15eacSSasha Smundak }, 1675*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1676*88d15eacSSasha Smundak reason: "PublicStruct also has unexported fields", 1677*88d15eacSSasha Smundak }, { 1678*88d15eacSSasha Smundak label: label + "/ParentStructD/Equal", 1679*88d15eacSSasha Smundak x: createStructD(0), 1680*88d15eacSSasha Smundak y: createStructD(0), 1681*88d15eacSSasha Smundak opts: []cmp.Option{ 1682*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructD{}, ts.PublicStruct{}), 1683*88d15eacSSasha Smundak }, 1684*88d15eacSSasha Smundak wantEqual: true, 1685*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructD and PublicStruct are allowed", 1686*88d15eacSSasha Smundak }, { 1687*88d15eacSSasha Smundak label: label + "/ParentStructD/Inequal", 1688*88d15eacSSasha Smundak x: createStructD(0), 1689*88d15eacSSasha Smundak y: createStructD(1), 1690*88d15eacSSasha Smundak opts: []cmp.Option{ 1691*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructD{}, ts.PublicStruct{}), 1692*88d15eacSSasha Smundak }, 1693*88d15eacSSasha Smundak wantEqual: false, 1694*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1695*88d15eacSSasha Smundak }, { 1696*88d15eacSSasha Smundak label: label + "/ParentStructE/PanicUnexported1", 1697*88d15eacSSasha Smundak x: ts.ParentStructE{}, 1698*88d15eacSSasha Smundak y: ts.ParentStructE{}, 1699*88d15eacSSasha Smundak opts: []cmp.Option{ 1700*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructE{}), 1701*88d15eacSSasha Smundak }, 1702*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1703*88d15eacSSasha Smundak reason: "ParentStructE has unexported fields", 1704*88d15eacSSasha Smundak }, { 1705*88d15eacSSasha Smundak label: label + "/ParentStructE/Ignored", 1706*88d15eacSSasha Smundak x: ts.ParentStructE{}, 1707*88d15eacSSasha Smundak y: ts.ParentStructE{}, 1708*88d15eacSSasha Smundak opts: []cmp.Option{ 1709*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructE{}), 1710*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.PublicStruct{}), 1711*88d15eacSSasha Smundak }, 1712*88d15eacSSasha Smundak wantEqual: true, 1713*88d15eacSSasha Smundak reason: "unexported fields of ParentStructE and PublicStruct are ignored", 1714*88d15eacSSasha Smundak }, { 1715*88d15eacSSasha Smundak label: label + "/ParentStructE/PanicUnexported2", 1716*88d15eacSSasha Smundak x: createStructE(0), 1717*88d15eacSSasha Smundak y: createStructE(0), 1718*88d15eacSSasha Smundak opts: []cmp.Option{ 1719*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructE{}), 1720*88d15eacSSasha Smundak }, 1721*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1722*88d15eacSSasha Smundak reason: "PublicStruct and privateStruct also has unexported fields", 1723*88d15eacSSasha Smundak }, { 1724*88d15eacSSasha Smundak label: label + "/ParentStructE/PanicUnexported3", 1725*88d15eacSSasha Smundak x: createStructE(0), 1726*88d15eacSSasha Smundak y: createStructE(0), 1727*88d15eacSSasha Smundak opts: []cmp.Option{ 1728*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}), 1729*88d15eacSSasha Smundak }, 1730*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1731*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1732*88d15eacSSasha Smundak }, { 1733*88d15eacSSasha Smundak label: label + "/ParentStructE/Equal", 1734*88d15eacSSasha Smundak x: createStructE(0), 1735*88d15eacSSasha Smundak y: createStructE(0), 1736*88d15eacSSasha Smundak opts: []cmp.Option{ 1737*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}, privateStruct), 1738*88d15eacSSasha Smundak }, 1739*88d15eacSSasha Smundak wantEqual: true, 1740*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructE, PublicStruct, and privateStruct are allowed", 1741*88d15eacSSasha Smundak }, { 1742*88d15eacSSasha Smundak label: label + "/ParentStructE/Inequal", 1743*88d15eacSSasha Smundak x: createStructE(0), 1744*88d15eacSSasha Smundak y: createStructE(1), 1745*88d15eacSSasha Smundak opts: []cmp.Option{ 1746*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructE{}, ts.PublicStruct{}, privateStruct), 1747*88d15eacSSasha Smundak }, 1748*88d15eacSSasha Smundak wantEqual: false, 1749*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1750*88d15eacSSasha Smundak }, { 1751*88d15eacSSasha Smundak label: label + "/ParentStructF/PanicUnexported1", 1752*88d15eacSSasha Smundak x: ts.ParentStructF{}, 1753*88d15eacSSasha Smundak y: ts.ParentStructF{}, 1754*88d15eacSSasha Smundak opts: []cmp.Option{ 1755*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructF{}), 1756*88d15eacSSasha Smundak }, 1757*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1758*88d15eacSSasha Smundak reason: "ParentStructF has unexported fields", 1759*88d15eacSSasha Smundak }, { 1760*88d15eacSSasha Smundak label: label + "/ParentStructF/Ignored", 1761*88d15eacSSasha Smundak x: ts.ParentStructF{}, 1762*88d15eacSSasha Smundak y: ts.ParentStructF{}, 1763*88d15eacSSasha Smundak opts: []cmp.Option{ 1764*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructF{}), 1765*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.PublicStruct{}), 1766*88d15eacSSasha Smundak }, 1767*88d15eacSSasha Smundak wantEqual: true, 1768*88d15eacSSasha Smundak reason: "unexported fields of ParentStructF and PublicStruct are ignored", 1769*88d15eacSSasha Smundak }, { 1770*88d15eacSSasha Smundak label: label + "/ParentStructF/PanicUnexported2", 1771*88d15eacSSasha Smundak x: createStructF(0), 1772*88d15eacSSasha Smundak y: createStructF(0), 1773*88d15eacSSasha Smundak opts: []cmp.Option{ 1774*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructF{}), 1775*88d15eacSSasha Smundak }, 1776*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1777*88d15eacSSasha Smundak reason: "PublicStruct and privateStruct also has unexported fields", 1778*88d15eacSSasha Smundak }, { 1779*88d15eacSSasha Smundak label: label + "/ParentStructF/PanicUnexported3", 1780*88d15eacSSasha Smundak x: createStructF(0), 1781*88d15eacSSasha Smundak y: createStructF(0), 1782*88d15eacSSasha Smundak opts: []cmp.Option{ 1783*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}), 1784*88d15eacSSasha Smundak }, 1785*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1786*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1787*88d15eacSSasha Smundak }, { 1788*88d15eacSSasha Smundak label: label + "/ParentStructF/Equal", 1789*88d15eacSSasha Smundak x: createStructF(0), 1790*88d15eacSSasha Smundak y: createStructF(0), 1791*88d15eacSSasha Smundak opts: []cmp.Option{ 1792*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}, privateStruct), 1793*88d15eacSSasha Smundak }, 1794*88d15eacSSasha Smundak wantEqual: true, 1795*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructF, PublicStruct, and privateStruct are allowed", 1796*88d15eacSSasha Smundak }, { 1797*88d15eacSSasha Smundak label: label + "/ParentStructF/Inequal", 1798*88d15eacSSasha Smundak x: createStructF(0), 1799*88d15eacSSasha Smundak y: createStructF(1), 1800*88d15eacSSasha Smundak opts: []cmp.Option{ 1801*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructF{}, ts.PublicStruct{}, privateStruct), 1802*88d15eacSSasha Smundak }, 1803*88d15eacSSasha Smundak wantEqual: false, 1804*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1805*88d15eacSSasha Smundak }, { 1806*88d15eacSSasha Smundak label: label + "/ParentStructG/PanicUnexported1", 1807*88d15eacSSasha Smundak x: ts.ParentStructG{}, 1808*88d15eacSSasha Smundak y: ts.ParentStructG{}, 1809*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1810*88d15eacSSasha Smundak reason: "ParentStructG has unexported fields", 1811*88d15eacSSasha Smundak }, { 1812*88d15eacSSasha Smundak label: label + "/ParentStructG/Ignored", 1813*88d15eacSSasha Smundak x: ts.ParentStructG{}, 1814*88d15eacSSasha Smundak y: ts.ParentStructG{}, 1815*88d15eacSSasha Smundak opts: []cmp.Option{ 1816*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructG{}), 1817*88d15eacSSasha Smundak }, 1818*88d15eacSSasha Smundak wantEqual: true, 1819*88d15eacSSasha Smundak reason: "unexported fields of ParentStructG are ignored", 1820*88d15eacSSasha Smundak }, { 1821*88d15eacSSasha Smundak label: label + "/ParentStructG/PanicUnexported2", 1822*88d15eacSSasha Smundak x: createStructG(0), 1823*88d15eacSSasha Smundak y: createStructG(0), 1824*88d15eacSSasha Smundak opts: []cmp.Option{ 1825*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructG{}), 1826*88d15eacSSasha Smundak }, 1827*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1828*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1829*88d15eacSSasha Smundak }, { 1830*88d15eacSSasha Smundak label: label + "/ParentStructG/Equal", 1831*88d15eacSSasha Smundak x: createStructG(0), 1832*88d15eacSSasha Smundak y: createStructG(0), 1833*88d15eacSSasha Smundak opts: []cmp.Option{ 1834*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructG{}, privateStruct), 1835*88d15eacSSasha Smundak }, 1836*88d15eacSSasha Smundak wantEqual: true, 1837*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructG and privateStruct are allowed", 1838*88d15eacSSasha Smundak }, { 1839*88d15eacSSasha Smundak label: label + "/ParentStructG/Inequal", 1840*88d15eacSSasha Smundak x: createStructG(0), 1841*88d15eacSSasha Smundak y: createStructG(1), 1842*88d15eacSSasha Smundak opts: []cmp.Option{ 1843*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructG{}, privateStruct), 1844*88d15eacSSasha Smundak }, 1845*88d15eacSSasha Smundak wantEqual: false, 1846*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1847*88d15eacSSasha Smundak }, { 1848*88d15eacSSasha Smundak label: label + "/ParentStructH/EqualNil", 1849*88d15eacSSasha Smundak x: ts.ParentStructH{}, 1850*88d15eacSSasha Smundak y: ts.ParentStructH{}, 1851*88d15eacSSasha Smundak wantEqual: true, 1852*88d15eacSSasha Smundak reason: "PublicStruct is not compared because the pointer is nil", 1853*88d15eacSSasha Smundak }, { 1854*88d15eacSSasha Smundak label: label + "/ParentStructH/PanicUnexported1", 1855*88d15eacSSasha Smundak x: createStructH(0), 1856*88d15eacSSasha Smundak y: createStructH(0), 1857*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1858*88d15eacSSasha Smundak reason: "PublicStruct has unexported fields", 1859*88d15eacSSasha Smundak }, { 1860*88d15eacSSasha Smundak label: label + "/ParentStructH/Ignored", 1861*88d15eacSSasha Smundak x: ts.ParentStructH{}, 1862*88d15eacSSasha Smundak y: ts.ParentStructH{}, 1863*88d15eacSSasha Smundak opts: []cmp.Option{ 1864*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructH{}), 1865*88d15eacSSasha Smundak }, 1866*88d15eacSSasha Smundak wantEqual: true, 1867*88d15eacSSasha Smundak reason: "unexported fields of ParentStructH are ignored (it has none)", 1868*88d15eacSSasha Smundak }, { 1869*88d15eacSSasha Smundak label: label + "/ParentStructH/PanicUnexported2", 1870*88d15eacSSasha Smundak x: createStructH(0), 1871*88d15eacSSasha Smundak y: createStructH(0), 1872*88d15eacSSasha Smundak opts: []cmp.Option{ 1873*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructH{}), 1874*88d15eacSSasha Smundak }, 1875*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1876*88d15eacSSasha Smundak reason: "PublicStruct also has unexported fields", 1877*88d15eacSSasha Smundak }, { 1878*88d15eacSSasha Smundak label: label + "/ParentStructH/Equal", 1879*88d15eacSSasha Smundak x: createStructH(0), 1880*88d15eacSSasha Smundak y: createStructH(0), 1881*88d15eacSSasha Smundak opts: []cmp.Option{ 1882*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructH{}, ts.PublicStruct{}), 1883*88d15eacSSasha Smundak }, 1884*88d15eacSSasha Smundak wantEqual: true, 1885*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructH and PublicStruct are allowed", 1886*88d15eacSSasha Smundak }, { 1887*88d15eacSSasha Smundak label: label + "/ParentStructH/Inequal", 1888*88d15eacSSasha Smundak x: createStructH(0), 1889*88d15eacSSasha Smundak y: createStructH(1), 1890*88d15eacSSasha Smundak opts: []cmp.Option{ 1891*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructH{}, ts.PublicStruct{}), 1892*88d15eacSSasha Smundak }, 1893*88d15eacSSasha Smundak wantEqual: false, 1894*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1895*88d15eacSSasha Smundak }, { 1896*88d15eacSSasha Smundak label: label + "/ParentStructI/PanicUnexported1", 1897*88d15eacSSasha Smundak x: ts.ParentStructI{}, 1898*88d15eacSSasha Smundak y: ts.ParentStructI{}, 1899*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1900*88d15eacSSasha Smundak reason: "ParentStructI has unexported fields", 1901*88d15eacSSasha Smundak }, { 1902*88d15eacSSasha Smundak label: label + "/ParentStructI/Ignored1", 1903*88d15eacSSasha Smundak x: ts.ParentStructI{}, 1904*88d15eacSSasha Smundak y: ts.ParentStructI{}, 1905*88d15eacSSasha Smundak opts: []cmp.Option{ 1906*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructI{}), 1907*88d15eacSSasha Smundak }, 1908*88d15eacSSasha Smundak wantEqual: true, 1909*88d15eacSSasha Smundak reason: "unexported fields of ParentStructI are ignored", 1910*88d15eacSSasha Smundak }, { 1911*88d15eacSSasha Smundak label: label + "/ParentStructI/PanicUnexported2", 1912*88d15eacSSasha Smundak x: createStructI(0), 1913*88d15eacSSasha Smundak y: createStructI(0), 1914*88d15eacSSasha Smundak opts: []cmp.Option{ 1915*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructI{}), 1916*88d15eacSSasha Smundak }, 1917*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1918*88d15eacSSasha Smundak reason: "PublicStruct and privateStruct also has unexported fields", 1919*88d15eacSSasha Smundak }, { 1920*88d15eacSSasha Smundak label: label + "/ParentStructI/Ignored2", 1921*88d15eacSSasha Smundak x: createStructI(0), 1922*88d15eacSSasha Smundak y: createStructI(0), 1923*88d15eacSSasha Smundak opts: []cmp.Option{ 1924*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructI{}, ts.PublicStruct{}), 1925*88d15eacSSasha Smundak }, 1926*88d15eacSSasha Smundak wantEqual: true, 1927*88d15eacSSasha Smundak reason: "unexported fields of ParentStructI and PublicStruct are ignored", 1928*88d15eacSSasha Smundak }, { 1929*88d15eacSSasha Smundak label: label + "/ParentStructI/PanicUnexported3", 1930*88d15eacSSasha Smundak x: createStructI(0), 1931*88d15eacSSasha Smundak y: createStructI(0), 1932*88d15eacSSasha Smundak opts: []cmp.Option{ 1933*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructI{}), 1934*88d15eacSSasha Smundak }, 1935*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1936*88d15eacSSasha Smundak reason: "PublicStruct and privateStruct also has unexported fields", 1937*88d15eacSSasha Smundak }, { 1938*88d15eacSSasha Smundak label: label + "/ParentStructI/Equal", 1939*88d15eacSSasha Smundak x: createStructI(0), 1940*88d15eacSSasha Smundak y: createStructI(0), 1941*88d15eacSSasha Smundak opts: []cmp.Option{ 1942*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructI{}, ts.PublicStruct{}, privateStruct), 1943*88d15eacSSasha Smundak }, 1944*88d15eacSSasha Smundak wantEqual: true, 1945*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructI, PublicStruct, and privateStruct are allowed", 1946*88d15eacSSasha Smundak }, { 1947*88d15eacSSasha Smundak label: label + "/ParentStructI/Inequal", 1948*88d15eacSSasha Smundak x: createStructI(0), 1949*88d15eacSSasha Smundak y: createStructI(1), 1950*88d15eacSSasha Smundak opts: []cmp.Option{ 1951*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructI{}, ts.PublicStruct{}, privateStruct), 1952*88d15eacSSasha Smundak }, 1953*88d15eacSSasha Smundak wantEqual: false, 1954*88d15eacSSasha Smundak reason: "the two values differ on some fields", 1955*88d15eacSSasha Smundak }, { 1956*88d15eacSSasha Smundak label: label + "/ParentStructJ/PanicUnexported1", 1957*88d15eacSSasha Smundak x: ts.ParentStructJ{}, 1958*88d15eacSSasha Smundak y: ts.ParentStructJ{}, 1959*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1960*88d15eacSSasha Smundak reason: "ParentStructJ has unexported fields", 1961*88d15eacSSasha Smundak }, { 1962*88d15eacSSasha Smundak label: label + "/ParentStructJ/PanicUnexported2", 1963*88d15eacSSasha Smundak x: ts.ParentStructJ{}, 1964*88d15eacSSasha Smundak y: ts.ParentStructJ{}, 1965*88d15eacSSasha Smundak opts: []cmp.Option{ 1966*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructJ{}), 1967*88d15eacSSasha Smundak }, 1968*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1969*88d15eacSSasha Smundak reason: "PublicStruct and privateStruct also has unexported fields", 1970*88d15eacSSasha Smundak }, { 1971*88d15eacSSasha Smundak label: label + "/ParentStructJ/Ignored", 1972*88d15eacSSasha Smundak x: ts.ParentStructJ{}, 1973*88d15eacSSasha Smundak y: ts.ParentStructJ{}, 1974*88d15eacSSasha Smundak opts: []cmp.Option{ 1975*88d15eacSSasha Smundak cmpopts.IgnoreUnexported(ts.ParentStructJ{}, ts.PublicStruct{}), 1976*88d15eacSSasha Smundak }, 1977*88d15eacSSasha Smundak wantEqual: true, 1978*88d15eacSSasha Smundak reason: "unexported fields of ParentStructJ and PublicStruct are ignored", 1979*88d15eacSSasha Smundak }, { 1980*88d15eacSSasha Smundak label: label + "/ParentStructJ/PanicUnexported3", 1981*88d15eacSSasha Smundak x: createStructJ(0), 1982*88d15eacSSasha Smundak y: createStructJ(0), 1983*88d15eacSSasha Smundak opts: []cmp.Option{ 1984*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}), 1985*88d15eacSSasha Smundak }, 1986*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 1987*88d15eacSSasha Smundak reason: "privateStruct also has unexported fields", 1988*88d15eacSSasha Smundak }, { 1989*88d15eacSSasha Smundak label: label + "/ParentStructJ/Equal", 1990*88d15eacSSasha Smundak x: createStructJ(0), 1991*88d15eacSSasha Smundak y: createStructJ(0), 1992*88d15eacSSasha Smundak opts: []cmp.Option{ 1993*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}, privateStruct), 1994*88d15eacSSasha Smundak }, 1995*88d15eacSSasha Smundak wantEqual: true, 1996*88d15eacSSasha Smundak reason: "unexported fields of both ParentStructJ, PublicStruct, and privateStruct are allowed", 1997*88d15eacSSasha Smundak }, { 1998*88d15eacSSasha Smundak label: label + "/ParentStructJ/Inequal", 1999*88d15eacSSasha Smundak x: createStructJ(0), 2000*88d15eacSSasha Smundak y: createStructJ(1), 2001*88d15eacSSasha Smundak opts: []cmp.Option{ 2002*88d15eacSSasha Smundak cmp.AllowUnexported(ts.ParentStructJ{}, ts.PublicStruct{}, privateStruct), 2003*88d15eacSSasha Smundak }, 2004*88d15eacSSasha Smundak wantEqual: false, 2005*88d15eacSSasha Smundak reason: "the two values differ on some fields", 2006*88d15eacSSasha Smundak }} 2007*88d15eacSSasha Smundak} 2008*88d15eacSSasha Smundak 2009*88d15eacSSasha Smundakfunc methodTests() []test { 2010*88d15eacSSasha Smundak const label = "EqualMethod" 2011*88d15eacSSasha Smundak 2012*88d15eacSSasha Smundak // A common mistake that the Equal method is on a pointer receiver, 2013*88d15eacSSasha Smundak // but only a non-pointer value is present in the struct. 2014*88d15eacSSasha Smundak // A transform can be used to forcibly reference the value. 2015*88d15eacSSasha Smundak addrTransform := cmp.FilterPath(func(p cmp.Path) bool { 2016*88d15eacSSasha Smundak if len(p) == 0 { 2017*88d15eacSSasha Smundak return false 2018*88d15eacSSasha Smundak } 2019*88d15eacSSasha Smundak t := p[len(p)-1].Type() 2020*88d15eacSSasha Smundak if _, ok := t.MethodByName("Equal"); ok || t.Kind() == reflect.Ptr { 2021*88d15eacSSasha Smundak return false 2022*88d15eacSSasha Smundak } 2023*88d15eacSSasha Smundak if m, ok := reflect.PtrTo(t).MethodByName("Equal"); ok { 2024*88d15eacSSasha Smundak tf := m.Func.Type() 2025*88d15eacSSasha Smundak return !tf.IsVariadic() && tf.NumIn() == 2 && tf.NumOut() == 1 && 2026*88d15eacSSasha Smundak tf.In(0).AssignableTo(tf.In(1)) && tf.Out(0) == reflect.TypeOf(true) 2027*88d15eacSSasha Smundak } 2028*88d15eacSSasha Smundak return false 2029*88d15eacSSasha Smundak }, cmp.Transformer("Addr", func(x interface{}) interface{} { 2030*88d15eacSSasha Smundak v := reflect.ValueOf(x) 2031*88d15eacSSasha Smundak vp := reflect.New(v.Type()) 2032*88d15eacSSasha Smundak vp.Elem().Set(v) 2033*88d15eacSSasha Smundak return vp.Interface() 2034*88d15eacSSasha Smundak })) 2035*88d15eacSSasha Smundak 2036*88d15eacSSasha Smundak // For each of these types, there is an Equal method defined, which always 2037*88d15eacSSasha Smundak // returns true, while the underlying data are fundamentally different. 2038*88d15eacSSasha Smundak // Since the method should be called, these are expected to be equal. 2039*88d15eacSSasha Smundak return []test{{ 2040*88d15eacSSasha Smundak label: label + "/StructA/ValueEqual", 2041*88d15eacSSasha Smundak x: ts.StructA{X: "NotEqual"}, 2042*88d15eacSSasha Smundak y: ts.StructA{X: "not_equal"}, 2043*88d15eacSSasha Smundak wantEqual: true, 2044*88d15eacSSasha Smundak reason: "Equal method on StructA value called", 2045*88d15eacSSasha Smundak }, { 2046*88d15eacSSasha Smundak label: label + "/StructA/PointerEqual", 2047*88d15eacSSasha Smundak x: &ts.StructA{X: "NotEqual"}, 2048*88d15eacSSasha Smundak y: &ts.StructA{X: "not_equal"}, 2049*88d15eacSSasha Smundak wantEqual: true, 2050*88d15eacSSasha Smundak reason: "Equal method on StructA pointer called", 2051*88d15eacSSasha Smundak }, { 2052*88d15eacSSasha Smundak label: label + "/StructB/ValueInequal", 2053*88d15eacSSasha Smundak x: ts.StructB{X: "NotEqual"}, 2054*88d15eacSSasha Smundak y: ts.StructB{X: "not_equal"}, 2055*88d15eacSSasha Smundak wantEqual: false, 2056*88d15eacSSasha Smundak reason: "Equal method on StructB value not called", 2057*88d15eacSSasha Smundak }, { 2058*88d15eacSSasha Smundak label: label + "/StructB/ValueAddrEqual", 2059*88d15eacSSasha Smundak x: ts.StructB{X: "NotEqual"}, 2060*88d15eacSSasha Smundak y: ts.StructB{X: "not_equal"}, 2061*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2062*88d15eacSSasha Smundak wantEqual: true, 2063*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called due to shallow copy transform", 2064*88d15eacSSasha Smundak }, { 2065*88d15eacSSasha Smundak label: label + "/StructB/PointerEqual", 2066*88d15eacSSasha Smundak x: &ts.StructB{X: "NotEqual"}, 2067*88d15eacSSasha Smundak y: &ts.StructB{X: "not_equal"}, 2068*88d15eacSSasha Smundak wantEqual: true, 2069*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called", 2070*88d15eacSSasha Smundak }, { 2071*88d15eacSSasha Smundak label: label + "/StructC/ValueEqual", 2072*88d15eacSSasha Smundak x: ts.StructC{X: "NotEqual"}, 2073*88d15eacSSasha Smundak y: ts.StructC{X: "not_equal"}, 2074*88d15eacSSasha Smundak wantEqual: true, 2075*88d15eacSSasha Smundak reason: "Equal method on StructC value called", 2076*88d15eacSSasha Smundak }, { 2077*88d15eacSSasha Smundak label: label + "/StructC/PointerEqual", 2078*88d15eacSSasha Smundak x: &ts.StructC{X: "NotEqual"}, 2079*88d15eacSSasha Smundak y: &ts.StructC{X: "not_equal"}, 2080*88d15eacSSasha Smundak wantEqual: true, 2081*88d15eacSSasha Smundak reason: "Equal method on StructC pointer called", 2082*88d15eacSSasha Smundak }, { 2083*88d15eacSSasha Smundak label: label + "/StructD/ValueInequal", 2084*88d15eacSSasha Smundak x: ts.StructD{X: "NotEqual"}, 2085*88d15eacSSasha Smundak y: ts.StructD{X: "not_equal"}, 2086*88d15eacSSasha Smundak wantEqual: false, 2087*88d15eacSSasha Smundak reason: "Equal method on StructD value not called", 2088*88d15eacSSasha Smundak }, { 2089*88d15eacSSasha Smundak label: label + "/StructD/ValueAddrEqual", 2090*88d15eacSSasha Smundak x: ts.StructD{X: "NotEqual"}, 2091*88d15eacSSasha Smundak y: ts.StructD{X: "not_equal"}, 2092*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2093*88d15eacSSasha Smundak wantEqual: true, 2094*88d15eacSSasha Smundak reason: "Equal method on StructD pointer called due to shallow copy transform", 2095*88d15eacSSasha Smundak }, { 2096*88d15eacSSasha Smundak label: label + "/StructD/PointerEqual", 2097*88d15eacSSasha Smundak x: &ts.StructD{X: "NotEqual"}, 2098*88d15eacSSasha Smundak y: &ts.StructD{X: "not_equal"}, 2099*88d15eacSSasha Smundak wantEqual: true, 2100*88d15eacSSasha Smundak reason: "Equal method on StructD pointer called", 2101*88d15eacSSasha Smundak }, { 2102*88d15eacSSasha Smundak label: label + "/StructE/ValueInequal", 2103*88d15eacSSasha Smundak x: ts.StructE{X: "NotEqual"}, 2104*88d15eacSSasha Smundak y: ts.StructE{X: "not_equal"}, 2105*88d15eacSSasha Smundak wantEqual: false, 2106*88d15eacSSasha Smundak reason: "Equal method on StructE value not called", 2107*88d15eacSSasha Smundak }, { 2108*88d15eacSSasha Smundak label: label + "/StructE/ValueAddrEqual", 2109*88d15eacSSasha Smundak x: ts.StructE{X: "NotEqual"}, 2110*88d15eacSSasha Smundak y: ts.StructE{X: "not_equal"}, 2111*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2112*88d15eacSSasha Smundak wantEqual: true, 2113*88d15eacSSasha Smundak reason: "Equal method on StructE pointer called due to shallow copy transform", 2114*88d15eacSSasha Smundak }, { 2115*88d15eacSSasha Smundak label: label + "/StructE/PointerEqual", 2116*88d15eacSSasha Smundak x: &ts.StructE{X: "NotEqual"}, 2117*88d15eacSSasha Smundak y: &ts.StructE{X: "not_equal"}, 2118*88d15eacSSasha Smundak wantEqual: true, 2119*88d15eacSSasha Smundak reason: "Equal method on StructE pointer called", 2120*88d15eacSSasha Smundak }, { 2121*88d15eacSSasha Smundak label: label + "/StructF/ValueInequal", 2122*88d15eacSSasha Smundak x: ts.StructF{X: "NotEqual"}, 2123*88d15eacSSasha Smundak y: ts.StructF{X: "not_equal"}, 2124*88d15eacSSasha Smundak wantEqual: false, 2125*88d15eacSSasha Smundak reason: "Equal method on StructF value not called", 2126*88d15eacSSasha Smundak }, { 2127*88d15eacSSasha Smundak label: label + "/StructF/PointerEqual", 2128*88d15eacSSasha Smundak x: &ts.StructF{X: "NotEqual"}, 2129*88d15eacSSasha Smundak y: &ts.StructF{X: "not_equal"}, 2130*88d15eacSSasha Smundak wantEqual: true, 2131*88d15eacSSasha Smundak reason: "Equal method on StructF pointer called", 2132*88d15eacSSasha Smundak }, { 2133*88d15eacSSasha Smundak label: label + "/StructA1/ValueEqual", 2134*88d15eacSSasha Smundak x: ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "equal"}, 2135*88d15eacSSasha Smundak y: ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "equal"}, 2136*88d15eacSSasha Smundak wantEqual: true, 2137*88d15eacSSasha Smundak reason: "Equal method on StructA value called with equal X field", 2138*88d15eacSSasha Smundak }, { 2139*88d15eacSSasha Smundak label: label + "/StructA1/ValueInequal", 2140*88d15eacSSasha Smundak x: ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "NotEqual"}, 2141*88d15eacSSasha Smundak y: ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "not_equal"}, 2142*88d15eacSSasha Smundak wantEqual: false, 2143*88d15eacSSasha Smundak reason: "Equal method on StructA value called, but inequal X field", 2144*88d15eacSSasha Smundak }, { 2145*88d15eacSSasha Smundak label: label + "/StructA1/PointerEqual", 2146*88d15eacSSasha Smundak x: &ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "equal"}, 2147*88d15eacSSasha Smundak y: &ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "equal"}, 2148*88d15eacSSasha Smundak wantEqual: true, 2149*88d15eacSSasha Smundak reason: "Equal method on StructA value called with equal X field", 2150*88d15eacSSasha Smundak }, { 2151*88d15eacSSasha Smundak label: label + "/StructA1/PointerInequal", 2152*88d15eacSSasha Smundak x: &ts.StructA1{StructA: ts.StructA{X: "NotEqual"}, X: "NotEqual"}, 2153*88d15eacSSasha Smundak y: &ts.StructA1{StructA: ts.StructA{X: "not_equal"}, X: "not_equal"}, 2154*88d15eacSSasha Smundak wantEqual: false, 2155*88d15eacSSasha Smundak reason: "Equal method on StructA value called, but inequal X field", 2156*88d15eacSSasha Smundak }, { 2157*88d15eacSSasha Smundak label: label + "/StructB1/ValueEqual", 2158*88d15eacSSasha Smundak x: ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "equal"}, 2159*88d15eacSSasha Smundak y: ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "equal"}, 2160*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2161*88d15eacSSasha Smundak wantEqual: true, 2162*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called due to shallow copy transform with equal X field", 2163*88d15eacSSasha Smundak }, { 2164*88d15eacSSasha Smundak label: label + "/StructB1/ValueInequal", 2165*88d15eacSSasha Smundak x: ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "NotEqual"}, 2166*88d15eacSSasha Smundak y: ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "not_equal"}, 2167*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2168*88d15eacSSasha Smundak wantEqual: false, 2169*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called due to shallow copy transform, but inequal X field", 2170*88d15eacSSasha Smundak }, { 2171*88d15eacSSasha Smundak label: label + "/StructB1/PointerEqual", 2172*88d15eacSSasha Smundak x: &ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "equal"}, 2173*88d15eacSSasha Smundak y: &ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "equal"}, 2174*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2175*88d15eacSSasha Smundak wantEqual: true, 2176*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called due to shallow copy transform with equal X field", 2177*88d15eacSSasha Smundak }, { 2178*88d15eacSSasha Smundak label: label + "/StructB1/PointerInequal", 2179*88d15eacSSasha Smundak x: &ts.StructB1{StructB: ts.StructB{X: "NotEqual"}, X: "NotEqual"}, 2180*88d15eacSSasha Smundak y: &ts.StructB1{StructB: ts.StructB{X: "not_equal"}, X: "not_equal"}, 2181*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2182*88d15eacSSasha Smundak wantEqual: false, 2183*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called due to shallow copy transform, but inequal X field", 2184*88d15eacSSasha Smundak }, { 2185*88d15eacSSasha Smundak label: label + "/StructC1/ValueEqual", 2186*88d15eacSSasha Smundak x: ts.StructC1{StructC: ts.StructC{X: "NotEqual"}, X: "NotEqual"}, 2187*88d15eacSSasha Smundak y: ts.StructC1{StructC: ts.StructC{X: "not_equal"}, X: "not_equal"}, 2188*88d15eacSSasha Smundak wantEqual: true, 2189*88d15eacSSasha Smundak reason: "Equal method on StructC1 value called", 2190*88d15eacSSasha Smundak }, { 2191*88d15eacSSasha Smundak label: label + "/StructC1/PointerEqual", 2192*88d15eacSSasha Smundak x: &ts.StructC1{StructC: ts.StructC{X: "NotEqual"}, X: "NotEqual"}, 2193*88d15eacSSasha Smundak y: &ts.StructC1{StructC: ts.StructC{X: "not_equal"}, X: "not_equal"}, 2194*88d15eacSSasha Smundak wantEqual: true, 2195*88d15eacSSasha Smundak reason: "Equal method on StructC1 pointer called", 2196*88d15eacSSasha Smundak }, { 2197*88d15eacSSasha Smundak label: label + "/StructD1/ValueInequal", 2198*88d15eacSSasha Smundak x: ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, 2199*88d15eacSSasha Smundak y: ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, 2200*88d15eacSSasha Smundak wantEqual: false, 2201*88d15eacSSasha Smundak reason: "Equal method on StructD1 value not called", 2202*88d15eacSSasha Smundak }, { 2203*88d15eacSSasha Smundak label: label + "/StructD1/PointerAddrEqual", 2204*88d15eacSSasha Smundak x: ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, 2205*88d15eacSSasha Smundak y: ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, 2206*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2207*88d15eacSSasha Smundak wantEqual: true, 2208*88d15eacSSasha Smundak reason: "Equal method on StructD1 pointer called due to shallow copy transform", 2209*88d15eacSSasha Smundak }, { 2210*88d15eacSSasha Smundak label: label + "/StructD1/PointerEqual", 2211*88d15eacSSasha Smundak x: &ts.StructD1{StructD: ts.StructD{X: "NotEqual"}, X: "NotEqual"}, 2212*88d15eacSSasha Smundak y: &ts.StructD1{StructD: ts.StructD{X: "not_equal"}, X: "not_equal"}, 2213*88d15eacSSasha Smundak wantEqual: true, 2214*88d15eacSSasha Smundak reason: "Equal method on StructD1 pointer called", 2215*88d15eacSSasha Smundak }, { 2216*88d15eacSSasha Smundak label: label + "/StructE1/ValueInequal", 2217*88d15eacSSasha Smundak x: ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, 2218*88d15eacSSasha Smundak y: ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, 2219*88d15eacSSasha Smundak wantEqual: false, 2220*88d15eacSSasha Smundak reason: "Equal method on StructE1 value not called", 2221*88d15eacSSasha Smundak }, { 2222*88d15eacSSasha Smundak label: label + "/StructE1/ValueAddrEqual", 2223*88d15eacSSasha Smundak x: ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, 2224*88d15eacSSasha Smundak y: ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, 2225*88d15eacSSasha Smundak opts: []cmp.Option{addrTransform}, 2226*88d15eacSSasha Smundak wantEqual: true, 2227*88d15eacSSasha Smundak reason: "Equal method on StructE1 pointer called due to shallow copy transform", 2228*88d15eacSSasha Smundak }, { 2229*88d15eacSSasha Smundak label: label + "/StructE1/PointerEqual", 2230*88d15eacSSasha Smundak x: &ts.StructE1{StructE: ts.StructE{X: "NotEqual"}, X: "NotEqual"}, 2231*88d15eacSSasha Smundak y: &ts.StructE1{StructE: ts.StructE{X: "not_equal"}, X: "not_equal"}, 2232*88d15eacSSasha Smundak wantEqual: true, 2233*88d15eacSSasha Smundak reason: "Equal method on StructE1 pointer called", 2234*88d15eacSSasha Smundak }, { 2235*88d15eacSSasha Smundak label: label + "/StructF1/ValueInequal", 2236*88d15eacSSasha Smundak x: ts.StructF1{StructF: ts.StructF{X: "NotEqual"}, X: "NotEqual"}, 2237*88d15eacSSasha Smundak y: ts.StructF1{StructF: ts.StructF{X: "not_equal"}, X: "not_equal"}, 2238*88d15eacSSasha Smundak wantEqual: false, 2239*88d15eacSSasha Smundak reason: "Equal method on StructF1 value not called", 2240*88d15eacSSasha Smundak }, { 2241*88d15eacSSasha Smundak label: label + "/StructF1/PointerEqual", 2242*88d15eacSSasha Smundak x: &ts.StructF1{StructF: ts.StructF{X: "NotEqual"}, X: "NotEqual"}, 2243*88d15eacSSasha Smundak y: &ts.StructF1{StructF: ts.StructF{X: "not_equal"}, X: "not_equal"}, 2244*88d15eacSSasha Smundak wantEqual: true, 2245*88d15eacSSasha Smundak reason: "Equal method on StructF1 pointer called", 2246*88d15eacSSasha Smundak }, { 2247*88d15eacSSasha Smundak label: label + "/StructA2/ValueEqual", 2248*88d15eacSSasha Smundak x: ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "equal"}, 2249*88d15eacSSasha Smundak y: ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "equal"}, 2250*88d15eacSSasha Smundak wantEqual: true, 2251*88d15eacSSasha Smundak reason: "Equal method on StructA pointer called with equal X field", 2252*88d15eacSSasha Smundak }, { 2253*88d15eacSSasha Smundak label: label + "/StructA2/ValueInequal", 2254*88d15eacSSasha Smundak x: ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "NotEqual"}, 2255*88d15eacSSasha Smundak y: ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "not_equal"}, 2256*88d15eacSSasha Smundak wantEqual: false, 2257*88d15eacSSasha Smundak reason: "Equal method on StructA pointer called, but inequal X field", 2258*88d15eacSSasha Smundak }, { 2259*88d15eacSSasha Smundak label: label + "/StructA2/PointerEqual", 2260*88d15eacSSasha Smundak x: &ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "equal"}, 2261*88d15eacSSasha Smundak y: &ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "equal"}, 2262*88d15eacSSasha Smundak wantEqual: true, 2263*88d15eacSSasha Smundak reason: "Equal method on StructA pointer called with equal X field", 2264*88d15eacSSasha Smundak }, { 2265*88d15eacSSasha Smundak label: label + "/StructA2/PointerInequal", 2266*88d15eacSSasha Smundak x: &ts.StructA2{StructA: &ts.StructA{X: "NotEqual"}, X: "NotEqual"}, 2267*88d15eacSSasha Smundak y: &ts.StructA2{StructA: &ts.StructA{X: "not_equal"}, X: "not_equal"}, 2268*88d15eacSSasha Smundak wantEqual: false, 2269*88d15eacSSasha Smundak reason: "Equal method on StructA pointer called, but inequal X field", 2270*88d15eacSSasha Smundak }, { 2271*88d15eacSSasha Smundak label: label + "/StructB2/ValueEqual", 2272*88d15eacSSasha Smundak x: ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "equal"}, 2273*88d15eacSSasha Smundak y: ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "equal"}, 2274*88d15eacSSasha Smundak wantEqual: true, 2275*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called with equal X field", 2276*88d15eacSSasha Smundak }, { 2277*88d15eacSSasha Smundak label: label + "/StructB2/ValueInequal", 2278*88d15eacSSasha Smundak x: ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "NotEqual"}, 2279*88d15eacSSasha Smundak y: ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "not_equal"}, 2280*88d15eacSSasha Smundak wantEqual: false, 2281*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called, but inequal X field", 2282*88d15eacSSasha Smundak }, { 2283*88d15eacSSasha Smundak label: label + "/StructB2/PointerEqual", 2284*88d15eacSSasha Smundak x: &ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "equal"}, 2285*88d15eacSSasha Smundak y: &ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "equal"}, 2286*88d15eacSSasha Smundak wantEqual: true, 2287*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called with equal X field", 2288*88d15eacSSasha Smundak }, { 2289*88d15eacSSasha Smundak label: label + "/StructB2/PointerInequal", 2290*88d15eacSSasha Smundak x: &ts.StructB2{StructB: &ts.StructB{X: "NotEqual"}, X: "NotEqual"}, 2291*88d15eacSSasha Smundak y: &ts.StructB2{StructB: &ts.StructB{X: "not_equal"}, X: "not_equal"}, 2292*88d15eacSSasha Smundak wantEqual: false, 2293*88d15eacSSasha Smundak reason: "Equal method on StructB pointer called, but inequal X field", 2294*88d15eacSSasha Smundak }, { 2295*88d15eacSSasha Smundak label: label + "/StructC2/ValueEqual", 2296*88d15eacSSasha Smundak x: ts.StructC2{StructC: &ts.StructC{X: "NotEqual"}, X: "NotEqual"}, 2297*88d15eacSSasha Smundak y: ts.StructC2{StructC: &ts.StructC{X: "not_equal"}, X: "not_equal"}, 2298*88d15eacSSasha Smundak wantEqual: true, 2299*88d15eacSSasha Smundak reason: "Equal method called on StructC2 value due to forwarded StructC pointer", 2300*88d15eacSSasha Smundak }, { 2301*88d15eacSSasha Smundak label: label + "/StructC2/PointerEqual", 2302*88d15eacSSasha Smundak x: &ts.StructC2{StructC: &ts.StructC{X: "NotEqual"}, X: "NotEqual"}, 2303*88d15eacSSasha Smundak y: &ts.StructC2{StructC: &ts.StructC{X: "not_equal"}, X: "not_equal"}, 2304*88d15eacSSasha Smundak wantEqual: true, 2305*88d15eacSSasha Smundak reason: "Equal method called on StructC2 pointer due to forwarded StructC pointer", 2306*88d15eacSSasha Smundak }, { 2307*88d15eacSSasha Smundak label: label + "/StructD2/ValueEqual", 2308*88d15eacSSasha Smundak x: ts.StructD2{StructD: &ts.StructD{X: "NotEqual"}, X: "NotEqual"}, 2309*88d15eacSSasha Smundak y: ts.StructD2{StructD: &ts.StructD{X: "not_equal"}, X: "not_equal"}, 2310*88d15eacSSasha Smundak wantEqual: true, 2311*88d15eacSSasha Smundak reason: "Equal method called on StructD2 value due to forwarded StructD pointer", 2312*88d15eacSSasha Smundak }, { 2313*88d15eacSSasha Smundak label: label + "/StructD2/PointerEqual", 2314*88d15eacSSasha Smundak x: &ts.StructD2{StructD: &ts.StructD{X: "NotEqual"}, X: "NotEqual"}, 2315*88d15eacSSasha Smundak y: &ts.StructD2{StructD: &ts.StructD{X: "not_equal"}, X: "not_equal"}, 2316*88d15eacSSasha Smundak wantEqual: true, 2317*88d15eacSSasha Smundak reason: "Equal method called on StructD2 pointer due to forwarded StructD pointer", 2318*88d15eacSSasha Smundak }, { 2319*88d15eacSSasha Smundak label: label + "/StructE2/ValueEqual", 2320*88d15eacSSasha Smundak x: ts.StructE2{StructE: &ts.StructE{X: "NotEqual"}, X: "NotEqual"}, 2321*88d15eacSSasha Smundak y: ts.StructE2{StructE: &ts.StructE{X: "not_equal"}, X: "not_equal"}, 2322*88d15eacSSasha Smundak wantEqual: true, 2323*88d15eacSSasha Smundak reason: "Equal method called on StructE2 value due to forwarded StructE pointer", 2324*88d15eacSSasha Smundak }, { 2325*88d15eacSSasha Smundak label: label + "/StructE2/PointerEqual", 2326*88d15eacSSasha Smundak x: &ts.StructE2{StructE: &ts.StructE{X: "NotEqual"}, X: "NotEqual"}, 2327*88d15eacSSasha Smundak y: &ts.StructE2{StructE: &ts.StructE{X: "not_equal"}, X: "not_equal"}, 2328*88d15eacSSasha Smundak wantEqual: true, 2329*88d15eacSSasha Smundak reason: "Equal method called on StructE2 pointer due to forwarded StructE pointer", 2330*88d15eacSSasha Smundak }, { 2331*88d15eacSSasha Smundak label: label + "/StructF2/ValueEqual", 2332*88d15eacSSasha Smundak x: ts.StructF2{StructF: &ts.StructF{X: "NotEqual"}, X: "NotEqual"}, 2333*88d15eacSSasha Smundak y: ts.StructF2{StructF: &ts.StructF{X: "not_equal"}, X: "not_equal"}, 2334*88d15eacSSasha Smundak wantEqual: true, 2335*88d15eacSSasha Smundak reason: "Equal method called on StructF2 value due to forwarded StructF pointer", 2336*88d15eacSSasha Smundak }, { 2337*88d15eacSSasha Smundak label: label + "/StructF2/PointerEqual", 2338*88d15eacSSasha Smundak x: &ts.StructF2{StructF: &ts.StructF{X: "NotEqual"}, X: "NotEqual"}, 2339*88d15eacSSasha Smundak y: &ts.StructF2{StructF: &ts.StructF{X: "not_equal"}, X: "not_equal"}, 2340*88d15eacSSasha Smundak wantEqual: true, 2341*88d15eacSSasha Smundak reason: "Equal method called on StructF2 pointer due to forwarded StructF pointer", 2342*88d15eacSSasha Smundak }, { 2343*88d15eacSSasha Smundak label: label + "/StructNo/Inequal", 2344*88d15eacSSasha Smundak x: ts.StructNo{X: "NotEqual"}, 2345*88d15eacSSasha Smundak y: ts.StructNo{X: "not_equal"}, 2346*88d15eacSSasha Smundak wantEqual: false, 2347*88d15eacSSasha Smundak reason: "Equal method not called since StructNo is not assignable to InterfaceA", 2348*88d15eacSSasha Smundak }, { 2349*88d15eacSSasha Smundak label: label + "/AssignA/Equal", 2350*88d15eacSSasha Smundak x: ts.AssignA(func() int { return 0 }), 2351*88d15eacSSasha Smundak y: ts.AssignA(func() int { return 1 }), 2352*88d15eacSSasha Smundak wantEqual: true, 2353*88d15eacSSasha Smundak reason: "Equal method called since named func is assignable to unnamed func", 2354*88d15eacSSasha Smundak }, { 2355*88d15eacSSasha Smundak label: label + "/AssignB/Equal", 2356*88d15eacSSasha Smundak x: ts.AssignB(struct{ A int }{0}), 2357*88d15eacSSasha Smundak y: ts.AssignB(struct{ A int }{1}), 2358*88d15eacSSasha Smundak wantEqual: true, 2359*88d15eacSSasha Smundak reason: "Equal method called since named struct is assignable to unnamed struct", 2360*88d15eacSSasha Smundak }, { 2361*88d15eacSSasha Smundak label: label + "/AssignC/Equal", 2362*88d15eacSSasha Smundak x: ts.AssignC(make(chan bool)), 2363*88d15eacSSasha Smundak y: ts.AssignC(make(chan bool)), 2364*88d15eacSSasha Smundak wantEqual: true, 2365*88d15eacSSasha Smundak reason: "Equal method called since named channel is assignable to unnamed channel", 2366*88d15eacSSasha Smundak }, { 2367*88d15eacSSasha Smundak label: label + "/AssignD/Equal", 2368*88d15eacSSasha Smundak x: ts.AssignD(make(chan bool)), 2369*88d15eacSSasha Smundak y: ts.AssignD(make(chan bool)), 2370*88d15eacSSasha Smundak wantEqual: true, 2371*88d15eacSSasha Smundak reason: "Equal method called since named channel is assignable to unnamed channel", 2372*88d15eacSSasha Smundak }} 2373*88d15eacSSasha Smundak} 2374*88d15eacSSasha Smundak 2375*88d15eacSSasha Smundaktype ( 2376*88d15eacSSasha Smundak CycleAlpha struct { 2377*88d15eacSSasha Smundak Name string 2378*88d15eacSSasha Smundak Bravos map[string]*CycleBravo 2379*88d15eacSSasha Smundak } 2380*88d15eacSSasha Smundak CycleBravo struct { 2381*88d15eacSSasha Smundak ID int 2382*88d15eacSSasha Smundak Name string 2383*88d15eacSSasha Smundak Mods int 2384*88d15eacSSasha Smundak Alphas map[string]*CycleAlpha 2385*88d15eacSSasha Smundak } 2386*88d15eacSSasha Smundak) 2387*88d15eacSSasha Smundak 2388*88d15eacSSasha Smundakfunc cycleTests() []test { 2389*88d15eacSSasha Smundak const label = "Cycle" 2390*88d15eacSSasha Smundak 2391*88d15eacSSasha Smundak type ( 2392*88d15eacSSasha Smundak P *P 2393*88d15eacSSasha Smundak S []S 2394*88d15eacSSasha Smundak M map[int]M 2395*88d15eacSSasha Smundak ) 2396*88d15eacSSasha Smundak 2397*88d15eacSSasha Smundak makeGraph := func() map[string]*CycleAlpha { 2398*88d15eacSSasha Smundak v := map[string]*CycleAlpha{ 2399*88d15eacSSasha Smundak "Foo": &CycleAlpha{ 2400*88d15eacSSasha Smundak Name: "Foo", 2401*88d15eacSSasha Smundak Bravos: map[string]*CycleBravo{ 2402*88d15eacSSasha Smundak "FooBravo": &CycleBravo{ 2403*88d15eacSSasha Smundak Name: "FooBravo", 2404*88d15eacSSasha Smundak ID: 101, 2405*88d15eacSSasha Smundak Mods: 100, 2406*88d15eacSSasha Smundak Alphas: map[string]*CycleAlpha{ 2407*88d15eacSSasha Smundak "Foo": nil, // cyclic reference 2408*88d15eacSSasha Smundak }, 2409*88d15eacSSasha Smundak }, 2410*88d15eacSSasha Smundak }, 2411*88d15eacSSasha Smundak }, 2412*88d15eacSSasha Smundak "Bar": &CycleAlpha{ 2413*88d15eacSSasha Smundak Name: "Bar", 2414*88d15eacSSasha Smundak Bravos: map[string]*CycleBravo{ 2415*88d15eacSSasha Smundak "BarBuzzBravo": &CycleBravo{ 2416*88d15eacSSasha Smundak Name: "BarBuzzBravo", 2417*88d15eacSSasha Smundak ID: 102, 2418*88d15eacSSasha Smundak Mods: 2, 2419*88d15eacSSasha Smundak Alphas: map[string]*CycleAlpha{ 2420*88d15eacSSasha Smundak "Bar": nil, // cyclic reference 2421*88d15eacSSasha Smundak "Buzz": nil, // cyclic reference 2422*88d15eacSSasha Smundak }, 2423*88d15eacSSasha Smundak }, 2424*88d15eacSSasha Smundak "BuzzBarBravo": &CycleBravo{ 2425*88d15eacSSasha Smundak Name: "BuzzBarBravo", 2426*88d15eacSSasha Smundak ID: 103, 2427*88d15eacSSasha Smundak Mods: 0, 2428*88d15eacSSasha Smundak Alphas: map[string]*CycleAlpha{ 2429*88d15eacSSasha Smundak "Bar": nil, // cyclic reference 2430*88d15eacSSasha Smundak "Buzz": nil, // cyclic reference 2431*88d15eacSSasha Smundak }, 2432*88d15eacSSasha Smundak }, 2433*88d15eacSSasha Smundak }, 2434*88d15eacSSasha Smundak }, 2435*88d15eacSSasha Smundak "Buzz": &CycleAlpha{ 2436*88d15eacSSasha Smundak Name: "Buzz", 2437*88d15eacSSasha Smundak Bravos: map[string]*CycleBravo{ 2438*88d15eacSSasha Smundak "BarBuzzBravo": nil, // cyclic reference 2439*88d15eacSSasha Smundak "BuzzBarBravo": nil, // cyclic reference 2440*88d15eacSSasha Smundak }, 2441*88d15eacSSasha Smundak }, 2442*88d15eacSSasha Smundak } 2443*88d15eacSSasha Smundak v["Foo"].Bravos["FooBravo"].Alphas["Foo"] = v["Foo"] 2444*88d15eacSSasha Smundak v["Bar"].Bravos["BarBuzzBravo"].Alphas["Bar"] = v["Bar"] 2445*88d15eacSSasha Smundak v["Bar"].Bravos["BarBuzzBravo"].Alphas["Buzz"] = v["Buzz"] 2446*88d15eacSSasha Smundak v["Bar"].Bravos["BuzzBarBravo"].Alphas["Bar"] = v["Bar"] 2447*88d15eacSSasha Smundak v["Bar"].Bravos["BuzzBarBravo"].Alphas["Buzz"] = v["Buzz"] 2448*88d15eacSSasha Smundak v["Buzz"].Bravos["BarBuzzBravo"] = v["Bar"].Bravos["BarBuzzBravo"] 2449*88d15eacSSasha Smundak v["Buzz"].Bravos["BuzzBarBravo"] = v["Bar"].Bravos["BuzzBarBravo"] 2450*88d15eacSSasha Smundak return v 2451*88d15eacSSasha Smundak } 2452*88d15eacSSasha Smundak 2453*88d15eacSSasha Smundak var tests []test 2454*88d15eacSSasha Smundak type XY struct{ x, y interface{} } 2455*88d15eacSSasha Smundak for _, tt := range []struct { 2456*88d15eacSSasha Smundak label string 2457*88d15eacSSasha Smundak in XY 2458*88d15eacSSasha Smundak wantEqual bool 2459*88d15eacSSasha Smundak reason string 2460*88d15eacSSasha Smundak }{{ 2461*88d15eacSSasha Smundak label: "PointersEqual", 2462*88d15eacSSasha Smundak in: func() XY { 2463*88d15eacSSasha Smundak x := new(P) 2464*88d15eacSSasha Smundak *x = x 2465*88d15eacSSasha Smundak y := new(P) 2466*88d15eacSSasha Smundak *y = y 2467*88d15eacSSasha Smundak return XY{x, y} 2468*88d15eacSSasha Smundak }(), 2469*88d15eacSSasha Smundak wantEqual: true, 2470*88d15eacSSasha Smundak reason: "equal pair of single-node pointers", 2471*88d15eacSSasha Smundak }, { 2472*88d15eacSSasha Smundak label: "PointersInequal", 2473*88d15eacSSasha Smundak in: func() XY { 2474*88d15eacSSasha Smundak x := new(P) 2475*88d15eacSSasha Smundak *x = x 2476*88d15eacSSasha Smundak y1, y2 := new(P), new(P) 2477*88d15eacSSasha Smundak *y1 = y2 2478*88d15eacSSasha Smundak *y2 = y1 2479*88d15eacSSasha Smundak return XY{x, y1} 2480*88d15eacSSasha Smundak }(), 2481*88d15eacSSasha Smundak wantEqual: false, 2482*88d15eacSSasha Smundak reason: "inequal pair of single-node and double-node pointers", 2483*88d15eacSSasha Smundak }, { 2484*88d15eacSSasha Smundak label: "SlicesEqual", 2485*88d15eacSSasha Smundak in: func() XY { 2486*88d15eacSSasha Smundak x := S{nil} 2487*88d15eacSSasha Smundak x[0] = x 2488*88d15eacSSasha Smundak y := S{nil} 2489*88d15eacSSasha Smundak y[0] = y 2490*88d15eacSSasha Smundak return XY{x, y} 2491*88d15eacSSasha Smundak }(), 2492*88d15eacSSasha Smundak wantEqual: true, 2493*88d15eacSSasha Smundak reason: "equal pair of single-node slices", 2494*88d15eacSSasha Smundak }, { 2495*88d15eacSSasha Smundak label: "SlicesInequal", 2496*88d15eacSSasha Smundak in: func() XY { 2497*88d15eacSSasha Smundak x := S{nil} 2498*88d15eacSSasha Smundak x[0] = x 2499*88d15eacSSasha Smundak y1, y2 := S{nil}, S{nil} 2500*88d15eacSSasha Smundak y1[0] = y2 2501*88d15eacSSasha Smundak y2[0] = y1 2502*88d15eacSSasha Smundak return XY{x, y1} 2503*88d15eacSSasha Smundak }(), 2504*88d15eacSSasha Smundak wantEqual: false, 2505*88d15eacSSasha Smundak reason: "inequal pair of single-node and double node slices", 2506*88d15eacSSasha Smundak }, { 2507*88d15eacSSasha Smundak label: "MapsEqual", 2508*88d15eacSSasha Smundak in: func() XY { 2509*88d15eacSSasha Smundak x := M{0: nil} 2510*88d15eacSSasha Smundak x[0] = x 2511*88d15eacSSasha Smundak y := M{0: nil} 2512*88d15eacSSasha Smundak y[0] = y 2513*88d15eacSSasha Smundak return XY{x, y} 2514*88d15eacSSasha Smundak }(), 2515*88d15eacSSasha Smundak wantEqual: true, 2516*88d15eacSSasha Smundak reason: "equal pair of single-node maps", 2517*88d15eacSSasha Smundak }, { 2518*88d15eacSSasha Smundak label: "MapsInequal", 2519*88d15eacSSasha Smundak in: func() XY { 2520*88d15eacSSasha Smundak x := M{0: nil} 2521*88d15eacSSasha Smundak x[0] = x 2522*88d15eacSSasha Smundak y1, y2 := M{0: nil}, M{0: nil} 2523*88d15eacSSasha Smundak y1[0] = y2 2524*88d15eacSSasha Smundak y2[0] = y1 2525*88d15eacSSasha Smundak return XY{x, y1} 2526*88d15eacSSasha Smundak }(), 2527*88d15eacSSasha Smundak wantEqual: false, 2528*88d15eacSSasha Smundak reason: "inequal pair of single-node and double-node maps", 2529*88d15eacSSasha Smundak }, { 2530*88d15eacSSasha Smundak label: "GraphEqual", 2531*88d15eacSSasha Smundak in: XY{makeGraph(), makeGraph()}, 2532*88d15eacSSasha Smundak wantEqual: true, 2533*88d15eacSSasha Smundak reason: "graphs are equal since they have identical forms", 2534*88d15eacSSasha Smundak }, { 2535*88d15eacSSasha Smundak label: "GraphInequalZeroed", 2536*88d15eacSSasha Smundak in: func() XY { 2537*88d15eacSSasha Smundak x := makeGraph() 2538*88d15eacSSasha Smundak y := makeGraph() 2539*88d15eacSSasha Smundak y["Foo"].Bravos["FooBravo"].ID = 0 2540*88d15eacSSasha Smundak y["Bar"].Bravos["BarBuzzBravo"].ID = 0 2541*88d15eacSSasha Smundak y["Bar"].Bravos["BuzzBarBravo"].ID = 0 2542*88d15eacSSasha Smundak return XY{x, y} 2543*88d15eacSSasha Smundak }(), 2544*88d15eacSSasha Smundak wantEqual: false, 2545*88d15eacSSasha Smundak reason: "graphs are inequal because the ID fields are different", 2546*88d15eacSSasha Smundak }, { 2547*88d15eacSSasha Smundak label: "GraphInequalStruct", 2548*88d15eacSSasha Smundak in: func() XY { 2549*88d15eacSSasha Smundak x := makeGraph() 2550*88d15eacSSasha Smundak y := makeGraph() 2551*88d15eacSSasha Smundak x["Buzz"].Bravos["BuzzBarBravo"] = &CycleBravo{ 2552*88d15eacSSasha Smundak Name: "BuzzBarBravo", 2553*88d15eacSSasha Smundak ID: 103, 2554*88d15eacSSasha Smundak } 2555*88d15eacSSasha Smundak return XY{x, y} 2556*88d15eacSSasha Smundak }(), 2557*88d15eacSSasha Smundak wantEqual: false, 2558*88d15eacSSasha Smundak reason: "graphs are inequal because they differ on a map element", 2559*88d15eacSSasha Smundak }} { 2560*88d15eacSSasha Smundak tests = append(tests, test{ 2561*88d15eacSSasha Smundak label: label + "/" + tt.label, 2562*88d15eacSSasha Smundak x: tt.in.x, 2563*88d15eacSSasha Smundak y: tt.in.y, 2564*88d15eacSSasha Smundak wantEqual: tt.wantEqual, 2565*88d15eacSSasha Smundak reason: tt.reason, 2566*88d15eacSSasha Smundak }) 2567*88d15eacSSasha Smundak } 2568*88d15eacSSasha Smundak return tests 2569*88d15eacSSasha Smundak} 2570*88d15eacSSasha Smundak 2571*88d15eacSSasha Smundakfunc project1Tests() []test { 2572*88d15eacSSasha Smundak const label = "Project1" 2573*88d15eacSSasha Smundak 2574*88d15eacSSasha Smundak ignoreUnexported := cmpopts.IgnoreUnexported( 2575*88d15eacSSasha Smundak ts.EagleImmutable{}, 2576*88d15eacSSasha Smundak ts.DreamerImmutable{}, 2577*88d15eacSSasha Smundak ts.SlapImmutable{}, 2578*88d15eacSSasha Smundak ts.GoatImmutable{}, 2579*88d15eacSSasha Smundak ts.DonkeyImmutable{}, 2580*88d15eacSSasha Smundak ts.LoveRadius{}, 2581*88d15eacSSasha Smundak ts.SummerLove{}, 2582*88d15eacSSasha Smundak ts.SummerLoveSummary{}, 2583*88d15eacSSasha Smundak ) 2584*88d15eacSSasha Smundak 2585*88d15eacSSasha Smundak createEagle := func() ts.Eagle { 2586*88d15eacSSasha Smundak return ts.Eagle{ 2587*88d15eacSSasha Smundak Name: "eagle", 2588*88d15eacSSasha Smundak Hounds: []string{"buford", "tannen"}, 2589*88d15eacSSasha Smundak Desc: "some description", 2590*88d15eacSSasha Smundak Dreamers: []ts.Dreamer{{}, { 2591*88d15eacSSasha Smundak Name: "dreamer2", 2592*88d15eacSSasha Smundak Animal: []interface{}{ 2593*88d15eacSSasha Smundak ts.Goat{ 2594*88d15eacSSasha Smundak Target: "corporation", 2595*88d15eacSSasha Smundak Immutable: &ts.GoatImmutable{ 2596*88d15eacSSasha Smundak ID: "southbay", 2597*88d15eacSSasha Smundak State: (*pb.Goat_States)(newInt(5)), 2598*88d15eacSSasha Smundak Started: now, 2599*88d15eacSSasha Smundak }, 2600*88d15eacSSasha Smundak }, 2601*88d15eacSSasha Smundak ts.Donkey{}, 2602*88d15eacSSasha Smundak }, 2603*88d15eacSSasha Smundak Amoeba: 53, 2604*88d15eacSSasha Smundak }}, 2605*88d15eacSSasha Smundak Slaps: []ts.Slap{{ 2606*88d15eacSSasha Smundak Name: "slapID", 2607*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2608*88d15eacSSasha Smundak Immutable: &ts.SlapImmutable{ 2609*88d15eacSSasha Smundak ID: "immutableSlap", 2610*88d15eacSSasha Smundak MildSlap: true, 2611*88d15eacSSasha Smundak Started: now, 2612*88d15eacSSasha Smundak LoveRadius: &ts.LoveRadius{ 2613*88d15eacSSasha Smundak Summer: &ts.SummerLove{ 2614*88d15eacSSasha Smundak Summary: &ts.SummerLoveSummary{ 2615*88d15eacSSasha Smundak Devices: []string{"foo", "bar", "baz"}, 2616*88d15eacSSasha Smundak ChangeType: []pb.SummerType{1, 2, 3}, 2617*88d15eacSSasha Smundak }, 2618*88d15eacSSasha Smundak }, 2619*88d15eacSSasha Smundak }, 2620*88d15eacSSasha Smundak }, 2621*88d15eacSSasha Smundak }}, 2622*88d15eacSSasha Smundak Immutable: &ts.EagleImmutable{ 2623*88d15eacSSasha Smundak ID: "eagleID", 2624*88d15eacSSasha Smundak Birthday: now, 2625*88d15eacSSasha Smundak MissingCall: (*pb.Eagle_MissingCalls)(newInt(55)), 2626*88d15eacSSasha Smundak }, 2627*88d15eacSSasha Smundak } 2628*88d15eacSSasha Smundak } 2629*88d15eacSSasha Smundak 2630*88d15eacSSasha Smundak return []test{{ 2631*88d15eacSSasha Smundak label: label + "/PanicUnexported", 2632*88d15eacSSasha Smundak x: ts.Eagle{Slaps: []ts.Slap{{ 2633*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2634*88d15eacSSasha Smundak }}}, 2635*88d15eacSSasha Smundak y: ts.Eagle{Slaps: []ts.Slap{{ 2636*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2637*88d15eacSSasha Smundak }}}, 2638*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2639*88d15eacSSasha Smundak reason: "struct contains unexported fields", 2640*88d15eacSSasha Smundak }, { 2641*88d15eacSSasha Smundak label: label + "/ProtoEqual", 2642*88d15eacSSasha Smundak x: ts.Eagle{Slaps: []ts.Slap{{ 2643*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2644*88d15eacSSasha Smundak }}}, 2645*88d15eacSSasha Smundak y: ts.Eagle{Slaps: []ts.Slap{{ 2646*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2647*88d15eacSSasha Smundak }}}, 2648*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal)}, 2649*88d15eacSSasha Smundak wantEqual: true, 2650*88d15eacSSasha Smundak reason: "simulated protobuf messages contain the same values", 2651*88d15eacSSasha Smundak }, { 2652*88d15eacSSasha Smundak label: label + "/ProtoInequal", 2653*88d15eacSSasha Smundak x: ts.Eagle{Slaps: []ts.Slap{{}, {}, {}, {}, { 2654*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}, 2655*88d15eacSSasha Smundak }}}, 2656*88d15eacSSasha Smundak y: ts.Eagle{Slaps: []ts.Slap{{}, {}, {}, {}, { 2657*88d15eacSSasha Smundak Args: &pb.MetaData{Stringer: pb.Stringer{X: "metadata2"}}, 2658*88d15eacSSasha Smundak }}}, 2659*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal)}, 2660*88d15eacSSasha Smundak wantEqual: false, 2661*88d15eacSSasha Smundak reason: "simulated protobuf messages contain different values", 2662*88d15eacSSasha Smundak }, { 2663*88d15eacSSasha Smundak label: label + "/Equal", 2664*88d15eacSSasha Smundak x: createEagle(), 2665*88d15eacSSasha Smundak y: createEagle(), 2666*88d15eacSSasha Smundak opts: []cmp.Option{ignoreUnexported, cmp.Comparer(pb.Equal)}, 2667*88d15eacSSasha Smundak wantEqual: true, 2668*88d15eacSSasha Smundak reason: "equal because values are the same", 2669*88d15eacSSasha Smundak }, { 2670*88d15eacSSasha Smundak label: label + "/Inequal", 2671*88d15eacSSasha Smundak x: func() ts.Eagle { 2672*88d15eacSSasha Smundak eg := createEagle() 2673*88d15eacSSasha Smundak eg.Dreamers[1].Animal[0].(ts.Goat).Immutable.ID = "southbay2" 2674*88d15eacSSasha Smundak eg.Dreamers[1].Animal[0].(ts.Goat).Immutable.State = (*pb.Goat_States)(newInt(6)) 2675*88d15eacSSasha Smundak eg.Slaps[0].Immutable.MildSlap = false 2676*88d15eacSSasha Smundak return eg 2677*88d15eacSSasha Smundak }(), 2678*88d15eacSSasha Smundak y: func() ts.Eagle { 2679*88d15eacSSasha Smundak eg := createEagle() 2680*88d15eacSSasha Smundak devs := eg.Slaps[0].Immutable.LoveRadius.Summer.Summary.Devices 2681*88d15eacSSasha Smundak eg.Slaps[0].Immutable.LoveRadius.Summer.Summary.Devices = devs[:1] 2682*88d15eacSSasha Smundak return eg 2683*88d15eacSSasha Smundak }(), 2684*88d15eacSSasha Smundak opts: []cmp.Option{ignoreUnexported, cmp.Comparer(pb.Equal)}, 2685*88d15eacSSasha Smundak wantEqual: false, 2686*88d15eacSSasha Smundak reason: "inequal because some values are different", 2687*88d15eacSSasha Smundak }} 2688*88d15eacSSasha Smundak} 2689*88d15eacSSasha Smundak 2690*88d15eacSSasha Smundaktype germSorter []*pb.Germ 2691*88d15eacSSasha Smundak 2692*88d15eacSSasha Smundakfunc (gs germSorter) Len() int { return len(gs) } 2693*88d15eacSSasha Smundakfunc (gs germSorter) Less(i, j int) bool { return gs[i].String() < gs[j].String() } 2694*88d15eacSSasha Smundakfunc (gs germSorter) Swap(i, j int) { gs[i], gs[j] = gs[j], gs[i] } 2695*88d15eacSSasha Smundak 2696*88d15eacSSasha Smundakfunc project2Tests() []test { 2697*88d15eacSSasha Smundak const label = "Project2" 2698*88d15eacSSasha Smundak 2699*88d15eacSSasha Smundak sortGerms := cmp.Transformer("Sort", func(in []*pb.Germ) []*pb.Germ { 2700*88d15eacSSasha Smundak out := append([]*pb.Germ(nil), in...) // Make copy 2701*88d15eacSSasha Smundak sort.Sort(germSorter(out)) 2702*88d15eacSSasha Smundak return out 2703*88d15eacSSasha Smundak }) 2704*88d15eacSSasha Smundak 2705*88d15eacSSasha Smundak equalDish := cmp.Comparer(func(x, y *ts.Dish) bool { 2706*88d15eacSSasha Smundak if x == nil || y == nil { 2707*88d15eacSSasha Smundak return x == nil && y == nil 2708*88d15eacSSasha Smundak } 2709*88d15eacSSasha Smundak px, err1 := x.Proto() 2710*88d15eacSSasha Smundak py, err2 := y.Proto() 2711*88d15eacSSasha Smundak if err1 != nil || err2 != nil { 2712*88d15eacSSasha Smundak return err1 == err2 2713*88d15eacSSasha Smundak } 2714*88d15eacSSasha Smundak return pb.Equal(px, py) 2715*88d15eacSSasha Smundak }) 2716*88d15eacSSasha Smundak 2717*88d15eacSSasha Smundak createBatch := func() ts.GermBatch { 2718*88d15eacSSasha Smundak return ts.GermBatch{ 2719*88d15eacSSasha Smundak DirtyGerms: map[int32][]*pb.Germ{ 2720*88d15eacSSasha Smundak 17: { 2721*88d15eacSSasha Smundak {Stringer: pb.Stringer{X: "germ1"}}, 2722*88d15eacSSasha Smundak }, 2723*88d15eacSSasha Smundak 18: { 2724*88d15eacSSasha Smundak {Stringer: pb.Stringer{X: "germ2"}}, 2725*88d15eacSSasha Smundak {Stringer: pb.Stringer{X: "germ3"}}, 2726*88d15eacSSasha Smundak {Stringer: pb.Stringer{X: "germ4"}}, 2727*88d15eacSSasha Smundak }, 2728*88d15eacSSasha Smundak }, 2729*88d15eacSSasha Smundak GermMap: map[int32]*pb.Germ{ 2730*88d15eacSSasha Smundak 13: {Stringer: pb.Stringer{X: "germ13"}}, 2731*88d15eacSSasha Smundak 21: {Stringer: pb.Stringer{X: "germ21"}}, 2732*88d15eacSSasha Smundak }, 2733*88d15eacSSasha Smundak DishMap: map[int32]*ts.Dish{ 2734*88d15eacSSasha Smundak 0: ts.CreateDish(nil, io.EOF), 2735*88d15eacSSasha Smundak 1: ts.CreateDish(nil, io.ErrUnexpectedEOF), 2736*88d15eacSSasha Smundak 2: ts.CreateDish(&pb.Dish{Stringer: pb.Stringer{X: "dish"}}, nil), 2737*88d15eacSSasha Smundak }, 2738*88d15eacSSasha Smundak HasPreviousResult: true, 2739*88d15eacSSasha Smundak DirtyID: 10, 2740*88d15eacSSasha Smundak GermStrain: 421, 2741*88d15eacSSasha Smundak InfectedAt: now, 2742*88d15eacSSasha Smundak } 2743*88d15eacSSasha Smundak } 2744*88d15eacSSasha Smundak 2745*88d15eacSSasha Smundak return []test{{ 2746*88d15eacSSasha Smundak label: label + "/PanicUnexported", 2747*88d15eacSSasha Smundak x: createBatch(), 2748*88d15eacSSasha Smundak y: createBatch(), 2749*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2750*88d15eacSSasha Smundak reason: "struct contains unexported fields", 2751*88d15eacSSasha Smundak }, { 2752*88d15eacSSasha Smundak label: label + "/Equal", 2753*88d15eacSSasha Smundak x: createBatch(), 2754*88d15eacSSasha Smundak y: createBatch(), 2755*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, 2756*88d15eacSSasha Smundak wantEqual: true, 2757*88d15eacSSasha Smundak reason: "equal because identical values are compared", 2758*88d15eacSSasha Smundak }, { 2759*88d15eacSSasha Smundak label: label + "/InequalOrder", 2760*88d15eacSSasha Smundak x: createBatch(), 2761*88d15eacSSasha Smundak y: func() ts.GermBatch { 2762*88d15eacSSasha Smundak gb := createBatch() 2763*88d15eacSSasha Smundak s := gb.DirtyGerms[18] 2764*88d15eacSSasha Smundak s[0], s[1], s[2] = s[1], s[2], s[0] 2765*88d15eacSSasha Smundak return gb 2766*88d15eacSSasha Smundak }(), 2767*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal), equalDish}, 2768*88d15eacSSasha Smundak wantEqual: false, 2769*88d15eacSSasha Smundak reason: "inequal because slice contains elements in differing order", 2770*88d15eacSSasha Smundak }, { 2771*88d15eacSSasha Smundak label: label + "/EqualOrder", 2772*88d15eacSSasha Smundak x: createBatch(), 2773*88d15eacSSasha Smundak y: func() ts.GermBatch { 2774*88d15eacSSasha Smundak gb := createBatch() 2775*88d15eacSSasha Smundak s := gb.DirtyGerms[18] 2776*88d15eacSSasha Smundak s[0], s[1], s[2] = s[1], s[2], s[0] 2777*88d15eacSSasha Smundak return gb 2778*88d15eacSSasha Smundak }(), 2779*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, 2780*88d15eacSSasha Smundak wantEqual: true, 2781*88d15eacSSasha Smundak reason: "equal because unordered slice is sorted using transformer", 2782*88d15eacSSasha Smundak }, { 2783*88d15eacSSasha Smundak label: label + "/Inequal", 2784*88d15eacSSasha Smundak x: func() ts.GermBatch { 2785*88d15eacSSasha Smundak gb := createBatch() 2786*88d15eacSSasha Smundak delete(gb.DirtyGerms, 17) 2787*88d15eacSSasha Smundak gb.DishMap[1] = nil 2788*88d15eacSSasha Smundak return gb 2789*88d15eacSSasha Smundak }(), 2790*88d15eacSSasha Smundak y: func() ts.GermBatch { 2791*88d15eacSSasha Smundak gb := createBatch() 2792*88d15eacSSasha Smundak gb.DirtyGerms[18] = gb.DirtyGerms[18][:2] 2793*88d15eacSSasha Smundak gb.GermStrain = 22 2794*88d15eacSSasha Smundak return gb 2795*88d15eacSSasha Smundak }(), 2796*88d15eacSSasha Smundak opts: []cmp.Option{cmp.Comparer(pb.Equal), sortGerms, equalDish}, 2797*88d15eacSSasha Smundak wantEqual: false, 2798*88d15eacSSasha Smundak reason: "inequal because some values are different", 2799*88d15eacSSasha Smundak }} 2800*88d15eacSSasha Smundak} 2801*88d15eacSSasha Smundak 2802*88d15eacSSasha Smundakfunc project3Tests() []test { 2803*88d15eacSSasha Smundak const label = "Project3" 2804*88d15eacSSasha Smundak 2805*88d15eacSSasha Smundak allowVisibility := cmp.AllowUnexported(ts.Dirt{}) 2806*88d15eacSSasha Smundak 2807*88d15eacSSasha Smundak ignoreLocker := cmpopts.IgnoreInterfaces(struct{ sync.Locker }{}) 2808*88d15eacSSasha Smundak 2809*88d15eacSSasha Smundak transformProtos := cmp.Transformer("λ", func(x pb.Dirt) *pb.Dirt { 2810*88d15eacSSasha Smundak return &x 2811*88d15eacSSasha Smundak }) 2812*88d15eacSSasha Smundak 2813*88d15eacSSasha Smundak equalTable := cmp.Comparer(func(x, y ts.Table) bool { 2814*88d15eacSSasha Smundak tx, ok1 := x.(*ts.MockTable) 2815*88d15eacSSasha Smundak ty, ok2 := y.(*ts.MockTable) 2816*88d15eacSSasha Smundak if !ok1 || !ok2 { 2817*88d15eacSSasha Smundak panic("table type must be MockTable") 2818*88d15eacSSasha Smundak } 2819*88d15eacSSasha Smundak return cmp.Equal(tx.State(), ty.State()) 2820*88d15eacSSasha Smundak }) 2821*88d15eacSSasha Smundak 2822*88d15eacSSasha Smundak createDirt := func() (d ts.Dirt) { 2823*88d15eacSSasha Smundak d.SetTable(ts.CreateMockTable([]string{"a", "b", "c"})) 2824*88d15eacSSasha Smundak d.SetTimestamp(12345) 2825*88d15eacSSasha Smundak d.Discord = 554 2826*88d15eacSSasha Smundak d.Proto = pb.Dirt{Stringer: pb.Stringer{X: "proto"}} 2827*88d15eacSSasha Smundak d.SetWizard(map[string]*pb.Wizard{ 2828*88d15eacSSasha Smundak "harry": {Stringer: pb.Stringer{X: "potter"}}, 2829*88d15eacSSasha Smundak "albus": {Stringer: pb.Stringer{X: "dumbledore"}}, 2830*88d15eacSSasha Smundak }) 2831*88d15eacSSasha Smundak d.SetLastTime(54321) 2832*88d15eacSSasha Smundak return d 2833*88d15eacSSasha Smundak } 2834*88d15eacSSasha Smundak 2835*88d15eacSSasha Smundak return []test{{ 2836*88d15eacSSasha Smundak label: label + "/PanicUnexported1", 2837*88d15eacSSasha Smundak x: createDirt(), 2838*88d15eacSSasha Smundak y: createDirt(), 2839*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2840*88d15eacSSasha Smundak reason: "struct contains unexported fields", 2841*88d15eacSSasha Smundak }, { 2842*88d15eacSSasha Smundak label: label + "/PanicUnexported2", 2843*88d15eacSSasha Smundak x: createDirt(), 2844*88d15eacSSasha Smundak y: createDirt(), 2845*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, 2846*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2847*88d15eacSSasha Smundak reason: "struct contains references to simulated protobuf types with unexported fields", 2848*88d15eacSSasha Smundak }, { 2849*88d15eacSSasha Smundak label: label + "/Equal", 2850*88d15eacSSasha Smundak x: createDirt(), 2851*88d15eacSSasha Smundak y: createDirt(), 2852*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, transformProtos, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, 2853*88d15eacSSasha Smundak wantEqual: true, 2854*88d15eacSSasha Smundak reason: "transformer used to create reference to protobuf message so it works with pb.Equal", 2855*88d15eacSSasha Smundak }, { 2856*88d15eacSSasha Smundak label: label + "/Inequal", 2857*88d15eacSSasha Smundak x: func() ts.Dirt { 2858*88d15eacSSasha Smundak d := createDirt() 2859*88d15eacSSasha Smundak d.SetTable(ts.CreateMockTable([]string{"a", "c"})) 2860*88d15eacSSasha Smundak d.Proto = pb.Dirt{Stringer: pb.Stringer{X: "blah"}} 2861*88d15eacSSasha Smundak return d 2862*88d15eacSSasha Smundak }(), 2863*88d15eacSSasha Smundak y: func() ts.Dirt { 2864*88d15eacSSasha Smundak d := createDirt() 2865*88d15eacSSasha Smundak d.Discord = 500 2866*88d15eacSSasha Smundak d.SetWizard(map[string]*pb.Wizard{ 2867*88d15eacSSasha Smundak "harry": {Stringer: pb.Stringer{X: "otter"}}, 2868*88d15eacSSasha Smundak }) 2869*88d15eacSSasha Smundak return d 2870*88d15eacSSasha Smundak }(), 2871*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, transformProtos, ignoreLocker, cmp.Comparer(pb.Equal), equalTable}, 2872*88d15eacSSasha Smundak wantEqual: false, 2873*88d15eacSSasha Smundak reason: "inequal because some values are different", 2874*88d15eacSSasha Smundak }} 2875*88d15eacSSasha Smundak} 2876*88d15eacSSasha Smundak 2877*88d15eacSSasha Smundakfunc project4Tests() []test { 2878*88d15eacSSasha Smundak const label = "Project4" 2879*88d15eacSSasha Smundak 2880*88d15eacSSasha Smundak allowVisibility := cmp.AllowUnexported( 2881*88d15eacSSasha Smundak ts.Cartel{}, 2882*88d15eacSSasha Smundak ts.Headquarter{}, 2883*88d15eacSSasha Smundak ts.Poison{}, 2884*88d15eacSSasha Smundak ) 2885*88d15eacSSasha Smundak 2886*88d15eacSSasha Smundak transformProtos := cmp.Transformer("λ", func(x pb.Restrictions) *pb.Restrictions { 2887*88d15eacSSasha Smundak return &x 2888*88d15eacSSasha Smundak }) 2889*88d15eacSSasha Smundak 2890*88d15eacSSasha Smundak createCartel := func() ts.Cartel { 2891*88d15eacSSasha Smundak var p ts.Poison 2892*88d15eacSSasha Smundak p.SetPoisonType(5) 2893*88d15eacSSasha Smundak p.SetExpiration(now) 2894*88d15eacSSasha Smundak p.SetManufacturer("acme") 2895*88d15eacSSasha Smundak 2896*88d15eacSSasha Smundak var hq ts.Headquarter 2897*88d15eacSSasha Smundak hq.SetID(5) 2898*88d15eacSSasha Smundak hq.SetLocation("moon") 2899*88d15eacSSasha Smundak hq.SetSubDivisions([]string{"alpha", "bravo", "charlie"}) 2900*88d15eacSSasha Smundak hq.SetMetaData(&pb.MetaData{Stringer: pb.Stringer{X: "metadata"}}) 2901*88d15eacSSasha Smundak hq.SetPublicMessage([]byte{1, 2, 3, 4, 5}) 2902*88d15eacSSasha Smundak hq.SetHorseBack("abcdef") 2903*88d15eacSSasha Smundak hq.SetStatus(44) 2904*88d15eacSSasha Smundak 2905*88d15eacSSasha Smundak var c ts.Cartel 2906*88d15eacSSasha Smundak c.Headquarter = hq 2907*88d15eacSSasha Smundak c.SetSource("mars") 2908*88d15eacSSasha Smundak c.SetCreationTime(now) 2909*88d15eacSSasha Smundak c.SetBoss("al capone") 2910*88d15eacSSasha Smundak c.SetPoisons([]*ts.Poison{&p}) 2911*88d15eacSSasha Smundak 2912*88d15eacSSasha Smundak return c 2913*88d15eacSSasha Smundak } 2914*88d15eacSSasha Smundak 2915*88d15eacSSasha Smundak return []test{{ 2916*88d15eacSSasha Smundak label: label + "/PanicUnexported1", 2917*88d15eacSSasha Smundak x: createCartel(), 2918*88d15eacSSasha Smundak y: createCartel(), 2919*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2920*88d15eacSSasha Smundak reason: "struct contains unexported fields", 2921*88d15eacSSasha Smundak }, { 2922*88d15eacSSasha Smundak label: label + "/PanicUnexported2", 2923*88d15eacSSasha Smundak x: createCartel(), 2924*88d15eacSSasha Smundak y: createCartel(), 2925*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, cmp.Comparer(pb.Equal)}, 2926*88d15eacSSasha Smundak wantPanic: "cannot handle unexported field", 2927*88d15eacSSasha Smundak reason: "struct contains references to simulated protobuf types with unexported fields", 2928*88d15eacSSasha Smundak }, { 2929*88d15eacSSasha Smundak label: label + "/Equal", 2930*88d15eacSSasha Smundak x: createCartel(), 2931*88d15eacSSasha Smundak y: createCartel(), 2932*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, transformProtos, cmp.Comparer(pb.Equal)}, 2933*88d15eacSSasha Smundak wantEqual: true, 2934*88d15eacSSasha Smundak reason: "transformer used to create reference to protobuf message so it works with pb.Equal", 2935*88d15eacSSasha Smundak }, { 2936*88d15eacSSasha Smundak label: label + "/Inequal", 2937*88d15eacSSasha Smundak x: func() ts.Cartel { 2938*88d15eacSSasha Smundak d := createCartel() 2939*88d15eacSSasha Smundak var p1, p2 ts.Poison 2940*88d15eacSSasha Smundak p1.SetPoisonType(1) 2941*88d15eacSSasha Smundak p1.SetExpiration(now) 2942*88d15eacSSasha Smundak p1.SetManufacturer("acme") 2943*88d15eacSSasha Smundak p2.SetPoisonType(2) 2944*88d15eacSSasha Smundak p2.SetManufacturer("acme2") 2945*88d15eacSSasha Smundak d.SetPoisons([]*ts.Poison{&p1, &p2}) 2946*88d15eacSSasha Smundak return d 2947*88d15eacSSasha Smundak }(), 2948*88d15eacSSasha Smundak y: func() ts.Cartel { 2949*88d15eacSSasha Smundak d := createCartel() 2950*88d15eacSSasha Smundak d.SetSubDivisions([]string{"bravo", "charlie"}) 2951*88d15eacSSasha Smundak d.SetPublicMessage([]byte{1, 2, 4, 3, 5}) 2952*88d15eacSSasha Smundak return d 2953*88d15eacSSasha Smundak }(), 2954*88d15eacSSasha Smundak opts: []cmp.Option{allowVisibility, transformProtos, cmp.Comparer(pb.Equal)}, 2955*88d15eacSSasha Smundak wantEqual: false, 2956*88d15eacSSasha Smundak reason: "inequal because some values are different", 2957*88d15eacSSasha Smundak }} 2958*88d15eacSSasha Smundak} 2959*88d15eacSSasha Smundak 2960*88d15eacSSasha Smundak// BenchmarkBytes benchmarks the performance of performing Equal or Diff on 2961*88d15eacSSasha Smundak// large slices of bytes. 2962*88d15eacSSasha Smundakfunc BenchmarkBytes(b *testing.B) { 2963*88d15eacSSasha Smundak // Create a list of PathFilters that never apply, but are evaluated. 2964*88d15eacSSasha Smundak const maxFilters = 5 2965*88d15eacSSasha Smundak var filters cmp.Options 2966*88d15eacSSasha Smundak errorIface := reflect.TypeOf((*error)(nil)).Elem() 2967*88d15eacSSasha Smundak for i := 0; i <= maxFilters; i++ { 2968*88d15eacSSasha Smundak filters = append(filters, cmp.FilterPath(func(p cmp.Path) bool { 2969*88d15eacSSasha Smundak return p.Last().Type().AssignableTo(errorIface) // Never true 2970*88d15eacSSasha Smundak }, cmp.Ignore())) 2971*88d15eacSSasha Smundak } 2972*88d15eacSSasha Smundak 2973*88d15eacSSasha Smundak type benchSize struct { 2974*88d15eacSSasha Smundak label string 2975*88d15eacSSasha Smundak size int64 2976*88d15eacSSasha Smundak } 2977*88d15eacSSasha Smundak for _, ts := range []benchSize{ 2978*88d15eacSSasha Smundak {"4KiB", 1 << 12}, 2979*88d15eacSSasha Smundak {"64KiB", 1 << 16}, 2980*88d15eacSSasha Smundak {"1MiB", 1 << 20}, 2981*88d15eacSSasha Smundak {"16MiB", 1 << 24}, 2982*88d15eacSSasha Smundak } { 2983*88d15eacSSasha Smundak bx := append(append(make([]byte, ts.size/2), 'x'), make([]byte, ts.size/2)...) 2984*88d15eacSSasha Smundak by := append(append(make([]byte, ts.size/2), 'y'), make([]byte, ts.size/2)...) 2985*88d15eacSSasha Smundak b.Run(ts.label, func(b *testing.B) { 2986*88d15eacSSasha Smundak // Iteratively add more filters that never apply, but are evaluated 2987*88d15eacSSasha Smundak // to measure the cost of simply evaluating each filter. 2988*88d15eacSSasha Smundak for i := 0; i <= maxFilters; i++ { 2989*88d15eacSSasha Smundak b.Run(fmt.Sprintf("EqualFilter%d", i), func(b *testing.B) { 2990*88d15eacSSasha Smundak b.ReportAllocs() 2991*88d15eacSSasha Smundak b.SetBytes(2 * ts.size) 2992*88d15eacSSasha Smundak for j := 0; j < b.N; j++ { 2993*88d15eacSSasha Smundak cmp.Equal(bx, by, filters[:i]...) 2994*88d15eacSSasha Smundak } 2995*88d15eacSSasha Smundak }) 2996*88d15eacSSasha Smundak } 2997*88d15eacSSasha Smundak for i := 0; i <= maxFilters; i++ { 2998*88d15eacSSasha Smundak b.Run(fmt.Sprintf("DiffFilter%d", i), func(b *testing.B) { 2999*88d15eacSSasha Smundak b.ReportAllocs() 3000*88d15eacSSasha Smundak b.SetBytes(2 * ts.size) 3001*88d15eacSSasha Smundak for j := 0; j < b.N; j++ { 3002*88d15eacSSasha Smundak cmp.Diff(bx, by, filters[:i]...) 3003*88d15eacSSasha Smundak } 3004*88d15eacSSasha Smundak }) 3005*88d15eacSSasha Smundak } 3006*88d15eacSSasha Smundak }) 3007*88d15eacSSasha Smundak } 3008*88d15eacSSasha Smundak} 3009