Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 5 | package reflectutil |
| 6 | |
| 7 | import ( |
| 8 | "reflect" |
| 9 | "testing" |
| 10 | "unsafe" |
| 11 | ) |
| 12 | |
| 13 | type ( |
| 14 | Struct struct { |
| 15 | A uint |
| 16 | B string |
| 17 | } |
| 18 | |
| 19 | Recurse struct { |
| 20 | U uint |
| 21 | R *Recurse |
| 22 | } |
| 23 | |
| 24 | RecurseA struct { |
| 25 | Ua uint |
| 26 | B *RecurseB |
| 27 | } |
| 28 | RecurseB struct { |
| 29 | Ub uint |
| 30 | A *RecurseA |
| 31 | } |
| 32 | |
| 33 | abIntPtr struct { |
| 34 | A, B *int |
| 35 | } |
| 36 | ) |
| 37 | |
| 38 | var ( |
| 39 | recurseCycle *Recurse = &Recurse{} |
| 40 | recurseABCycle *RecurseA = &RecurseA{} |
| 41 | |
| 42 | intPtr1a *int = new(int) |
| 43 | intPtr1b *int = new(int) |
| 44 | |
| 45 | iface interface{} |
| 46 | ) |
| 47 | |
| 48 | func init() { |
| 49 | recurseCycle.U = 5 |
| 50 | recurseCycle.R = recurseCycle |
| 51 | |
| 52 | recurseABCycle.Ua = 5 |
| 53 | recurseABCycle.B = &RecurseB{6, recurseABCycle} |
| 54 | |
| 55 | *intPtr1a = 1 |
| 56 | *intPtr1b = 1 |
| 57 | } |
| 58 | |
Benjamin Prosnitz | 235346e | 2015-02-13 10:55:55 -0800 | [diff] [blame] | 59 | func TestDeepEqual(t *testing.T) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 60 | tests := []struct { |
| 61 | a, b interface{} |
| 62 | expect bool |
| 63 | }{ |
| 64 | {true, true, true}, |
| 65 | {1, 1, true}, |
| 66 | {-1, -1, true}, |
| 67 | {1.1, 1.1, true}, |
| 68 | {"abc", "abc", true}, |
| 69 | {1 + 1i, 1 + 1i, true}, |
| 70 | {[2]uint{1, 1}, [2]uint{1, 1}, true}, |
| 71 | {[]uint{1, 1}, []uint{1, 1}, true}, |
| 72 | {map[uint]string{1: "1", 2: "2"}, map[uint]string{1: "1", 2: "2"}, true}, |
| 73 | {Struct{1, "a"}, Struct{1, "a"}, true}, |
| 74 | {recurseCycle, recurseCycle, true}, |
| 75 | {recurseABCycle, recurseABCycle, true}, |
| 76 | {abIntPtr{intPtr1a, intPtr1a}, abIntPtr{intPtr1a, intPtr1a}, true}, |
| 77 | {abIntPtr{intPtr1a, intPtr1b}, abIntPtr{intPtr1a, intPtr1b}, true}, |
| 78 | |
| 79 | {true, false, false}, |
| 80 | {1, 2, false}, |
| 81 | {-1, -2, false}, |
| 82 | {1.1, 2.2, false}, |
| 83 | {"abc", "def", false}, |
| 84 | {1 + 1i, 2 + 2i, false}, |
| 85 | {[2]uint{1, 1}, [2]uint{2, 2}, false}, |
| 86 | {[]uint{1, 1}, []uint{2, 2}, false}, |
| 87 | {map[uint]string{1: "1", 2: "2"}, map[uint]string{3: "3", 4: "4"}, false}, |
| 88 | {Struct{1, "a"}, Struct{1, "b"}, false}, |
| 89 | {recurseCycle, &Recurse{5, &Recurse{5, nil}}, false}, |
| 90 | {recurseABCycle, &RecurseA{5, &RecurseB{6, nil}}, false}, |
| 91 | {abIntPtr{intPtr1a, intPtr1a}, abIntPtr{intPtr1a, intPtr1b}, false}, |
| 92 | {abIntPtr{intPtr1a, intPtr1b}, abIntPtr{intPtr1a, intPtr1a}, false}, |
| 93 | } |
| 94 | for _, test := range tests { |
Benjamin Prosnitz | 235346e | 2015-02-13 10:55:55 -0800 | [diff] [blame] | 95 | actual := DeepEqual(test.a, test.b, &DeepEqualOpts{}) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 96 | if actual != test.expect { |
Benjamin Prosnitz | 235346e | 2015-02-13 10:55:55 -0800 | [diff] [blame] | 97 | t.Errorf("DeepEqual(%#v, %#v) != %v", test.a, test.b, test.expect) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | func TestAreComparable(t *testing.T) { |
| 103 | tests := []struct { |
| 104 | a, b interface{} |
| 105 | expect bool |
| 106 | }{ |
| 107 | {true, true, true}, |
| 108 | {"", "", true}, |
| 109 | {uint(0), uint(0), true}, |
| 110 | {uint8(0), uint8(0), true}, |
| 111 | {uint16(0), uint16(0), true}, |
| 112 | {uint32(0), uint32(0), true}, |
| 113 | {uint64(0), uint64(0), true}, |
| 114 | {uintptr(0), uintptr(0), true}, |
| 115 | {int(0), int(0), true}, |
| 116 | {int8(0), int8(0), true}, |
| 117 | {int16(0), int16(0), true}, |
| 118 | {int32(0), int32(0), true}, |
| 119 | {int64(0), int64(0), true}, |
| 120 | {float32(0), float32(0), true}, |
| 121 | {float64(0), float64(0), true}, |
| 122 | {complex64(0), complex64(0), true}, |
| 123 | {complex128(0), complex128(0), true}, |
| 124 | {[2]uint{1, 1}, [2]uint{1, 1}, true}, |
| 125 | {[]uint{1, 1}, []uint{1, 1}, true}, |
| 126 | {Struct{1, "a"}, Struct{1, "a"}, true}, |
| 127 | {(*int)(nil), (*int)(nil), true}, |
| 128 | {recurseCycle, recurseCycle, true}, |
| 129 | {recurseABCycle, recurseABCycle, true}, |
| 130 | {abIntPtr{intPtr1a, intPtr1a}, abIntPtr{intPtr1a, intPtr1a}, true}, |
| 131 | {abIntPtr{intPtr1a, intPtr1b}, abIntPtr{intPtr1a, intPtr1b}, true}, |
| 132 | |
| 133 | {map[uint]string{1: "1"}, map[uint]string{1: "1"}, false}, |
| 134 | {&iface, &iface, false}, |
| 135 | {make(chan int), make(chan int), false}, |
| 136 | {TestAreComparable, TestAreComparable, false}, |
| 137 | {unsafe.Pointer(nil), unsafe.Pointer(nil), false}, |
| 138 | } |
| 139 | for _, test := range tests { |
| 140 | actual := AreComparable(test.a, test.b) |
| 141 | if actual != test.expect { |
| 142 | t.Errorf("AreComparable(%#v, %#v) != %v", test.a, test.b, test.expect) |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | func TestLess(t *testing.T) { |
| 148 | for _, test := range compareTests { |
| 149 | actual := Less(test.a, test.b) |
| 150 | expect := false |
| 151 | if test.expect == -1 { |
| 152 | expect = true // For eq and gt we expect Less to return false. |
| 153 | } |
| 154 | if actual != expect { |
| 155 | t.Errorf("Less(%#v, %#v) != %v", test.a, test.b, expect) |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | func TestCompare(t *testing.T) { |
| 161 | for _, test := range compareTests { |
| 162 | actual := Compare(test.a, test.b) |
| 163 | if actual != test.expect { |
| 164 | t.Errorf("Compare(%#v, %#v) != %v", test.a, test.b, test.expect) |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | var compareTests = []struct { |
| 170 | a, b interface{} |
| 171 | expect int |
| 172 | }{ |
| 173 | {false, true, -1}, |
| 174 | {false, false, 0}, |
| 175 | {true, false, +1}, |
| 176 | {true, true, 0}, |
| 177 | |
| 178 | {"", "aa", -1}, |
| 179 | {"a", "aa", -1}, |
| 180 | {"aa", "ab", -1}, |
| 181 | {"aa", "b", -1}, |
| 182 | {"", "", 0}, |
| 183 | {"aa", "", +1}, |
| 184 | {"aa", "a", +1}, |
| 185 | {"ab", "aa", +1}, |
| 186 | {"b", "aa", +1}, |
| 187 | |
| 188 | {uint(0), uint(1), -1}, |
| 189 | {uint(0), uint(0), 0}, |
| 190 | {uint(1), uint(0), +1}, |
| 191 | {uint(1), uint(1), 0}, |
| 192 | |
| 193 | {int(-1), int(+1), -1}, |
| 194 | {int(-1), int(-1), 0}, |
| 195 | {int(+1), int(-1), +1}, |
| 196 | {int(+1), int(+1), 0}, |
| 197 | |
| 198 | {float32(-1.1), float32(+1.1), -1}, |
| 199 | {float32(-1.1), float32(-1.1), 0}, |
| 200 | {float32(+1.1), float32(-1.1), +1}, |
| 201 | {float32(+1.1), float32(+1.1), 0}, |
| 202 | |
| 203 | {complex64(1 + 1i), complex64(1 + 2i), -1}, |
| 204 | {complex64(1 + 2i), complex64(2 + 1i), -1}, |
| 205 | {complex64(1 + 2i), complex64(2 + 2i), -1}, |
| 206 | {complex64(1 + 2i), complex64(2 + 3i), -1}, |
| 207 | {complex64(1 + 1i), complex64(1 + 1i), 0}, |
| 208 | {complex64(1 + 2i), complex64(1 + 1i), +1}, |
| 209 | {complex64(2 + 1i), complex64(1 + 2i), +1}, |
| 210 | {complex64(2 + 2i), complex64(1 + 2i), +1}, |
| 211 | {complex64(2 + 3i), complex64(1 + 2i), +1}, |
| 212 | |
| 213 | {[2]int{1, 1}, [2]int{1, 2}, -1}, |
| 214 | {[2]int{1, 2}, [2]int{2, 1}, -1}, |
| 215 | {[2]int{1, 2}, [2]int{2, 2}, -1}, |
| 216 | {[2]int{1, 2}, [2]int{2, 3}, -1}, |
| 217 | {[2]int{1, 1}, [2]int{1, 1}, 0}, |
| 218 | {[2]int{1, 2}, [2]int{1, 1}, +1}, |
| 219 | {[2]int{2, 1}, [2]int{1, 2}, +1}, |
| 220 | {[2]int{2, 2}, [2]int{1, 2}, +1}, |
| 221 | {[2]int{2, 3}, [2]int{1, 2}, +1}, |
| 222 | |
| 223 | {[]int{}, []int{1, 1}, -1}, |
| 224 | {[]int{1}, []int{1, 1}, -1}, |
| 225 | {[]int{1, 1}, []int{}, +1}, |
| 226 | {[]int{1, 1}, []int{1}, +1}, |
| 227 | {[]int{1, 1}, []int{1, 2}, -1}, |
| 228 | {[]int{1, 2}, []int{2, 1}, -1}, |
| 229 | {[]int{1, 2}, []int{2, 2}, -1}, |
| 230 | {[]int{1, 2}, []int{2, 3}, -1}, |
| 231 | {[]int{1, 1}, []int{1, 1}, 0}, |
| 232 | {[]int{1, 2}, []int{1, 1}, +1}, |
| 233 | {[]int{2, 1}, []int{1, 2}, +1}, |
| 234 | {[]int{2, 2}, []int{1, 2}, +1}, |
| 235 | {[]int{2, 3}, []int{1, 2}, +1}, |
| 236 | |
| 237 | {Struct{1, "a"}, Struct{1, "b"}, -1}, |
| 238 | {Struct{1, "b"}, Struct{2, "a"}, -1}, |
| 239 | {Struct{1, "b"}, Struct{2, "b"}, -1}, |
| 240 | {Struct{1, "b"}, Struct{2, "c"}, -1}, |
| 241 | {Struct{1, "a"}, Struct{1, "a"}, 0}, |
| 242 | {Struct{1, "b"}, Struct{1, "a"}, +1}, |
| 243 | {Struct{2, "a"}, Struct{1, "b"}, +1}, |
| 244 | {Struct{2, "b"}, Struct{1, "b"}, +1}, |
| 245 | {Struct{2, "c"}, Struct{1, "b"}, +1}, |
| 246 | |
| 247 | {(*Struct)(nil), &Struct{1, "a"}, -1}, |
| 248 | {&Struct{1, "a"}, &Struct{1, "b"}, -1}, |
| 249 | {&Struct{1, "b"}, &Struct{2, "a"}, -1}, |
| 250 | {&Struct{1, "b"}, &Struct{2, "b"}, -1}, |
| 251 | {&Struct{1, "b"}, &Struct{2, "c"}, -1}, |
| 252 | {(*Struct)(nil), (*Struct)(nil), 0}, |
| 253 | {&Struct{1, "a"}, (*Struct)(nil), +1}, |
| 254 | {&Struct{1, "a"}, &Struct{1, "a"}, 0}, |
| 255 | {&Struct{1, "b"}, &Struct{1, "a"}, +1}, |
| 256 | {&Struct{2, "a"}, &Struct{1, "b"}, +1}, |
| 257 | {&Struct{2, "b"}, &Struct{1, "b"}, +1}, |
| 258 | {&Struct{2, "c"}, &Struct{1, "b"}, +1}, |
| 259 | } |
| 260 | |
| 261 | type v []interface{} |
| 262 | |
| 263 | func toRVS(values v) (rvs []reflect.Value) { |
| 264 | for _, val := range values { |
| 265 | rvs = append(rvs, reflect.ValueOf(val)) |
| 266 | } |
| 267 | return |
| 268 | } |
| 269 | |
| 270 | func fromRVS(rvs []reflect.Value) (values v) { |
| 271 | for _, rv := range rvs { |
| 272 | values = append(values, rv.Interface()) |
| 273 | } |
| 274 | return |
| 275 | } |
| 276 | |
| 277 | func TestTrySortValues(t *testing.T) { |
| 278 | tests := []struct { |
| 279 | values v |
| 280 | expect v |
| 281 | }{ |
| 282 | { |
| 283 | v{true, false}, |
| 284 | v{false, true}, |
| 285 | }, |
| 286 | { |
| 287 | v{"c", "b", "a"}, |
| 288 | v{"a", "b", "c"}, |
| 289 | }, |
| 290 | { |
| 291 | v{3, 1, 2}, |
| 292 | v{1, 2, 3}, |
| 293 | }, |
| 294 | { |
| 295 | v{3.3, 1.1, 2.2}, |
| 296 | v{1.1, 2.2, 3.3}, |
| 297 | }, |
| 298 | { |
| 299 | v{3 + 3i, 1 + 1i, 2 + 2i}, |
| 300 | v{1 + 1i, 2 + 2i, 3 + 3i}, |
| 301 | }, |
| 302 | { |
| 303 | v{[1]int{3}, [1]int{1}, [1]int{2}}, |
| 304 | v{[1]int{1}, [1]int{2}, [1]int{3}}, |
| 305 | }, |
| 306 | { |
| 307 | v{[]int{3}, []int{}, []int{2, 2}}, |
| 308 | v{[]int{}, []int{2, 2}, []int{3}}, |
| 309 | }, |
| 310 | { |
| 311 | v{Struct{3, "c"}, Struct{1, "a"}, Struct{2, "b"}}, |
| 312 | v{Struct{1, "a"}, Struct{2, "b"}, Struct{3, "c"}}, |
| 313 | }, |
| 314 | { |
| 315 | v{&Struct{3, "c"}, (*Struct)(nil), &Struct{2, "b"}}, |
| 316 | v{(*Struct)(nil), &Struct{2, "b"}, &Struct{3, "c"}}, |
| 317 | }, |
| 318 | } |
| 319 | for _, test := range tests { |
| 320 | actual := fromRVS(TrySortValues(toRVS(test.values))) |
| 321 | if !reflect.DeepEqual(actual, test.expect) { |
| 322 | t.Errorf("TrySortValues(%v) got %v, want %v", test.values, actual, test.expect) |
| 323 | } |
| 324 | } |
| 325 | } |
Benjamin Prosnitz | 235346e | 2015-02-13 10:55:55 -0800 | [diff] [blame] | 326 | |
| 327 | func TestOptionSliceEqNilEmpty(t *testing.T) { |
| 328 | tests := []struct { |
| 329 | first interface{} |
| 330 | second interface{} |
| 331 | resultWithoutOption bool |
| 332 | resultWithOption bool |
| 333 | }{ |
| 334 | { |
| 335 | []int{}, []int{}, true, true, |
| 336 | }, |
| 337 | { |
| 338 | []int(nil), []int(nil), true, true, |
| 339 | }, |
| 340 | { |
| 341 | []int{}, []int(nil), false, true, |
| 342 | }, |
| 343 | { |
| 344 | []([]int){([]int)(nil)}, []([]int){[]int{}}, false, true, |
| 345 | }, |
| 346 | } |
| 347 | |
| 348 | for _, nilEqOpt := range []bool{true, false} { |
| 349 | for _, test := range tests { |
| 350 | options := &DeepEqualOpts{ |
| 351 | SliceEqNilEmpty: nilEqOpt, |
| 352 | } |
| 353 | |
| 354 | result := DeepEqual(test.first, test.second, options) |
| 355 | |
| 356 | if nilEqOpt { |
| 357 | if result != test.resultWithOption { |
| 358 | t.Errorf("Unexpected result with SliceEqNilEmpty option: inputs %#v and %#v. Got %v, expected: %v", test.first, test.second, result, test.resultWithOption) |
| 359 | } |
| 360 | } else { |
| 361 | if result != test.resultWithoutOption { |
| 362 | t.Errorf("Unexpected result without SliceEqNilEmpty option: inputs %#v and %#v. Got %v, expected: %v", test.first, test.second, result, test.resultWithoutOption) |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | } |