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 cmpopts 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport ( 8*88d15eacSSasha Smundak "bytes" 9*88d15eacSSasha Smundak "errors" 10*88d15eacSSasha Smundak "fmt" 11*88d15eacSSasha Smundak "io" 12*88d15eacSSasha Smundak "math" 13*88d15eacSSasha Smundak "reflect" 14*88d15eacSSasha Smundak "strings" 15*88d15eacSSasha Smundak "sync" 16*88d15eacSSasha Smundak "testing" 17*88d15eacSSasha Smundak "time" 18*88d15eacSSasha Smundak 19*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp" 20*88d15eacSSasha Smundak) 21*88d15eacSSasha Smundak 22*88d15eacSSasha Smundaktype ( 23*88d15eacSSasha Smundak MyInt int 24*88d15eacSSasha Smundak MyInts []int 25*88d15eacSSasha Smundak MyFloat float32 26*88d15eacSSasha Smundak MyString string 27*88d15eacSSasha Smundak MyTime struct{ time.Time } 28*88d15eacSSasha Smundak MyStruct struct { 29*88d15eacSSasha Smundak A, B []int 30*88d15eacSSasha Smundak C, D map[time.Time]string 31*88d15eacSSasha Smundak } 32*88d15eacSSasha Smundak 33*88d15eacSSasha Smundak Foo1 struct{ Alpha, Bravo, Charlie int } 34*88d15eacSSasha Smundak Foo2 struct{ *Foo1 } 35*88d15eacSSasha Smundak Foo3 struct{ *Foo2 } 36*88d15eacSSasha Smundak Bar1 struct{ Foo3 } 37*88d15eacSSasha Smundak Bar2 struct { 38*88d15eacSSasha Smundak Bar1 39*88d15eacSSasha Smundak *Foo3 40*88d15eacSSasha Smundak Bravo float32 41*88d15eacSSasha Smundak } 42*88d15eacSSasha Smundak Bar3 struct { 43*88d15eacSSasha Smundak Bar1 44*88d15eacSSasha Smundak Bravo *Bar2 45*88d15eacSSasha Smundak Delta struct{ Echo Foo1 } 46*88d15eacSSasha Smundak *Foo3 47*88d15eacSSasha Smundak Alpha string 48*88d15eacSSasha Smundak } 49*88d15eacSSasha Smundak 50*88d15eacSSasha Smundak privateStruct struct{ Public, private int } 51*88d15eacSSasha Smundak PublicStruct struct{ Public, private int } 52*88d15eacSSasha Smundak ParentStruct struct { 53*88d15eacSSasha Smundak *privateStruct 54*88d15eacSSasha Smundak *PublicStruct 55*88d15eacSSasha Smundak Public int 56*88d15eacSSasha Smundak private int 57*88d15eacSSasha Smundak } 58*88d15eacSSasha Smundak 59*88d15eacSSasha Smundak Everything struct { 60*88d15eacSSasha Smundak MyInt 61*88d15eacSSasha Smundak MyFloat 62*88d15eacSSasha Smundak MyTime 63*88d15eacSSasha Smundak MyStruct 64*88d15eacSSasha Smundak Bar3 65*88d15eacSSasha Smundak ParentStruct 66*88d15eacSSasha Smundak } 67*88d15eacSSasha Smundak 68*88d15eacSSasha Smundak EmptyInterface interface{} 69*88d15eacSSasha Smundak) 70*88d15eacSSasha Smundak 71*88d15eacSSasha Smundakfunc TestOptions(t *testing.T) { 72*88d15eacSSasha Smundak createBar3X := func() *Bar3 { 73*88d15eacSSasha Smundak return &Bar3{ 74*88d15eacSSasha Smundak Bar1: Bar1{Foo3{&Foo2{&Foo1{Bravo: 2}}}}, 75*88d15eacSSasha Smundak Bravo: &Bar2{ 76*88d15eacSSasha Smundak Bar1: Bar1{Foo3{&Foo2{&Foo1{Charlie: 7}}}}, 77*88d15eacSSasha Smundak Foo3: &Foo3{&Foo2{&Foo1{Bravo: 5}}}, 78*88d15eacSSasha Smundak Bravo: 4, 79*88d15eacSSasha Smundak }, 80*88d15eacSSasha Smundak Delta: struct{ Echo Foo1 }{Foo1{Charlie: 3}}, 81*88d15eacSSasha Smundak Foo3: &Foo3{&Foo2{&Foo1{Alpha: 1}}}, 82*88d15eacSSasha Smundak Alpha: "alpha", 83*88d15eacSSasha Smundak } 84*88d15eacSSasha Smundak } 85*88d15eacSSasha Smundak createBar3Y := func() *Bar3 { 86*88d15eacSSasha Smundak return &Bar3{ 87*88d15eacSSasha Smundak Bar1: Bar1{Foo3{&Foo2{&Foo1{Bravo: 3}}}}, 88*88d15eacSSasha Smundak Bravo: &Bar2{ 89*88d15eacSSasha Smundak Bar1: Bar1{Foo3{&Foo2{&Foo1{Charlie: 8}}}}, 90*88d15eacSSasha Smundak Foo3: &Foo3{&Foo2{&Foo1{Bravo: 6}}}, 91*88d15eacSSasha Smundak Bravo: 5, 92*88d15eacSSasha Smundak }, 93*88d15eacSSasha Smundak Delta: struct{ Echo Foo1 }{Foo1{Charlie: 4}}, 94*88d15eacSSasha Smundak Foo3: &Foo3{&Foo2{&Foo1{Alpha: 2}}}, 95*88d15eacSSasha Smundak Alpha: "ALPHA", 96*88d15eacSSasha Smundak } 97*88d15eacSSasha Smundak } 98*88d15eacSSasha Smundak 99*88d15eacSSasha Smundak tests := []struct { 100*88d15eacSSasha Smundak label string // Test name 101*88d15eacSSasha Smundak x, y interface{} // Input values to compare 102*88d15eacSSasha Smundak opts []cmp.Option // Input options 103*88d15eacSSasha Smundak wantEqual bool // Whether the inputs are equal 104*88d15eacSSasha Smundak wantPanic bool // Whether Equal should panic 105*88d15eacSSasha Smundak reason string // The reason for the expected outcome 106*88d15eacSSasha Smundak }{{ 107*88d15eacSSasha Smundak label: "EquateEmpty", 108*88d15eacSSasha Smundak x: []int{}, 109*88d15eacSSasha Smundak y: []int(nil), 110*88d15eacSSasha Smundak wantEqual: false, 111*88d15eacSSasha Smundak reason: "not equal because empty non-nil and nil slice differ", 112*88d15eacSSasha Smundak }, { 113*88d15eacSSasha Smundak label: "EquateEmpty", 114*88d15eacSSasha Smundak x: []int{}, 115*88d15eacSSasha Smundak y: []int(nil), 116*88d15eacSSasha Smundak opts: []cmp.Option{EquateEmpty()}, 117*88d15eacSSasha Smundak wantEqual: true, 118*88d15eacSSasha Smundak reason: "equal because EquateEmpty equates empty slices", 119*88d15eacSSasha Smundak }, { 120*88d15eacSSasha Smundak label: "SortSlices", 121*88d15eacSSasha Smundak x: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 122*88d15eacSSasha Smundak y: []int{1, 0, 5, 2, 8, 9, 4, 3, 6, 7}, 123*88d15eacSSasha Smundak wantEqual: false, 124*88d15eacSSasha Smundak reason: "not equal because element order differs", 125*88d15eacSSasha Smundak }, { 126*88d15eacSSasha Smundak label: "SortSlices", 127*88d15eacSSasha Smundak x: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 128*88d15eacSSasha Smundak y: []int{1, 0, 5, 2, 8, 9, 4, 3, 6, 7}, 129*88d15eacSSasha Smundak opts: []cmp.Option{SortSlices(func(x, y int) bool { return x < y })}, 130*88d15eacSSasha Smundak wantEqual: true, 131*88d15eacSSasha Smundak reason: "equal because SortSlices sorts the slices", 132*88d15eacSSasha Smundak }, { 133*88d15eacSSasha Smundak label: "SortSlices", 134*88d15eacSSasha Smundak x: []MyInt{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 135*88d15eacSSasha Smundak y: []MyInt{1, 0, 5, 2, 8, 9, 4, 3, 6, 7}, 136*88d15eacSSasha Smundak opts: []cmp.Option{SortSlices(func(x, y int) bool { return x < y })}, 137*88d15eacSSasha Smundak wantEqual: false, 138*88d15eacSSasha Smundak reason: "not equal because MyInt is not the same type as int", 139*88d15eacSSasha Smundak }, { 140*88d15eacSSasha Smundak label: "SortSlices", 141*88d15eacSSasha Smundak x: []float64{0, 1, 1, 2, 2, 2}, 142*88d15eacSSasha Smundak y: []float64{2, 0, 2, 1, 2, 1}, 143*88d15eacSSasha Smundak opts: []cmp.Option{SortSlices(func(x, y float64) bool { return x < y })}, 144*88d15eacSSasha Smundak wantEqual: true, 145*88d15eacSSasha Smundak reason: "equal even when sorted with duplicate elements", 146*88d15eacSSasha Smundak }, { 147*88d15eacSSasha Smundak label: "SortSlices", 148*88d15eacSSasha Smundak x: []float64{0, 1, 1, 2, 2, 2, math.NaN(), 3, 3, 3, 3, 4, 4, 4, 4}, 149*88d15eacSSasha Smundak y: []float64{2, 0, 4, 4, 3, math.NaN(), 4, 1, 3, 2, 3, 3, 4, 1, 2}, 150*88d15eacSSasha Smundak opts: []cmp.Option{SortSlices(func(x, y float64) bool { return x < y })}, 151*88d15eacSSasha Smundak wantPanic: true, 152*88d15eacSSasha Smundak reason: "panics because SortSlices used with non-transitive less function", 153*88d15eacSSasha Smundak }, { 154*88d15eacSSasha Smundak label: "SortSlices", 155*88d15eacSSasha Smundak x: []float64{0, 1, 1, 2, 2, 2, math.NaN(), 3, 3, 3, 3, 4, 4, 4, 4}, 156*88d15eacSSasha Smundak y: []float64{2, 0, 4, 4, 3, math.NaN(), 4, 1, 3, 2, 3, 3, 4, 1, 2}, 157*88d15eacSSasha Smundak opts: []cmp.Option{SortSlices(func(x, y float64) bool { 158*88d15eacSSasha Smundak return (!math.IsNaN(x) && math.IsNaN(y)) || x < y 159*88d15eacSSasha Smundak })}, 160*88d15eacSSasha Smundak wantEqual: false, 161*88d15eacSSasha Smundak reason: "no panics because SortSlices used with valid less function; not equal because NaN != NaN", 162*88d15eacSSasha Smundak }, { 163*88d15eacSSasha Smundak label: "SortSlices+EquateNaNs", 164*88d15eacSSasha Smundak x: []float64{0, 1, 1, 2, 2, 2, math.NaN(), 3, 3, 3, math.NaN(), 3, 4, 4, 4, 4}, 165*88d15eacSSasha Smundak y: []float64{2, 0, 4, 4, 3, math.NaN(), 4, 1, 3, 2, 3, 3, 4, 1, math.NaN(), 2}, 166*88d15eacSSasha Smundak opts: []cmp.Option{ 167*88d15eacSSasha Smundak EquateNaNs(), 168*88d15eacSSasha Smundak SortSlices(func(x, y float64) bool { 169*88d15eacSSasha Smundak return (!math.IsNaN(x) && math.IsNaN(y)) || x < y 170*88d15eacSSasha Smundak }), 171*88d15eacSSasha Smundak }, 172*88d15eacSSasha Smundak wantEqual: true, 173*88d15eacSSasha Smundak reason: "no panics because SortSlices used with valid less function; equal because EquateNaNs is used", 174*88d15eacSSasha Smundak }, { 175*88d15eacSSasha Smundak label: "SortMaps", 176*88d15eacSSasha Smundak x: map[time.Time]string{ 177*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC): "0th birthday", 178*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC): "1st birthday", 179*88d15eacSSasha Smundak time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC): "2nd birthday", 180*88d15eacSSasha Smundak }, 181*88d15eacSSasha Smundak y: map[time.Time]string{ 182*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "0th birthday", 183*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "1st birthday", 184*88d15eacSSasha Smundak time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "2nd birthday", 185*88d15eacSSasha Smundak }, 186*88d15eacSSasha Smundak wantEqual: false, 187*88d15eacSSasha Smundak reason: "not equal because timezones differ", 188*88d15eacSSasha Smundak }, { 189*88d15eacSSasha Smundak label: "SortMaps", 190*88d15eacSSasha Smundak x: map[time.Time]string{ 191*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC): "0th birthday", 192*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC): "1st birthday", 193*88d15eacSSasha Smundak time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC): "2nd birthday", 194*88d15eacSSasha Smundak }, 195*88d15eacSSasha Smundak y: map[time.Time]string{ 196*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "0th birthday", 197*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "1st birthday", 198*88d15eacSSasha Smundak time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "2nd birthday", 199*88d15eacSSasha Smundak }, 200*88d15eacSSasha Smundak opts: []cmp.Option{SortMaps(func(x, y time.Time) bool { return x.Before(y) })}, 201*88d15eacSSasha Smundak wantEqual: true, 202*88d15eacSSasha Smundak reason: "equal because SortMaps flattens to a slice where Time.Equal can be used", 203*88d15eacSSasha Smundak }, { 204*88d15eacSSasha Smundak label: "SortMaps", 205*88d15eacSSasha Smundak x: map[MyTime]string{ 206*88d15eacSSasha Smundak {time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)}: "0th birthday", 207*88d15eacSSasha Smundak {time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)}: "1st birthday", 208*88d15eacSSasha Smundak {time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC)}: "2nd birthday", 209*88d15eacSSasha Smundak }, 210*88d15eacSSasha Smundak y: map[MyTime]string{ 211*88d15eacSSasha Smundak {time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local)}: "0th birthday", 212*88d15eacSSasha Smundak {time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local)}: "1st birthday", 213*88d15eacSSasha Smundak {time.Date(2011, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local)}: "2nd birthday", 214*88d15eacSSasha Smundak }, 215*88d15eacSSasha Smundak opts: []cmp.Option{SortMaps(func(x, y time.Time) bool { return x.Before(y) })}, 216*88d15eacSSasha Smundak wantEqual: false, 217*88d15eacSSasha Smundak reason: "not equal because MyTime is not assignable to time.Time", 218*88d15eacSSasha Smundak }, { 219*88d15eacSSasha Smundak label: "SortMaps", 220*88d15eacSSasha Smundak x: map[int]string{-3: "", -2: "", -1: "", 0: "", 1: "", 2: "", 3: ""}, 221*88d15eacSSasha Smundak // => {0, 1, 2, 3, -1, -2, -3}, 222*88d15eacSSasha Smundak y: map[int]string{300: "", 200: "", 100: "", 0: "", 1: "", 2: "", 3: ""}, 223*88d15eacSSasha Smundak // => {0, 1, 2, 3, 100, 200, 300}, 224*88d15eacSSasha Smundak opts: []cmp.Option{SortMaps(func(a, b int) bool { 225*88d15eacSSasha Smundak if -10 < a && a <= 0 { 226*88d15eacSSasha Smundak a *= -100 227*88d15eacSSasha Smundak } 228*88d15eacSSasha Smundak if -10 < b && b <= 0 { 229*88d15eacSSasha Smundak b *= -100 230*88d15eacSSasha Smundak } 231*88d15eacSSasha Smundak return a < b 232*88d15eacSSasha Smundak })}, 233*88d15eacSSasha Smundak wantEqual: false, 234*88d15eacSSasha Smundak reason: "not equal because values differ even though SortMap provides valid ordering", 235*88d15eacSSasha Smundak }, { 236*88d15eacSSasha Smundak label: "SortMaps", 237*88d15eacSSasha Smundak x: map[int]string{-3: "", -2: "", -1: "", 0: "", 1: "", 2: "", 3: ""}, 238*88d15eacSSasha Smundak // => {0, 1, 2, 3, -1, -2, -3}, 239*88d15eacSSasha Smundak y: map[int]string{300: "", 200: "", 100: "", 0: "", 1: "", 2: "", 3: ""}, 240*88d15eacSSasha Smundak // => {0, 1, 2, 3, 100, 200, 300}, 241*88d15eacSSasha Smundak opts: []cmp.Option{ 242*88d15eacSSasha Smundak SortMaps(func(x, y int) bool { 243*88d15eacSSasha Smundak if -10 < x && x <= 0 { 244*88d15eacSSasha Smundak x *= -100 245*88d15eacSSasha Smundak } 246*88d15eacSSasha Smundak if -10 < y && y <= 0 { 247*88d15eacSSasha Smundak y *= -100 248*88d15eacSSasha Smundak } 249*88d15eacSSasha Smundak return x < y 250*88d15eacSSasha Smundak }), 251*88d15eacSSasha Smundak cmp.Comparer(func(x, y int) bool { 252*88d15eacSSasha Smundak if -10 < x && x <= 0 { 253*88d15eacSSasha Smundak x *= -100 254*88d15eacSSasha Smundak } 255*88d15eacSSasha Smundak if -10 < y && y <= 0 { 256*88d15eacSSasha Smundak y *= -100 257*88d15eacSSasha Smundak } 258*88d15eacSSasha Smundak return x == y 259*88d15eacSSasha Smundak }), 260*88d15eacSSasha Smundak }, 261*88d15eacSSasha Smundak wantEqual: true, 262*88d15eacSSasha Smundak reason: "equal because Comparer used to equate differences", 263*88d15eacSSasha Smundak }, { 264*88d15eacSSasha Smundak label: "SortMaps", 265*88d15eacSSasha Smundak x: map[int]string{-3: "", -2: "", -1: "", 0: "", 1: "", 2: "", 3: ""}, 266*88d15eacSSasha Smundak y: map[int]string{}, 267*88d15eacSSasha Smundak opts: []cmp.Option{SortMaps(func(x, y int) bool { 268*88d15eacSSasha Smundak return x < y && x >= 0 && y >= 0 269*88d15eacSSasha Smundak })}, 270*88d15eacSSasha Smundak wantPanic: true, 271*88d15eacSSasha Smundak reason: "panics because SortMaps used with non-transitive less function", 272*88d15eacSSasha Smundak }, { 273*88d15eacSSasha Smundak label: "SortMaps", 274*88d15eacSSasha Smundak x: map[int]string{-3: "", -2: "", -1: "", 0: "", 1: "", 2: "", 3: ""}, 275*88d15eacSSasha Smundak y: map[int]string{}, 276*88d15eacSSasha Smundak opts: []cmp.Option{SortMaps(func(x, y int) bool { 277*88d15eacSSasha Smundak return math.Abs(float64(x)) < math.Abs(float64(y)) 278*88d15eacSSasha Smundak })}, 279*88d15eacSSasha Smundak wantPanic: true, 280*88d15eacSSasha Smundak reason: "panics because SortMaps used with partial less function", 281*88d15eacSSasha Smundak }, { 282*88d15eacSSasha Smundak label: "EquateEmpty+SortSlices+SortMaps", 283*88d15eacSSasha Smundak x: MyStruct{ 284*88d15eacSSasha Smundak A: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 285*88d15eacSSasha Smundak C: map[time.Time]string{ 286*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC): "0th birthday", 287*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC): "1st birthday", 288*88d15eacSSasha Smundak }, 289*88d15eacSSasha Smundak D: map[time.Time]string{}, 290*88d15eacSSasha Smundak }, 291*88d15eacSSasha Smundak y: MyStruct{ 292*88d15eacSSasha Smundak A: []int{1, 0, 5, 2, 8, 9, 4, 3, 6, 7}, 293*88d15eacSSasha Smundak B: []int{}, 294*88d15eacSSasha Smundak C: map[time.Time]string{ 295*88d15eacSSasha Smundak time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "0th birthday", 296*88d15eacSSasha Smundak time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC).In(time.Local): "1st birthday", 297*88d15eacSSasha Smundak }, 298*88d15eacSSasha Smundak }, 299*88d15eacSSasha Smundak opts: []cmp.Option{ 300*88d15eacSSasha Smundak EquateEmpty(), 301*88d15eacSSasha Smundak SortSlices(func(x, y int) bool { return x < y }), 302*88d15eacSSasha Smundak SortMaps(func(x, y time.Time) bool { return x.Before(y) }), 303*88d15eacSSasha Smundak }, 304*88d15eacSSasha Smundak wantEqual: true, 305*88d15eacSSasha Smundak reason: "no panics because EquateEmpty should compose with the sort options", 306*88d15eacSSasha Smundak }, { 307*88d15eacSSasha Smundak label: "EquateApprox", 308*88d15eacSSasha Smundak x: 3.09, 309*88d15eacSSasha Smundak y: 3.10, 310*88d15eacSSasha Smundak wantEqual: false, 311*88d15eacSSasha Smundak reason: "not equal because floats do not exactly matches", 312*88d15eacSSasha Smundak }, { 313*88d15eacSSasha Smundak label: "EquateApprox", 314*88d15eacSSasha Smundak x: 3.09, 315*88d15eacSSasha Smundak y: 3.10, 316*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 0)}, 317*88d15eacSSasha Smundak wantEqual: false, 318*88d15eacSSasha Smundak reason: "not equal because EquateApprox(0 ,0) is equivalent to using ==", 319*88d15eacSSasha Smundak }, { 320*88d15eacSSasha Smundak label: "EquateApprox", 321*88d15eacSSasha Smundak x: 3.09, 322*88d15eacSSasha Smundak y: 3.10, 323*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0.003, 0.009)}, 324*88d15eacSSasha Smundak wantEqual: false, 325*88d15eacSSasha Smundak reason: "not equal because EquateApprox is too strict", 326*88d15eacSSasha Smundak }, { 327*88d15eacSSasha Smundak label: "EquateApprox", 328*88d15eacSSasha Smundak x: 3.09, 329*88d15eacSSasha Smundak y: 3.10, 330*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 0.011)}, 331*88d15eacSSasha Smundak wantEqual: true, 332*88d15eacSSasha Smundak reason: "equal because margin is loose enough to match", 333*88d15eacSSasha Smundak }, { 334*88d15eacSSasha Smundak label: "EquateApprox", 335*88d15eacSSasha Smundak x: 3.09, 336*88d15eacSSasha Smundak y: 3.10, 337*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0.004, 0)}, 338*88d15eacSSasha Smundak wantEqual: true, 339*88d15eacSSasha Smundak reason: "equal because fraction is loose enough to match", 340*88d15eacSSasha Smundak }, { 341*88d15eacSSasha Smundak label: "EquateApprox", 342*88d15eacSSasha Smundak x: 3.09, 343*88d15eacSSasha Smundak y: 3.10, 344*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0.004, 0.011)}, 345*88d15eacSSasha Smundak wantEqual: true, 346*88d15eacSSasha Smundak reason: "equal because both the margin and fraction are loose enough to match", 347*88d15eacSSasha Smundak }, { 348*88d15eacSSasha Smundak label: "EquateApprox", 349*88d15eacSSasha Smundak x: float32(3.09), 350*88d15eacSSasha Smundak y: float64(3.10), 351*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0.004, 0)}, 352*88d15eacSSasha Smundak wantEqual: false, 353*88d15eacSSasha Smundak reason: "not equal because the types differ", 354*88d15eacSSasha Smundak }, { 355*88d15eacSSasha Smundak label: "EquateApprox", 356*88d15eacSSasha Smundak x: float32(3.09), 357*88d15eacSSasha Smundak y: float32(3.10), 358*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0.004, 0)}, 359*88d15eacSSasha Smundak wantEqual: true, 360*88d15eacSSasha Smundak reason: "equal because EquateApprox also applies on float32s", 361*88d15eacSSasha Smundak }, { 362*88d15eacSSasha Smundak label: "EquateApprox", 363*88d15eacSSasha Smundak x: []float64{math.Inf(+1), math.Inf(-1)}, 364*88d15eacSSasha Smundak y: []float64{math.Inf(+1), math.Inf(-1)}, 365*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 1)}, 366*88d15eacSSasha Smundak wantEqual: true, 367*88d15eacSSasha Smundak reason: "equal because we fall back on == which matches Inf (EquateApprox does not apply on Inf) ", 368*88d15eacSSasha Smundak }, { 369*88d15eacSSasha Smundak label: "EquateApprox", 370*88d15eacSSasha Smundak x: []float64{math.Inf(+1), -1e100}, 371*88d15eacSSasha Smundak y: []float64{+1e100, math.Inf(-1)}, 372*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 1)}, 373*88d15eacSSasha Smundak wantEqual: false, 374*88d15eacSSasha Smundak reason: "not equal because we fall back on == where Inf != 1e100 (EquateApprox does not apply on Inf)", 375*88d15eacSSasha Smundak }, { 376*88d15eacSSasha Smundak label: "EquateApprox", 377*88d15eacSSasha Smundak x: float64(+1e100), 378*88d15eacSSasha Smundak y: float64(-1e100), 379*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(math.Inf(+1), 0)}, 380*88d15eacSSasha Smundak wantEqual: true, 381*88d15eacSSasha Smundak reason: "equal because infinite fraction matches everything", 382*88d15eacSSasha Smundak }, { 383*88d15eacSSasha Smundak label: "EquateApprox", 384*88d15eacSSasha Smundak x: float64(+1e100), 385*88d15eacSSasha Smundak y: float64(-1e100), 386*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, math.Inf(+1))}, 387*88d15eacSSasha Smundak wantEqual: true, 388*88d15eacSSasha Smundak reason: "equal because infinite margin matches everything", 389*88d15eacSSasha Smundak }, { 390*88d15eacSSasha Smundak label: "EquateApprox", 391*88d15eacSSasha Smundak x: math.Pi, 392*88d15eacSSasha Smundak y: math.Pi, 393*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 0)}, 394*88d15eacSSasha Smundak wantEqual: true, 395*88d15eacSSasha Smundak reason: "equal because EquateApprox(0, 0) is equivalent to ==", 396*88d15eacSSasha Smundak }, { 397*88d15eacSSasha Smundak label: "EquateApprox", 398*88d15eacSSasha Smundak x: math.Pi, 399*88d15eacSSasha Smundak y: math.Nextafter(math.Pi, math.Inf(+1)), 400*88d15eacSSasha Smundak opts: []cmp.Option{EquateApprox(0, 0)}, 401*88d15eacSSasha Smundak wantEqual: false, 402*88d15eacSSasha Smundak reason: "not equal because EquateApprox(0, 0) is equivalent to ==", 403*88d15eacSSasha Smundak }, { 404*88d15eacSSasha Smundak label: "EquateNaNs", 405*88d15eacSSasha Smundak x: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1)}, 406*88d15eacSSasha Smundak y: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1)}, 407*88d15eacSSasha Smundak wantEqual: false, 408*88d15eacSSasha Smundak reason: "not equal because NaN != NaN", 409*88d15eacSSasha Smundak }, { 410*88d15eacSSasha Smundak label: "EquateNaNs", 411*88d15eacSSasha Smundak x: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1)}, 412*88d15eacSSasha Smundak y: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1)}, 413*88d15eacSSasha Smundak opts: []cmp.Option{EquateNaNs()}, 414*88d15eacSSasha Smundak wantEqual: true, 415*88d15eacSSasha Smundak reason: "equal because EquateNaNs allows NaN == NaN", 416*88d15eacSSasha Smundak }, { 417*88d15eacSSasha Smundak label: "EquateNaNs", 418*88d15eacSSasha Smundak x: []float32{1.0, float32(math.NaN()), math.E, -0.0, +0.0}, 419*88d15eacSSasha Smundak y: []float32{1.0, float32(math.NaN()), math.E, -0.0, +0.0}, 420*88d15eacSSasha Smundak opts: []cmp.Option{EquateNaNs()}, 421*88d15eacSSasha Smundak wantEqual: true, 422*88d15eacSSasha Smundak reason: "equal because EquateNaNs operates on float32", 423*88d15eacSSasha Smundak }, { 424*88d15eacSSasha Smundak label: "EquateApprox+EquateNaNs", 425*88d15eacSSasha Smundak x: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1), 1.01, 5001}, 426*88d15eacSSasha Smundak y: []float64{1.0, math.NaN(), math.E, -0.0, +0.0, math.Inf(+1), math.Inf(-1), 1.02, 5002}, 427*88d15eacSSasha Smundak opts: []cmp.Option{ 428*88d15eacSSasha Smundak EquateNaNs(), 429*88d15eacSSasha Smundak EquateApprox(0.01, 0), 430*88d15eacSSasha Smundak }, 431*88d15eacSSasha Smundak wantEqual: true, 432*88d15eacSSasha Smundak reason: "equal because EquateNaNs and EquateApprox compose together", 433*88d15eacSSasha Smundak }, { 434*88d15eacSSasha Smundak label: "EquateApprox+EquateNaNs", 435*88d15eacSSasha Smundak x: []MyFloat{1.0, MyFloat(math.NaN()), MyFloat(math.E), -0.0, +0.0, MyFloat(math.Inf(+1)), MyFloat(math.Inf(-1)), 1.01, 5001}, 436*88d15eacSSasha Smundak y: []MyFloat{1.0, MyFloat(math.NaN()), MyFloat(math.E), -0.0, +0.0, MyFloat(math.Inf(+1)), MyFloat(math.Inf(-1)), 1.02, 5002}, 437*88d15eacSSasha Smundak opts: []cmp.Option{ 438*88d15eacSSasha Smundak EquateNaNs(), 439*88d15eacSSasha Smundak EquateApprox(0.01, 0), 440*88d15eacSSasha Smundak }, 441*88d15eacSSasha Smundak wantEqual: false, 442*88d15eacSSasha Smundak reason: "not equal because EquateApprox and EquateNaNs do not apply on a named type", 443*88d15eacSSasha Smundak }, { 444*88d15eacSSasha Smundak label: "EquateApprox+EquateNaNs+Transform", 445*88d15eacSSasha Smundak x: []MyFloat{1.0, MyFloat(math.NaN()), MyFloat(math.E), -0.0, +0.0, MyFloat(math.Inf(+1)), MyFloat(math.Inf(-1)), 1.01, 5001}, 446*88d15eacSSasha Smundak y: []MyFloat{1.0, MyFloat(math.NaN()), MyFloat(math.E), -0.0, +0.0, MyFloat(math.Inf(+1)), MyFloat(math.Inf(-1)), 1.02, 5002}, 447*88d15eacSSasha Smundak opts: []cmp.Option{ 448*88d15eacSSasha Smundak cmp.Transformer("", func(x MyFloat) float64 { return float64(x) }), 449*88d15eacSSasha Smundak EquateNaNs(), 450*88d15eacSSasha Smundak EquateApprox(0.01, 0), 451*88d15eacSSasha Smundak }, 452*88d15eacSSasha Smundak wantEqual: true, 453*88d15eacSSasha Smundak reason: "equal because named type is transformed to float64", 454*88d15eacSSasha Smundak }, { 455*88d15eacSSasha Smundak label: "EquateApproxTime", 456*88d15eacSSasha Smundak x: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 457*88d15eacSSasha Smundak y: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 458*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(0)}, 459*88d15eacSSasha Smundak wantEqual: true, 460*88d15eacSSasha Smundak reason: "equal because times are identical", 461*88d15eacSSasha Smundak }, { 462*88d15eacSSasha Smundak label: "EquateApproxTime", 463*88d15eacSSasha Smundak x: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 464*88d15eacSSasha Smundak y: time.Date(2009, 11, 10, 23, 0, 3, 0, time.UTC), 465*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 466*88d15eacSSasha Smundak wantEqual: true, 467*88d15eacSSasha Smundak reason: "equal because time is exactly at the allowed margin", 468*88d15eacSSasha Smundak }, { 469*88d15eacSSasha Smundak label: "EquateApproxTime", 470*88d15eacSSasha Smundak x: time.Date(2009, 11, 10, 23, 0, 3, 0, time.UTC), 471*88d15eacSSasha Smundak y: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 472*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 473*88d15eacSSasha Smundak wantEqual: true, 474*88d15eacSSasha Smundak reason: "equal because time is exactly at the allowed margin (negative)", 475*88d15eacSSasha Smundak }, { 476*88d15eacSSasha Smundak label: "EquateApproxTime", 477*88d15eacSSasha Smundak x: time.Date(2009, 11, 10, 23, 0, 3, 0, time.UTC), 478*88d15eacSSasha Smundak y: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 479*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3*time.Second - 1)}, 480*88d15eacSSasha Smundak wantEqual: false, 481*88d15eacSSasha Smundak reason: "not equal because time is outside allowed margin", 482*88d15eacSSasha Smundak }, { 483*88d15eacSSasha Smundak label: "EquateApproxTime", 484*88d15eacSSasha Smundak x: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), 485*88d15eacSSasha Smundak y: time.Date(2009, 11, 10, 23, 0, 3, 0, time.UTC), 486*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3*time.Second - 1)}, 487*88d15eacSSasha Smundak wantEqual: false, 488*88d15eacSSasha Smundak reason: "not equal because time is outside allowed margin (negative)", 489*88d15eacSSasha Smundak }, { 490*88d15eacSSasha Smundak label: "EquateApproxTime", 491*88d15eacSSasha Smundak x: time.Time{}, 492*88d15eacSSasha Smundak y: time.Time{}, 493*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 494*88d15eacSSasha Smundak wantEqual: true, 495*88d15eacSSasha Smundak reason: "equal because both times are zero", 496*88d15eacSSasha Smundak }, { 497*88d15eacSSasha Smundak label: "EquateApproxTime", 498*88d15eacSSasha Smundak x: time.Time{}, 499*88d15eacSSasha Smundak y: time.Time{}.Add(1), 500*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 501*88d15eacSSasha Smundak wantEqual: false, 502*88d15eacSSasha Smundak reason: "not equal because zero time is always not equal not non-zero", 503*88d15eacSSasha Smundak }, { 504*88d15eacSSasha Smundak label: "EquateApproxTime", 505*88d15eacSSasha Smundak x: time.Time{}.Add(1), 506*88d15eacSSasha Smundak y: time.Time{}, 507*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 508*88d15eacSSasha Smundak wantEqual: false, 509*88d15eacSSasha Smundak reason: "not equal because zero time is always not equal not non-zero", 510*88d15eacSSasha Smundak }, { 511*88d15eacSSasha Smundak label: "EquateApproxTime", 512*88d15eacSSasha Smundak x: time.Date(2409, 11, 10, 23, 0, 0, 0, time.UTC), 513*88d15eacSSasha Smundak y: time.Date(2000, 11, 10, 23, 0, 3, 0, time.UTC), 514*88d15eacSSasha Smundak opts: []cmp.Option{EquateApproxTime(3 * time.Second)}, 515*88d15eacSSasha Smundak wantEqual: false, 516*88d15eacSSasha Smundak reason: "time difference overflows time.Duration", 517*88d15eacSSasha Smundak }, { 518*88d15eacSSasha Smundak label: "EquateErrors", 519*88d15eacSSasha Smundak x: nil, 520*88d15eacSSasha Smundak y: nil, 521*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 522*88d15eacSSasha Smundak wantEqual: true, 523*88d15eacSSasha Smundak reason: "nil values are equal", 524*88d15eacSSasha Smundak }, { 525*88d15eacSSasha Smundak label: "EquateErrors", 526*88d15eacSSasha Smundak x: errors.New("EOF"), 527*88d15eacSSasha Smundak y: io.EOF, 528*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 529*88d15eacSSasha Smundak wantEqual: false, 530*88d15eacSSasha Smundak reason: "user-defined EOF is not exactly equal", 531*88d15eacSSasha Smundak }, { 532*88d15eacSSasha Smundak label: "EquateErrors", 533*88d15eacSSasha Smundak x: fmt.Errorf("wrapped: %w", io.EOF), 534*88d15eacSSasha Smundak y: io.EOF, 535*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 536*88d15eacSSasha Smundak wantEqual: true, 537*88d15eacSSasha Smundak reason: "wrapped io.EOF is equal according to errors.Is", 538*88d15eacSSasha Smundak }, { 539*88d15eacSSasha Smundak label: "EquateErrors", 540*88d15eacSSasha Smundak x: fmt.Errorf("wrapped: %w", io.EOF), 541*88d15eacSSasha Smundak y: io.EOF, 542*88d15eacSSasha Smundak wantEqual: false, 543*88d15eacSSasha Smundak reason: "wrapped io.EOF is not equal without EquateErrors option", 544*88d15eacSSasha Smundak }, { 545*88d15eacSSasha Smundak label: "EquateErrors", 546*88d15eacSSasha Smundak x: io.EOF, 547*88d15eacSSasha Smundak y: io.EOF, 548*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 549*88d15eacSSasha Smundak wantEqual: true, 550*88d15eacSSasha Smundak reason: "sentinel errors are equal", 551*88d15eacSSasha Smundak }, { 552*88d15eacSSasha Smundak label: "EquateErrors", 553*88d15eacSSasha Smundak x: io.EOF, 554*88d15eacSSasha Smundak y: AnyError, 555*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 556*88d15eacSSasha Smundak wantEqual: true, 557*88d15eacSSasha Smundak reason: "AnyError is equal to any non-nil error", 558*88d15eacSSasha Smundak }, { 559*88d15eacSSasha Smundak label: "EquateErrors", 560*88d15eacSSasha Smundak x: io.EOF, 561*88d15eacSSasha Smundak y: AnyError, 562*88d15eacSSasha Smundak wantEqual: false, 563*88d15eacSSasha Smundak reason: "AnyError is not equal to any non-nil error without EquateErrors option", 564*88d15eacSSasha Smundak }, { 565*88d15eacSSasha Smundak label: "EquateErrors", 566*88d15eacSSasha Smundak x: nil, 567*88d15eacSSasha Smundak y: AnyError, 568*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 569*88d15eacSSasha Smundak wantEqual: false, 570*88d15eacSSasha Smundak reason: "AnyError is not equal to nil value", 571*88d15eacSSasha Smundak }, { 572*88d15eacSSasha Smundak label: "EquateErrors", 573*88d15eacSSasha Smundak x: nil, 574*88d15eacSSasha Smundak y: nil, 575*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 576*88d15eacSSasha Smundak wantEqual: true, 577*88d15eacSSasha Smundak reason: "nil values are equal", 578*88d15eacSSasha Smundak }, { 579*88d15eacSSasha Smundak label: "EquateErrors", 580*88d15eacSSasha Smundak x: errors.New("EOF"), 581*88d15eacSSasha Smundak y: io.EOF, 582*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 583*88d15eacSSasha Smundak wantEqual: false, 584*88d15eacSSasha Smundak reason: "user-defined EOF is not exactly equal", 585*88d15eacSSasha Smundak }, { 586*88d15eacSSasha Smundak label: "EquateErrors", 587*88d15eacSSasha Smundak x: fmt.Errorf("wrapped: %w", io.EOF), 588*88d15eacSSasha Smundak y: io.EOF, 589*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 590*88d15eacSSasha Smundak wantEqual: true, 591*88d15eacSSasha Smundak reason: "wrapped io.EOF is equal according to errors.Is", 592*88d15eacSSasha Smundak }, { 593*88d15eacSSasha Smundak label: "EquateErrors", 594*88d15eacSSasha Smundak x: fmt.Errorf("wrapped: %w", io.EOF), 595*88d15eacSSasha Smundak y: io.EOF, 596*88d15eacSSasha Smundak wantEqual: false, 597*88d15eacSSasha Smundak reason: "wrapped io.EOF is not equal without EquateErrors option", 598*88d15eacSSasha Smundak }, { 599*88d15eacSSasha Smundak label: "EquateErrors", 600*88d15eacSSasha Smundak x: io.EOF, 601*88d15eacSSasha Smundak y: io.EOF, 602*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 603*88d15eacSSasha Smundak wantEqual: true, 604*88d15eacSSasha Smundak reason: "sentinel errors are equal", 605*88d15eacSSasha Smundak }, { 606*88d15eacSSasha Smundak label: "EquateErrors", 607*88d15eacSSasha Smundak x: io.EOF, 608*88d15eacSSasha Smundak y: AnyError, 609*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 610*88d15eacSSasha Smundak wantEqual: true, 611*88d15eacSSasha Smundak reason: "AnyError is equal to any non-nil error", 612*88d15eacSSasha Smundak }, { 613*88d15eacSSasha Smundak label: "EquateErrors", 614*88d15eacSSasha Smundak x: io.EOF, 615*88d15eacSSasha Smundak y: AnyError, 616*88d15eacSSasha Smundak wantEqual: false, 617*88d15eacSSasha Smundak reason: "AnyError is not equal to any non-nil error without EquateErrors option", 618*88d15eacSSasha Smundak }, { 619*88d15eacSSasha Smundak label: "EquateErrors", 620*88d15eacSSasha Smundak x: nil, 621*88d15eacSSasha Smundak y: AnyError, 622*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 623*88d15eacSSasha Smundak wantEqual: false, 624*88d15eacSSasha Smundak reason: "AnyError is not equal to nil value", 625*88d15eacSSasha Smundak }, { 626*88d15eacSSasha Smundak label: "EquateErrors", 627*88d15eacSSasha Smundak x: struct{ E error }{nil}, 628*88d15eacSSasha Smundak y: struct{ E error }{nil}, 629*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 630*88d15eacSSasha Smundak wantEqual: true, 631*88d15eacSSasha Smundak reason: "nil values are equal", 632*88d15eacSSasha Smundak }, { 633*88d15eacSSasha Smundak label: "EquateErrors", 634*88d15eacSSasha Smundak x: struct{ E error }{errors.New("EOF")}, 635*88d15eacSSasha Smundak y: struct{ E error }{io.EOF}, 636*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 637*88d15eacSSasha Smundak wantEqual: false, 638*88d15eacSSasha Smundak reason: "user-defined EOF is not exactly equal", 639*88d15eacSSasha Smundak }, { 640*88d15eacSSasha Smundak label: "EquateErrors", 641*88d15eacSSasha Smundak x: struct{ E error }{fmt.Errorf("wrapped: %w", io.EOF)}, 642*88d15eacSSasha Smundak y: struct{ E error }{io.EOF}, 643*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 644*88d15eacSSasha Smundak wantEqual: true, 645*88d15eacSSasha Smundak reason: "wrapped io.EOF is equal according to errors.Is", 646*88d15eacSSasha Smundak }, { 647*88d15eacSSasha Smundak label: "EquateErrors", 648*88d15eacSSasha Smundak x: struct{ E error }{fmt.Errorf("wrapped: %w", io.EOF)}, 649*88d15eacSSasha Smundak y: struct{ E error }{io.EOF}, 650*88d15eacSSasha Smundak wantEqual: false, 651*88d15eacSSasha Smundak reason: "wrapped io.EOF is not equal without EquateErrors option", 652*88d15eacSSasha Smundak }, { 653*88d15eacSSasha Smundak label: "EquateErrors", 654*88d15eacSSasha Smundak x: struct{ E error }{io.EOF}, 655*88d15eacSSasha Smundak y: struct{ E error }{io.EOF}, 656*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 657*88d15eacSSasha Smundak wantEqual: true, 658*88d15eacSSasha Smundak reason: "sentinel errors are equal", 659*88d15eacSSasha Smundak }, { 660*88d15eacSSasha Smundak label: "EquateErrors", 661*88d15eacSSasha Smundak x: struct{ E error }{io.EOF}, 662*88d15eacSSasha Smundak y: struct{ E error }{AnyError}, 663*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 664*88d15eacSSasha Smundak wantEqual: true, 665*88d15eacSSasha Smundak reason: "AnyError is equal to any non-nil error", 666*88d15eacSSasha Smundak }, { 667*88d15eacSSasha Smundak label: "EquateErrors", 668*88d15eacSSasha Smundak x: struct{ E error }{io.EOF}, 669*88d15eacSSasha Smundak y: struct{ E error }{AnyError}, 670*88d15eacSSasha Smundak wantEqual: false, 671*88d15eacSSasha Smundak reason: "AnyError is not equal to any non-nil error without EquateErrors option", 672*88d15eacSSasha Smundak }, { 673*88d15eacSSasha Smundak label: "EquateErrors", 674*88d15eacSSasha Smundak x: struct{ E error }{nil}, 675*88d15eacSSasha Smundak y: struct{ E error }{AnyError}, 676*88d15eacSSasha Smundak opts: []cmp.Option{EquateErrors()}, 677*88d15eacSSasha Smundak wantEqual: false, 678*88d15eacSSasha Smundak reason: "AnyError is not equal to nil value", 679*88d15eacSSasha Smundak }, { 680*88d15eacSSasha Smundak label: "IgnoreFields", 681*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 682*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 683*88d15eacSSasha Smundak wantEqual: false, 684*88d15eacSSasha Smundak reason: "not equal because values do not match in deeply embedded field", 685*88d15eacSSasha Smundak }, { 686*88d15eacSSasha Smundak label: "IgnoreFields", 687*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 688*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 689*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar1{}, "Alpha")}, 690*88d15eacSSasha Smundak wantEqual: true, 691*88d15eacSSasha Smundak reason: "equal because IgnoreField ignores deeply embedded field: Alpha", 692*88d15eacSSasha Smundak }, { 693*88d15eacSSasha Smundak label: "IgnoreFields", 694*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 695*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 696*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar1{}, "Foo1.Alpha")}, 697*88d15eacSSasha Smundak wantEqual: true, 698*88d15eacSSasha Smundak reason: "equal because IgnoreField ignores deeply embedded field: Foo1.Alpha", 699*88d15eacSSasha Smundak }, { 700*88d15eacSSasha Smundak label: "IgnoreFields", 701*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 702*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 703*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar1{}, "Foo2.Alpha")}, 704*88d15eacSSasha Smundak wantEqual: true, 705*88d15eacSSasha Smundak reason: "equal because IgnoreField ignores deeply embedded field: Foo2.Alpha", 706*88d15eacSSasha Smundak }, { 707*88d15eacSSasha Smundak label: "IgnoreFields", 708*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 709*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 710*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar1{}, "Foo3.Alpha")}, 711*88d15eacSSasha Smundak wantEqual: true, 712*88d15eacSSasha Smundak reason: "equal because IgnoreField ignores deeply embedded field: Foo3.Alpha", 713*88d15eacSSasha Smundak }, { 714*88d15eacSSasha Smundak label: "IgnoreFields", 715*88d15eacSSasha Smundak x: Bar1{Foo3{&Foo2{&Foo1{Alpha: 5}}}}, 716*88d15eacSSasha Smundak y: Bar1{Foo3{&Foo2{&Foo1{Alpha: 6}}}}, 717*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar1{}, "Foo3.Foo2.Alpha")}, 718*88d15eacSSasha Smundak wantEqual: true, 719*88d15eacSSasha Smundak reason: "equal because IgnoreField ignores deeply embedded field: Foo3.Foo2.Alpha", 720*88d15eacSSasha Smundak }, { 721*88d15eacSSasha Smundak label: "IgnoreFields", 722*88d15eacSSasha Smundak x: createBar3X(), 723*88d15eacSSasha Smundak y: createBar3Y(), 724*88d15eacSSasha Smundak wantEqual: false, 725*88d15eacSSasha Smundak reason: "not equal because many deeply nested or embedded fields differ", 726*88d15eacSSasha Smundak }, { 727*88d15eacSSasha Smundak label: "IgnoreFields", 728*88d15eacSSasha Smundak x: createBar3X(), 729*88d15eacSSasha Smundak y: createBar3Y(), 730*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar3{}, "Bar1", "Bravo", "Delta", "Foo3", "Alpha")}, 731*88d15eacSSasha Smundak wantEqual: true, 732*88d15eacSSasha Smundak reason: "equal because IgnoreFields ignores fields at the highest levels", 733*88d15eacSSasha Smundak }, { 734*88d15eacSSasha Smundak label: "IgnoreFields", 735*88d15eacSSasha Smundak x: createBar3X(), 736*88d15eacSSasha Smundak y: createBar3Y(), 737*88d15eacSSasha Smundak opts: []cmp.Option{ 738*88d15eacSSasha Smundak IgnoreFields(Bar3{}, 739*88d15eacSSasha Smundak "Bar1.Foo3.Bravo", 740*88d15eacSSasha Smundak "Bravo.Bar1.Foo3.Foo2.Foo1.Charlie", 741*88d15eacSSasha Smundak "Bravo.Foo3.Foo2.Foo1.Bravo", 742*88d15eacSSasha Smundak "Bravo.Bravo", 743*88d15eacSSasha Smundak "Delta.Echo.Charlie", 744*88d15eacSSasha Smundak "Foo3.Foo2.Foo1.Alpha", 745*88d15eacSSasha Smundak "Alpha", 746*88d15eacSSasha Smundak ), 747*88d15eacSSasha Smundak }, 748*88d15eacSSasha Smundak wantEqual: true, 749*88d15eacSSasha Smundak reason: "equal because IgnoreFields ignores fields using fully-qualified field", 750*88d15eacSSasha Smundak }, { 751*88d15eacSSasha Smundak label: "IgnoreFields", 752*88d15eacSSasha Smundak x: createBar3X(), 753*88d15eacSSasha Smundak y: createBar3Y(), 754*88d15eacSSasha Smundak opts: []cmp.Option{ 755*88d15eacSSasha Smundak IgnoreFields(Bar3{}, 756*88d15eacSSasha Smundak "Bar1.Foo3.Bravo", 757*88d15eacSSasha Smundak "Bravo.Foo3.Foo2.Foo1.Bravo", 758*88d15eacSSasha Smundak "Bravo.Bravo", 759*88d15eacSSasha Smundak "Delta.Echo.Charlie", 760*88d15eacSSasha Smundak "Foo3.Foo2.Foo1.Alpha", 761*88d15eacSSasha Smundak "Alpha", 762*88d15eacSSasha Smundak ), 763*88d15eacSSasha Smundak }, 764*88d15eacSSasha Smundak wantEqual: false, 765*88d15eacSSasha Smundak reason: "not equal because one fully-qualified field is not ignored: Bravo.Bar1.Foo3.Foo2.Foo1.Charlie", 766*88d15eacSSasha Smundak }, { 767*88d15eacSSasha Smundak label: "IgnoreFields", 768*88d15eacSSasha Smundak x: createBar3X(), 769*88d15eacSSasha Smundak y: createBar3Y(), 770*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreFields(Bar3{}, "Bar1", "Bravo", "Delta", "Alpha")}, 771*88d15eacSSasha Smundak wantEqual: false, 772*88d15eacSSasha Smundak reason: "not equal because highest-level field is not ignored: Foo3", 773*88d15eacSSasha Smundak }, { 774*88d15eacSSasha Smundak label: "IgnoreFields", 775*88d15eacSSasha Smundak x: ParentStruct{ 776*88d15eacSSasha Smundak privateStruct: &privateStruct{private: 1}, 777*88d15eacSSasha Smundak PublicStruct: &PublicStruct{private: 2}, 778*88d15eacSSasha Smundak private: 3, 779*88d15eacSSasha Smundak }, 780*88d15eacSSasha Smundak y: ParentStruct{ 781*88d15eacSSasha Smundak privateStruct: &privateStruct{private: 10}, 782*88d15eacSSasha Smundak PublicStruct: &PublicStruct{private: 20}, 783*88d15eacSSasha Smundak private: 30, 784*88d15eacSSasha Smundak }, 785*88d15eacSSasha Smundak opts: []cmp.Option{cmp.AllowUnexported(ParentStruct{}, PublicStruct{}, privateStruct{})}, 786*88d15eacSSasha Smundak wantEqual: false, 787*88d15eacSSasha Smundak reason: "not equal because unexported fields mismatch", 788*88d15eacSSasha Smundak }, { 789*88d15eacSSasha Smundak label: "IgnoreFields", 790*88d15eacSSasha Smundak x: ParentStruct{ 791*88d15eacSSasha Smundak privateStruct: &privateStruct{private: 1}, 792*88d15eacSSasha Smundak PublicStruct: &PublicStruct{private: 2}, 793*88d15eacSSasha Smundak private: 3, 794*88d15eacSSasha Smundak }, 795*88d15eacSSasha Smundak y: ParentStruct{ 796*88d15eacSSasha Smundak privateStruct: &privateStruct{private: 10}, 797*88d15eacSSasha Smundak PublicStruct: &PublicStruct{private: 20}, 798*88d15eacSSasha Smundak private: 30, 799*88d15eacSSasha Smundak }, 800*88d15eacSSasha Smundak opts: []cmp.Option{ 801*88d15eacSSasha Smundak cmp.AllowUnexported(ParentStruct{}, PublicStruct{}, privateStruct{}), 802*88d15eacSSasha Smundak IgnoreFields(ParentStruct{}, "PublicStruct.private", "privateStruct.private", "private"), 803*88d15eacSSasha Smundak }, 804*88d15eacSSasha Smundak wantEqual: true, 805*88d15eacSSasha Smundak reason: "equal because mismatching unexported fields are ignored", 806*88d15eacSSasha Smundak }, { 807*88d15eacSSasha Smundak label: "IgnoreTypes", 808*88d15eacSSasha Smundak x: []interface{}{5, "same"}, 809*88d15eacSSasha Smundak y: []interface{}{6, "same"}, 810*88d15eacSSasha Smundak wantEqual: false, 811*88d15eacSSasha Smundak reason: "not equal because 5 != 6", 812*88d15eacSSasha Smundak }, { 813*88d15eacSSasha Smundak label: "IgnoreTypes", 814*88d15eacSSasha Smundak x: []interface{}{5, "same"}, 815*88d15eacSSasha Smundak y: []interface{}{6, "same"}, 816*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreTypes(0)}, 817*88d15eacSSasha Smundak wantEqual: true, 818*88d15eacSSasha Smundak reason: "equal because ints are ignored", 819*88d15eacSSasha Smundak }, { 820*88d15eacSSasha Smundak label: "IgnoreTypes+IgnoreInterfaces", 821*88d15eacSSasha Smundak x: []interface{}{5, "same", new(bytes.Buffer)}, 822*88d15eacSSasha Smundak y: []interface{}{6, "same", new(bytes.Buffer)}, 823*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreTypes(0)}, 824*88d15eacSSasha Smundak wantPanic: true, 825*88d15eacSSasha Smundak reason: "panics because bytes.Buffer has unexported fields", 826*88d15eacSSasha Smundak }, { 827*88d15eacSSasha Smundak label: "IgnoreTypes+IgnoreInterfaces", 828*88d15eacSSasha Smundak x: []interface{}{5, "same", new(bytes.Buffer)}, 829*88d15eacSSasha Smundak y: []interface{}{6, "diff", new(bytes.Buffer)}, 830*88d15eacSSasha Smundak opts: []cmp.Option{ 831*88d15eacSSasha Smundak IgnoreTypes(0, ""), 832*88d15eacSSasha Smundak IgnoreInterfaces(struct{ io.Reader }{}), 833*88d15eacSSasha Smundak }, 834*88d15eacSSasha Smundak wantEqual: true, 835*88d15eacSSasha Smundak reason: "equal because bytes.Buffer is ignored by match on interface type", 836*88d15eacSSasha Smundak }, { 837*88d15eacSSasha Smundak label: "IgnoreTypes+IgnoreInterfaces", 838*88d15eacSSasha Smundak x: []interface{}{5, "same", new(bytes.Buffer)}, 839*88d15eacSSasha Smundak y: []interface{}{6, "same", new(bytes.Buffer)}, 840*88d15eacSSasha Smundak opts: []cmp.Option{ 841*88d15eacSSasha Smundak IgnoreTypes(0, ""), 842*88d15eacSSasha Smundak IgnoreInterfaces(struct { 843*88d15eacSSasha Smundak io.Reader 844*88d15eacSSasha Smundak io.Writer 845*88d15eacSSasha Smundak fmt.Stringer 846*88d15eacSSasha Smundak }{}), 847*88d15eacSSasha Smundak }, 848*88d15eacSSasha Smundak wantEqual: true, 849*88d15eacSSasha Smundak reason: "equal because bytes.Buffer is ignored by match on multiple interface types", 850*88d15eacSSasha Smundak }, { 851*88d15eacSSasha Smundak label: "IgnoreInterfaces", 852*88d15eacSSasha Smundak x: struct{ mu sync.Mutex }{}, 853*88d15eacSSasha Smundak y: struct{ mu sync.Mutex }{}, 854*88d15eacSSasha Smundak wantPanic: true, 855*88d15eacSSasha Smundak reason: "panics because sync.Mutex has unexported fields", 856*88d15eacSSasha Smundak }, { 857*88d15eacSSasha Smundak label: "IgnoreInterfaces", 858*88d15eacSSasha Smundak x: struct{ mu sync.Mutex }{}, 859*88d15eacSSasha Smundak y: struct{ mu sync.Mutex }{}, 860*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreInterfaces(struct{ sync.Locker }{})}, 861*88d15eacSSasha Smundak wantEqual: true, 862*88d15eacSSasha Smundak reason: "equal because IgnoreInterfaces applies on values (with pointer receiver)", 863*88d15eacSSasha Smundak }, { 864*88d15eacSSasha Smundak label: "IgnoreInterfaces", 865*88d15eacSSasha Smundak x: struct{ mu *sync.Mutex }{}, 866*88d15eacSSasha Smundak y: struct{ mu *sync.Mutex }{}, 867*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreInterfaces(struct{ sync.Locker }{})}, 868*88d15eacSSasha Smundak wantEqual: true, 869*88d15eacSSasha Smundak reason: "equal because IgnoreInterfaces applies on pointers", 870*88d15eacSSasha Smundak }, { 871*88d15eacSSasha Smundak label: "IgnoreUnexported", 872*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2}, 873*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: -2}, 874*88d15eacSSasha Smundak opts: []cmp.Option{cmp.AllowUnexported(ParentStruct{})}, 875*88d15eacSSasha Smundak wantEqual: false, 876*88d15eacSSasha Smundak reason: "not equal because ParentStruct.private differs with AllowUnexported", 877*88d15eacSSasha Smundak }, { 878*88d15eacSSasha Smundak label: "IgnoreUnexported", 879*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2}, 880*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: -2}, 881*88d15eacSSasha Smundak opts: []cmp.Option{IgnoreUnexported(ParentStruct{})}, 882*88d15eacSSasha Smundak wantEqual: true, 883*88d15eacSSasha Smundak reason: "equal because IgnoreUnexported ignored ParentStruct.private", 884*88d15eacSSasha Smundak }, { 885*88d15eacSSasha Smundak label: "IgnoreUnexported", 886*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, PublicStruct: &PublicStruct{Public: 3, private: 4}}, 887*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: -2, PublicStruct: &PublicStruct{Public: 3, private: 4}}, 888*88d15eacSSasha Smundak opts: []cmp.Option{ 889*88d15eacSSasha Smundak cmp.AllowUnexported(PublicStruct{}), 890*88d15eacSSasha Smundak IgnoreUnexported(ParentStruct{}), 891*88d15eacSSasha Smundak }, 892*88d15eacSSasha Smundak wantEqual: true, 893*88d15eacSSasha Smundak reason: "equal because ParentStruct.private is ignored", 894*88d15eacSSasha Smundak }, { 895*88d15eacSSasha Smundak label: "IgnoreUnexported", 896*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, PublicStruct: &PublicStruct{Public: 3, private: 4}}, 897*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: -2, PublicStruct: &PublicStruct{Public: 3, private: -4}}, 898*88d15eacSSasha Smundak opts: []cmp.Option{ 899*88d15eacSSasha Smundak cmp.AllowUnexported(PublicStruct{}), 900*88d15eacSSasha Smundak IgnoreUnexported(ParentStruct{}), 901*88d15eacSSasha Smundak }, 902*88d15eacSSasha Smundak wantEqual: false, 903*88d15eacSSasha Smundak reason: "not equal because ParentStruct.PublicStruct.private differs and not ignored by IgnoreUnexported(ParentStruct{})", 904*88d15eacSSasha Smundak }, { 905*88d15eacSSasha Smundak label: "IgnoreUnexported", 906*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, PublicStruct: &PublicStruct{Public: 3, private: 4}}, 907*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: -2, PublicStruct: &PublicStruct{Public: 3, private: -4}}, 908*88d15eacSSasha Smundak opts: []cmp.Option{ 909*88d15eacSSasha Smundak IgnoreUnexported(ParentStruct{}, PublicStruct{}), 910*88d15eacSSasha Smundak }, 911*88d15eacSSasha Smundak wantEqual: true, 912*88d15eacSSasha Smundak reason: "equal because both ParentStruct.PublicStruct and ParentStruct.PublicStruct.private are ignored", 913*88d15eacSSasha Smundak }, { 914*88d15eacSSasha Smundak label: "IgnoreUnexported", 915*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: 3, private: 4}}, 916*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: -3, private: -4}}, 917*88d15eacSSasha Smundak opts: []cmp.Option{ 918*88d15eacSSasha Smundak cmp.AllowUnexported(privateStruct{}, PublicStruct{}, ParentStruct{}), 919*88d15eacSSasha Smundak }, 920*88d15eacSSasha Smundak wantEqual: false, 921*88d15eacSSasha Smundak reason: "not equal since ParentStruct.privateStruct differs", 922*88d15eacSSasha Smundak }, { 923*88d15eacSSasha Smundak label: "IgnoreUnexported", 924*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: 3, private: 4}}, 925*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: -3, private: -4}}, 926*88d15eacSSasha Smundak opts: []cmp.Option{ 927*88d15eacSSasha Smundak cmp.AllowUnexported(privateStruct{}, PublicStruct{}), 928*88d15eacSSasha Smundak IgnoreUnexported(ParentStruct{}), 929*88d15eacSSasha Smundak }, 930*88d15eacSSasha Smundak wantEqual: true, 931*88d15eacSSasha Smundak reason: "equal because ParentStruct.privateStruct ignored by IgnoreUnexported(ParentStruct{})", 932*88d15eacSSasha Smundak }, { 933*88d15eacSSasha Smundak label: "IgnoreUnexported", 934*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: 3, private: 4}}, 935*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: 3, private: -4}}, 936*88d15eacSSasha Smundak opts: []cmp.Option{ 937*88d15eacSSasha Smundak cmp.AllowUnexported(PublicStruct{}, ParentStruct{}), 938*88d15eacSSasha Smundak IgnoreUnexported(privateStruct{}), 939*88d15eacSSasha Smundak }, 940*88d15eacSSasha Smundak wantEqual: true, 941*88d15eacSSasha Smundak reason: "equal because privateStruct.private ignored by IgnoreUnexported(privateStruct{})", 942*88d15eacSSasha Smundak }, { 943*88d15eacSSasha Smundak label: "IgnoreUnexported", 944*88d15eacSSasha Smundak x: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: 3, private: 4}}, 945*88d15eacSSasha Smundak y: ParentStruct{Public: 1, private: 2, privateStruct: &privateStruct{Public: -3, private: -4}}, 946*88d15eacSSasha Smundak opts: []cmp.Option{ 947*88d15eacSSasha Smundak cmp.AllowUnexported(PublicStruct{}, ParentStruct{}), 948*88d15eacSSasha Smundak IgnoreUnexported(privateStruct{}), 949*88d15eacSSasha Smundak }, 950*88d15eacSSasha Smundak wantEqual: false, 951*88d15eacSSasha Smundak reason: "not equal because privateStruct.Public differs and not ignored by IgnoreUnexported(privateStruct{})", 952*88d15eacSSasha Smundak }, { 953*88d15eacSSasha Smundak label: "IgnoreFields+IgnoreTypes+IgnoreUnexported", 954*88d15eacSSasha Smundak x: &Everything{ 955*88d15eacSSasha Smundak MyInt: 5, 956*88d15eacSSasha Smundak MyFloat: 3.3, 957*88d15eacSSasha Smundak MyTime: MyTime{time.Now()}, 958*88d15eacSSasha Smundak Bar3: *createBar3X(), 959*88d15eacSSasha Smundak ParentStruct: ParentStruct{ 960*88d15eacSSasha Smundak Public: 1, private: 2, PublicStruct: &PublicStruct{Public: 3, private: 4}, 961*88d15eacSSasha Smundak }, 962*88d15eacSSasha Smundak }, 963*88d15eacSSasha Smundak y: &Everything{ 964*88d15eacSSasha Smundak MyInt: -5, 965*88d15eacSSasha Smundak MyFloat: 3.3, 966*88d15eacSSasha Smundak MyTime: MyTime{time.Now()}, 967*88d15eacSSasha Smundak Bar3: *createBar3Y(), 968*88d15eacSSasha Smundak ParentStruct: ParentStruct{ 969*88d15eacSSasha Smundak Public: 1, private: -2, PublicStruct: &PublicStruct{Public: -3, private: -4}, 970*88d15eacSSasha Smundak }, 971*88d15eacSSasha Smundak }, 972*88d15eacSSasha Smundak opts: []cmp.Option{ 973*88d15eacSSasha Smundak IgnoreFields(Everything{}, "MyTime", "Bar3.Foo3"), 974*88d15eacSSasha Smundak IgnoreFields(Bar3{}, "Bar1", "Bravo", "Delta", "Alpha"), 975*88d15eacSSasha Smundak IgnoreTypes(MyInt(0), PublicStruct{}), 976*88d15eacSSasha Smundak IgnoreUnexported(ParentStruct{}), 977*88d15eacSSasha Smundak }, 978*88d15eacSSasha Smundak wantEqual: true, 979*88d15eacSSasha Smundak reason: "equal because all Ignore options can be composed together", 980*88d15eacSSasha Smundak }, { 981*88d15eacSSasha Smundak label: "IgnoreSliceElements", 982*88d15eacSSasha Smundak x: []int{1, 0, 2, 3, 0, 4, 0, 0}, 983*88d15eacSSasha Smundak y: []int{0, 0, 0, 0, 1, 2, 3, 4}, 984*88d15eacSSasha Smundak opts: []cmp.Option{ 985*88d15eacSSasha Smundak IgnoreSliceElements(func(v int) bool { return v == 0 }), 986*88d15eacSSasha Smundak }, 987*88d15eacSSasha Smundak wantEqual: true, 988*88d15eacSSasha Smundak reason: "equal because zero elements are ignored", 989*88d15eacSSasha Smundak }, { 990*88d15eacSSasha Smundak label: "IgnoreSliceElements", 991*88d15eacSSasha Smundak x: []MyInt{1, 0, 2, 3, 0, 4, 0, 0}, 992*88d15eacSSasha Smundak y: []MyInt{0, 0, 0, 0, 1, 2, 3, 4}, 993*88d15eacSSasha Smundak opts: []cmp.Option{ 994*88d15eacSSasha Smundak IgnoreSliceElements(func(v int) bool { return v == 0 }), 995*88d15eacSSasha Smundak }, 996*88d15eacSSasha Smundak wantEqual: false, 997*88d15eacSSasha Smundak reason: "not equal because MyInt is not assignable to int", 998*88d15eacSSasha Smundak }, { 999*88d15eacSSasha Smundak label: "IgnoreSliceElements", 1000*88d15eacSSasha Smundak x: MyInts{1, 0, 2, 3, 0, 4, 0, 0}, 1001*88d15eacSSasha Smundak y: MyInts{0, 0, 0, 0, 1, 2, 3, 4}, 1002*88d15eacSSasha Smundak opts: []cmp.Option{ 1003*88d15eacSSasha Smundak IgnoreSliceElements(func(v int) bool { return v == 0 }), 1004*88d15eacSSasha Smundak }, 1005*88d15eacSSasha Smundak wantEqual: true, 1006*88d15eacSSasha Smundak reason: "equal because the element type of MyInts is assignable to int", 1007*88d15eacSSasha Smundak }, { 1008*88d15eacSSasha Smundak label: "IgnoreSliceElements+EquateEmpty", 1009*88d15eacSSasha Smundak x: []MyInt{}, 1010*88d15eacSSasha Smundak y: []MyInt{0, 0, 0, 0}, 1011*88d15eacSSasha Smundak opts: []cmp.Option{ 1012*88d15eacSSasha Smundak IgnoreSliceElements(func(v int) bool { return v == 0 }), 1013*88d15eacSSasha Smundak EquateEmpty(), 1014*88d15eacSSasha Smundak }, 1015*88d15eacSSasha Smundak wantEqual: false, 1016*88d15eacSSasha Smundak reason: "not equal because ignored elements does not imply empty slice", 1017*88d15eacSSasha Smundak }, { 1018*88d15eacSSasha Smundak label: "IgnoreMapEntries", 1019*88d15eacSSasha Smundak x: map[string]int{"one": 1, "TWO": 2, "three": 3, "FIVE": 5}, 1020*88d15eacSSasha Smundak y: map[string]int{"one": 1, "three": 3, "TEN": 10}, 1021*88d15eacSSasha Smundak opts: []cmp.Option{ 1022*88d15eacSSasha Smundak IgnoreMapEntries(func(k string, v int) bool { return strings.ToUpper(k) == k }), 1023*88d15eacSSasha Smundak }, 1024*88d15eacSSasha Smundak wantEqual: true, 1025*88d15eacSSasha Smundak reason: "equal because uppercase keys are ignored", 1026*88d15eacSSasha Smundak }, { 1027*88d15eacSSasha Smundak label: "IgnoreMapEntries", 1028*88d15eacSSasha Smundak x: map[MyString]int{"one": 1, "TWO": 2, "three": 3, "FIVE": 5}, 1029*88d15eacSSasha Smundak y: map[MyString]int{"one": 1, "three": 3, "TEN": 10}, 1030*88d15eacSSasha Smundak opts: []cmp.Option{ 1031*88d15eacSSasha Smundak IgnoreMapEntries(func(k string, v int) bool { return strings.ToUpper(k) == k }), 1032*88d15eacSSasha Smundak }, 1033*88d15eacSSasha Smundak wantEqual: false, 1034*88d15eacSSasha Smundak reason: "not equal because MyString is not assignable to string", 1035*88d15eacSSasha Smundak }, { 1036*88d15eacSSasha Smundak label: "IgnoreMapEntries", 1037*88d15eacSSasha Smundak x: map[string]MyInt{"one": 1, "TWO": 2, "three": 3, "FIVE": 5}, 1038*88d15eacSSasha Smundak y: map[string]MyInt{"one": 1, "three": 3, "TEN": 10}, 1039*88d15eacSSasha Smundak opts: []cmp.Option{ 1040*88d15eacSSasha Smundak IgnoreMapEntries(func(k string, v int) bool { return strings.ToUpper(k) == k }), 1041*88d15eacSSasha Smundak }, 1042*88d15eacSSasha Smundak wantEqual: false, 1043*88d15eacSSasha Smundak reason: "not equal because MyInt is not assignable to int", 1044*88d15eacSSasha Smundak }, { 1045*88d15eacSSasha Smundak label: "IgnoreMapEntries+EquateEmpty", 1046*88d15eacSSasha Smundak x: map[string]MyInt{"ONE": 1, "TWO": 2, "THREE": 3}, 1047*88d15eacSSasha Smundak y: nil, 1048*88d15eacSSasha Smundak opts: []cmp.Option{ 1049*88d15eacSSasha Smundak IgnoreMapEntries(func(k string, v int) bool { return strings.ToUpper(k) == k }), 1050*88d15eacSSasha Smundak EquateEmpty(), 1051*88d15eacSSasha Smundak }, 1052*88d15eacSSasha Smundak wantEqual: false, 1053*88d15eacSSasha Smundak reason: "not equal because ignored entries does not imply empty map", 1054*88d15eacSSasha Smundak }, { 1055*88d15eacSSasha Smundak label: "AcyclicTransformer", 1056*88d15eacSSasha Smundak x: "a\nb\nc\nd", 1057*88d15eacSSasha Smundak y: "a\nb\nd\nd", 1058*88d15eacSSasha Smundak opts: []cmp.Option{ 1059*88d15eacSSasha Smundak AcyclicTransformer("", func(s string) []string { return strings.Split(s, "\n") }), 1060*88d15eacSSasha Smundak }, 1061*88d15eacSSasha Smundak wantEqual: false, 1062*88d15eacSSasha Smundak reason: "not equal because 3rd line differs, but should not recurse infinitely", 1063*88d15eacSSasha Smundak }, { 1064*88d15eacSSasha Smundak label: "AcyclicTransformer", 1065*88d15eacSSasha Smundak x: []string{"foo", "Bar", "BAZ"}, 1066*88d15eacSSasha Smundak y: []string{"Foo", "BAR", "baz"}, 1067*88d15eacSSasha Smundak opts: []cmp.Option{ 1068*88d15eacSSasha Smundak AcyclicTransformer("", strings.ToUpper), 1069*88d15eacSSasha Smundak }, 1070*88d15eacSSasha Smundak wantEqual: true, 1071*88d15eacSSasha Smundak reason: "equal because of strings.ToUpper; AcyclicTransformer unnecessary, but check this still works", 1072*88d15eacSSasha Smundak }, { 1073*88d15eacSSasha Smundak label: "AcyclicTransformer", 1074*88d15eacSSasha Smundak x: "this is a sentence", 1075*88d15eacSSasha Smundak y: "this is a sentence", 1076*88d15eacSSasha Smundak opts: []cmp.Option{ 1077*88d15eacSSasha Smundak AcyclicTransformer("", strings.Fields), 1078*88d15eacSSasha Smundak }, 1079*88d15eacSSasha Smundak wantEqual: true, 1080*88d15eacSSasha Smundak reason: "equal because acyclic transformer splits on any contiguous whitespace", 1081*88d15eacSSasha Smundak }} 1082*88d15eacSSasha Smundak 1083*88d15eacSSasha Smundak for _, tt := range tests { 1084*88d15eacSSasha Smundak t.Run(tt.label, func(t *testing.T) { 1085*88d15eacSSasha Smundak var gotEqual bool 1086*88d15eacSSasha Smundak var gotPanic string 1087*88d15eacSSasha Smundak func() { 1088*88d15eacSSasha Smundak defer func() { 1089*88d15eacSSasha Smundak if ex := recover(); ex != nil { 1090*88d15eacSSasha Smundak gotPanic = fmt.Sprint(ex) 1091*88d15eacSSasha Smundak } 1092*88d15eacSSasha Smundak }() 1093*88d15eacSSasha Smundak gotEqual = cmp.Equal(tt.x, tt.y, tt.opts...) 1094*88d15eacSSasha Smundak }() 1095*88d15eacSSasha Smundak switch { 1096*88d15eacSSasha Smundak case tt.reason == "": 1097*88d15eacSSasha Smundak t.Errorf("reason must be provided") 1098*88d15eacSSasha Smundak case gotPanic == "" && tt.wantPanic: 1099*88d15eacSSasha Smundak t.Errorf("expected Equal panic\nreason: %s", tt.reason) 1100*88d15eacSSasha Smundak case gotPanic != "" && !tt.wantPanic: 1101*88d15eacSSasha Smundak t.Errorf("unexpected Equal panic: got %v\nreason: %v", gotPanic, tt.reason) 1102*88d15eacSSasha Smundak case gotEqual != tt.wantEqual: 1103*88d15eacSSasha Smundak t.Errorf("Equal = %v, want %v\nreason: %v", gotEqual, tt.wantEqual, tt.reason) 1104*88d15eacSSasha Smundak } 1105*88d15eacSSasha Smundak }) 1106*88d15eacSSasha Smundak } 1107*88d15eacSSasha Smundak} 1108*88d15eacSSasha Smundak 1109*88d15eacSSasha Smundakfunc TestPanic(t *testing.T) { 1110*88d15eacSSasha Smundak args := func(x ...interface{}) []interface{} { return x } 1111*88d15eacSSasha Smundak tests := []struct { 1112*88d15eacSSasha Smundak label string // Test name 1113*88d15eacSSasha Smundak fnc interface{} // Option function to call 1114*88d15eacSSasha Smundak args []interface{} // Arguments to pass in 1115*88d15eacSSasha Smundak wantPanic string // Expected panic message 1116*88d15eacSSasha Smundak reason string // The reason for the expected outcome 1117*88d15eacSSasha Smundak }{{ 1118*88d15eacSSasha Smundak label: "EquateApprox", 1119*88d15eacSSasha Smundak fnc: EquateApprox, 1120*88d15eacSSasha Smundak args: args(0.0, 0.0), 1121*88d15eacSSasha Smundak reason: "zero margin and fraction is equivalent to exact equality", 1122*88d15eacSSasha Smundak }, { 1123*88d15eacSSasha Smundak label: "EquateApprox", 1124*88d15eacSSasha Smundak fnc: EquateApprox, 1125*88d15eacSSasha Smundak args: args(-0.1, 0.0), 1126*88d15eacSSasha Smundak wantPanic: "margin or fraction must be a non-negative number", 1127*88d15eacSSasha Smundak reason: "negative inputs are invalid", 1128*88d15eacSSasha Smundak }, { 1129*88d15eacSSasha Smundak label: "EquateApprox", 1130*88d15eacSSasha Smundak fnc: EquateApprox, 1131*88d15eacSSasha Smundak args: args(0.0, -0.1), 1132*88d15eacSSasha Smundak wantPanic: "margin or fraction must be a non-negative number", 1133*88d15eacSSasha Smundak reason: "negative inputs are invalid", 1134*88d15eacSSasha Smundak }, { 1135*88d15eacSSasha Smundak label: "EquateApprox", 1136*88d15eacSSasha Smundak fnc: EquateApprox, 1137*88d15eacSSasha Smundak args: args(math.NaN(), 0.0), 1138*88d15eacSSasha Smundak wantPanic: "margin or fraction must be a non-negative number", 1139*88d15eacSSasha Smundak reason: "NaN inputs are invalid", 1140*88d15eacSSasha Smundak }, { 1141*88d15eacSSasha Smundak label: "EquateApprox", 1142*88d15eacSSasha Smundak fnc: EquateApprox, 1143*88d15eacSSasha Smundak args: args(1.0, 0.0), 1144*88d15eacSSasha Smundak reason: "fraction of 1.0 or greater is valid", 1145*88d15eacSSasha Smundak }, { 1146*88d15eacSSasha Smundak label: "EquateApprox", 1147*88d15eacSSasha Smundak fnc: EquateApprox, 1148*88d15eacSSasha Smundak args: args(0.0, math.Inf(+1)), 1149*88d15eacSSasha Smundak reason: "margin of infinity is valid", 1150*88d15eacSSasha Smundak }, { 1151*88d15eacSSasha Smundak label: "EquateApproxTime", 1152*88d15eacSSasha Smundak fnc: EquateApproxTime, 1153*88d15eacSSasha Smundak args: args(time.Duration(-1)), 1154*88d15eacSSasha Smundak wantPanic: "margin must be a non-negative number", 1155*88d15eacSSasha Smundak reason: "negative duration is invalid", 1156*88d15eacSSasha Smundak }, { 1157*88d15eacSSasha Smundak label: "SortSlices", 1158*88d15eacSSasha Smundak fnc: SortSlices, 1159*88d15eacSSasha Smundak args: args(strings.Compare), 1160*88d15eacSSasha Smundak wantPanic: "invalid less function", 1161*88d15eacSSasha Smundak reason: "func(x, y string) int is wrong signature for less", 1162*88d15eacSSasha Smundak }, { 1163*88d15eacSSasha Smundak label: "SortSlices", 1164*88d15eacSSasha Smundak fnc: SortSlices, 1165*88d15eacSSasha Smundak args: args((func(_, _ int) bool)(nil)), 1166*88d15eacSSasha Smundak wantPanic: "invalid less function", 1167*88d15eacSSasha Smundak reason: "nil value is not valid", 1168*88d15eacSSasha Smundak }, { 1169*88d15eacSSasha Smundak label: "SortMaps", 1170*88d15eacSSasha Smundak fnc: SortMaps, 1171*88d15eacSSasha Smundak args: args(strings.Compare), 1172*88d15eacSSasha Smundak wantPanic: "invalid less function", 1173*88d15eacSSasha Smundak reason: "func(x, y string) int is wrong signature for less", 1174*88d15eacSSasha Smundak }, { 1175*88d15eacSSasha Smundak label: "SortMaps", 1176*88d15eacSSasha Smundak fnc: SortMaps, 1177*88d15eacSSasha Smundak args: args((func(_, _ int) bool)(nil)), 1178*88d15eacSSasha Smundak wantPanic: "invalid less function", 1179*88d15eacSSasha Smundak reason: "nil value is not valid", 1180*88d15eacSSasha Smundak }, { 1181*88d15eacSSasha Smundak label: "IgnoreFields", 1182*88d15eacSSasha Smundak fnc: IgnoreFields, 1183*88d15eacSSasha Smundak args: args(Foo1{}, ""), 1184*88d15eacSSasha Smundak wantPanic: "name must not be empty", 1185*88d15eacSSasha Smundak reason: "empty selector is invalid", 1186*88d15eacSSasha Smundak }, { 1187*88d15eacSSasha Smundak label: "IgnoreFields", 1188*88d15eacSSasha Smundak fnc: IgnoreFields, 1189*88d15eacSSasha Smundak args: args(Foo1{}, "."), 1190*88d15eacSSasha Smundak wantPanic: "name must not be empty", 1191*88d15eacSSasha Smundak reason: "single dot selector is invalid", 1192*88d15eacSSasha Smundak }, { 1193*88d15eacSSasha Smundak label: "IgnoreFields", 1194*88d15eacSSasha Smundak fnc: IgnoreFields, 1195*88d15eacSSasha Smundak args: args(Foo1{}, ".Alpha"), 1196*88d15eacSSasha Smundak reason: "dot-prefix is okay since Foo1.Alpha reads naturally", 1197*88d15eacSSasha Smundak }, { 1198*88d15eacSSasha Smundak label: "IgnoreFields", 1199*88d15eacSSasha Smundak fnc: IgnoreFields, 1200*88d15eacSSasha Smundak args: args(Foo1{}, "Alpha."), 1201*88d15eacSSasha Smundak wantPanic: "name must not be empty", 1202*88d15eacSSasha Smundak reason: "dot-suffix is invalid", 1203*88d15eacSSasha Smundak }, { 1204*88d15eacSSasha Smundak label: "IgnoreFields", 1205*88d15eacSSasha Smundak fnc: IgnoreFields, 1206*88d15eacSSasha Smundak args: args(Foo1{}, "Alpha "), 1207*88d15eacSSasha Smundak wantPanic: "does not exist", 1208*88d15eacSSasha Smundak reason: "identifiers must not have spaces", 1209*88d15eacSSasha Smundak }, { 1210*88d15eacSSasha Smundak label: "IgnoreFields", 1211*88d15eacSSasha Smundak fnc: IgnoreFields, 1212*88d15eacSSasha Smundak args: args(Foo1{}, "Zulu"), 1213*88d15eacSSasha Smundak wantPanic: "does not exist", 1214*88d15eacSSasha Smundak reason: "name of non-existent field is invalid", 1215*88d15eacSSasha Smundak }, { 1216*88d15eacSSasha Smundak label: "IgnoreFields", 1217*88d15eacSSasha Smundak fnc: IgnoreFields, 1218*88d15eacSSasha Smundak args: args(Foo1{}, "Alpha.NoExist"), 1219*88d15eacSSasha Smundak wantPanic: "must be a struct", 1220*88d15eacSSasha Smundak reason: "cannot select into a non-struct", 1221*88d15eacSSasha Smundak }, { 1222*88d15eacSSasha Smundak label: "IgnoreFields", 1223*88d15eacSSasha Smundak fnc: IgnoreFields, 1224*88d15eacSSasha Smundak args: args(&Foo1{}, "Alpha"), 1225*88d15eacSSasha Smundak wantPanic: "must be a non-pointer struct", 1226*88d15eacSSasha Smundak reason: "the type must be a struct (not pointer to a struct)", 1227*88d15eacSSasha Smundak }, { 1228*88d15eacSSasha Smundak label: "IgnoreFields", 1229*88d15eacSSasha Smundak fnc: IgnoreFields, 1230*88d15eacSSasha Smundak args: args(struct{ privateStruct }{}, "privateStruct"), 1231*88d15eacSSasha Smundak reason: "privateStruct field permitted since it is the default name of the embedded type", 1232*88d15eacSSasha Smundak }, { 1233*88d15eacSSasha Smundak label: "IgnoreFields", 1234*88d15eacSSasha Smundak fnc: IgnoreFields, 1235*88d15eacSSasha Smundak args: args(struct{ privateStruct }{}, "Public"), 1236*88d15eacSSasha Smundak reason: "Public field permitted since it is a forwarded field that is exported", 1237*88d15eacSSasha Smundak }, { 1238*88d15eacSSasha Smundak label: "IgnoreFields", 1239*88d15eacSSasha Smundak fnc: IgnoreFields, 1240*88d15eacSSasha Smundak args: args(struct{ privateStruct }{}, "private"), 1241*88d15eacSSasha Smundak wantPanic: "does not exist", 1242*88d15eacSSasha Smundak reason: "private field not permitted since it is a forwarded field that is unexported", 1243*88d15eacSSasha Smundak }, { 1244*88d15eacSSasha Smundak label: "IgnoreTypes", 1245*88d15eacSSasha Smundak fnc: IgnoreTypes, 1246*88d15eacSSasha Smundak reason: "empty input is valid", 1247*88d15eacSSasha Smundak }, { 1248*88d15eacSSasha Smundak label: "IgnoreTypes", 1249*88d15eacSSasha Smundak fnc: IgnoreTypes, 1250*88d15eacSSasha Smundak args: args(nil), 1251*88d15eacSSasha Smundak wantPanic: "cannot determine type", 1252*88d15eacSSasha Smundak reason: "input must not be nil value", 1253*88d15eacSSasha Smundak }, { 1254*88d15eacSSasha Smundak label: "IgnoreTypes", 1255*88d15eacSSasha Smundak fnc: IgnoreTypes, 1256*88d15eacSSasha Smundak args: args(0, 0, 0), 1257*88d15eacSSasha Smundak reason: "duplicate inputs of the same type is valid", 1258*88d15eacSSasha Smundak }, { 1259*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1260*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1261*88d15eacSSasha Smundak args: args(nil), 1262*88d15eacSSasha Smundak wantPanic: "input must be an anonymous struct", 1263*88d15eacSSasha Smundak reason: "input must not be nil value", 1264*88d15eacSSasha Smundak }, { 1265*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1266*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1267*88d15eacSSasha Smundak args: args(Foo1{}), 1268*88d15eacSSasha Smundak wantPanic: "input must be an anonymous struct", 1269*88d15eacSSasha Smundak reason: "input must not be a named struct type", 1270*88d15eacSSasha Smundak }, { 1271*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1272*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1273*88d15eacSSasha Smundak args: args(struct{ _ io.Reader }{}), 1274*88d15eacSSasha Smundak wantPanic: "struct cannot have named fields", 1275*88d15eacSSasha Smundak reason: "input must not have named fields", 1276*88d15eacSSasha Smundak }, { 1277*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1278*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1279*88d15eacSSasha Smundak args: args(struct{ Foo1 }{}), 1280*88d15eacSSasha Smundak wantPanic: "embedded field must be an interface type", 1281*88d15eacSSasha Smundak reason: "field types must be interfaces", 1282*88d15eacSSasha Smundak }, { 1283*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1284*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1285*88d15eacSSasha Smundak args: args(struct{ EmptyInterface }{}), 1286*88d15eacSSasha Smundak wantPanic: "cannot ignore empty interface", 1287*88d15eacSSasha Smundak reason: "field types must not be the empty interface", 1288*88d15eacSSasha Smundak }, { 1289*88d15eacSSasha Smundak label: "IgnoreInterfaces", 1290*88d15eacSSasha Smundak fnc: IgnoreInterfaces, 1291*88d15eacSSasha Smundak args: args(struct { 1292*88d15eacSSasha Smundak io.Reader 1293*88d15eacSSasha Smundak io.Writer 1294*88d15eacSSasha Smundak io.Closer 1295*88d15eacSSasha Smundak io.ReadWriteCloser 1296*88d15eacSSasha Smundak }{}), 1297*88d15eacSSasha Smundak reason: "multiple interfaces may be specified, even if they overlap", 1298*88d15eacSSasha Smundak }, { 1299*88d15eacSSasha Smundak label: "IgnoreUnexported", 1300*88d15eacSSasha Smundak fnc: IgnoreUnexported, 1301*88d15eacSSasha Smundak reason: "empty input is valid", 1302*88d15eacSSasha Smundak }, { 1303*88d15eacSSasha Smundak label: "IgnoreUnexported", 1304*88d15eacSSasha Smundak fnc: IgnoreUnexported, 1305*88d15eacSSasha Smundak args: args(nil), 1306*88d15eacSSasha Smundak wantPanic: "must be a non-pointer struct", 1307*88d15eacSSasha Smundak reason: "input must not be nil value", 1308*88d15eacSSasha Smundak }, { 1309*88d15eacSSasha Smundak label: "IgnoreUnexported", 1310*88d15eacSSasha Smundak fnc: IgnoreUnexported, 1311*88d15eacSSasha Smundak args: args(&Foo1{}), 1312*88d15eacSSasha Smundak wantPanic: "must be a non-pointer struct", 1313*88d15eacSSasha Smundak reason: "input must be a struct type (not a pointer to a struct)", 1314*88d15eacSSasha Smundak }, { 1315*88d15eacSSasha Smundak label: "IgnoreUnexported", 1316*88d15eacSSasha Smundak fnc: IgnoreUnexported, 1317*88d15eacSSasha Smundak args: args(Foo1{}, struct{ x, X int }{}), 1318*88d15eacSSasha Smundak reason: "input may be named or unnamed structs", 1319*88d15eacSSasha Smundak }, { 1320*88d15eacSSasha Smundak label: "AcyclicTransformer", 1321*88d15eacSSasha Smundak fnc: AcyclicTransformer, 1322*88d15eacSSasha Smundak args: args("", "not a func"), 1323*88d15eacSSasha Smundak wantPanic: "invalid transformer function", 1324*88d15eacSSasha Smundak reason: "AcyclicTransformer has same input requirements as Transformer", 1325*88d15eacSSasha Smundak }} 1326*88d15eacSSasha Smundak 1327*88d15eacSSasha Smundak for _, tt := range tests { 1328*88d15eacSSasha Smundak t.Run(tt.label, func(t *testing.T) { 1329*88d15eacSSasha Smundak // Prepare function arguments. 1330*88d15eacSSasha Smundak vf := reflect.ValueOf(tt.fnc) 1331*88d15eacSSasha Smundak var vargs []reflect.Value 1332*88d15eacSSasha Smundak for i, arg := range tt.args { 1333*88d15eacSSasha Smundak if arg == nil { 1334*88d15eacSSasha Smundak tf := vf.Type() 1335*88d15eacSSasha Smundak if i == tf.NumIn()-1 && tf.IsVariadic() { 1336*88d15eacSSasha Smundak vargs = append(vargs, reflect.Zero(tf.In(i).Elem())) 1337*88d15eacSSasha Smundak } else { 1338*88d15eacSSasha Smundak vargs = append(vargs, reflect.Zero(tf.In(i))) 1339*88d15eacSSasha Smundak } 1340*88d15eacSSasha Smundak } else { 1341*88d15eacSSasha Smundak vargs = append(vargs, reflect.ValueOf(arg)) 1342*88d15eacSSasha Smundak } 1343*88d15eacSSasha Smundak } 1344*88d15eacSSasha Smundak 1345*88d15eacSSasha Smundak // Call the function and capture any panics. 1346*88d15eacSSasha Smundak var gotPanic string 1347*88d15eacSSasha Smundak func() { 1348*88d15eacSSasha Smundak defer func() { 1349*88d15eacSSasha Smundak if ex := recover(); ex != nil { 1350*88d15eacSSasha Smundak if s, ok := ex.(string); ok { 1351*88d15eacSSasha Smundak gotPanic = s 1352*88d15eacSSasha Smundak } else { 1353*88d15eacSSasha Smundak panic(ex) 1354*88d15eacSSasha Smundak } 1355*88d15eacSSasha Smundak } 1356*88d15eacSSasha Smundak }() 1357*88d15eacSSasha Smundak vf.Call(vargs) 1358*88d15eacSSasha Smundak }() 1359*88d15eacSSasha Smundak 1360*88d15eacSSasha Smundak switch { 1361*88d15eacSSasha Smundak case tt.reason == "": 1362*88d15eacSSasha Smundak t.Errorf("reason must be provided") 1363*88d15eacSSasha Smundak case tt.wantPanic == "" && gotPanic != "": 1364*88d15eacSSasha Smundak t.Errorf("unexpected panic message: %s\nreason: %s", gotPanic, tt.reason) 1365*88d15eacSSasha Smundak case tt.wantPanic != "" && !strings.Contains(gotPanic, tt.wantPanic): 1366*88d15eacSSasha Smundak t.Errorf("panic message:\ngot: %s\nwant: %s\nreason: %s", gotPanic, tt.wantPanic, tt.reason) 1367*88d15eacSSasha Smundak } 1368*88d15eacSSasha Smundak }) 1369*88d15eacSSasha Smundak } 1370*88d15eacSSasha Smundak} 1371