1// Copyright 2017, The Go 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 5package value_test 6 7import ( 8 "math" 9 "reflect" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 "github.com/google/go-cmp/cmp/internal/value" 14) 15 16func TestSortKeys(t *testing.T) { 17 type ( 18 MyString string 19 MyArray [2]int 20 MyStruct struct { 21 A MyString 22 B MyArray 23 C chan float64 24 } 25 EmptyStruct struct{} 26 ) 27 28 opts := []cmp.Option{ 29 cmp.Comparer(func(x, y float64) bool { 30 if math.IsNaN(x) && math.IsNaN(y) { 31 return true 32 } 33 return x == y 34 }), 35 cmp.Comparer(func(x, y complex128) bool { 36 rx, ix, ry, iy := real(x), imag(x), real(y), imag(y) 37 if math.IsNaN(rx) && math.IsNaN(ry) { 38 rx, ry = 0, 0 39 } 40 if math.IsNaN(ix) && math.IsNaN(iy) { 41 ix, iy = 0, 0 42 } 43 return rx == ry && ix == iy 44 }), 45 cmp.Comparer(func(x, y chan bool) bool { return true }), 46 cmp.Comparer(func(x, y chan int) bool { return true }), 47 cmp.Comparer(func(x, y chan float64) bool { return true }), 48 cmp.Comparer(func(x, y chan interface{}) bool { return true }), 49 cmp.Comparer(func(x, y *int) bool { return true }), 50 } 51 52 tests := []struct { 53 in map[interface{}]bool // Set of keys to sort 54 want []interface{} 55 }{{ 56 in: map[interface{}]bool{1: true, 2: true, 3: true}, 57 want: []interface{}{1, 2, 3}, 58 }, { 59 in: map[interface{}]bool{ 60 nil: true, 61 true: true, 62 false: true, 63 -5: true, 64 -55: true, 65 -555: true, 66 uint(1): true, 67 uint(11): true, 68 uint(111): true, 69 "abc": true, 70 "abcd": true, 71 "abcde": true, 72 "foo": true, 73 "bar": true, 74 MyString("abc"): true, 75 MyString("abcd"): true, 76 MyString("abcde"): true, 77 new(int): true, 78 new(int): true, 79 make(chan bool): true, 80 make(chan bool): true, 81 make(chan int): true, 82 make(chan interface{}): true, 83 math.Inf(+1): true, 84 math.Inf(-1): true, 85 1.2345: true, 86 12.345: true, 87 123.45: true, 88 1234.5: true, 89 0 + 0i: true, 90 1 + 0i: true, 91 2 + 0i: true, 92 0 + 1i: true, 93 0 + 2i: true, 94 0 + 3i: true, 95 [2]int{2, 3}: true, 96 [2]int{4, 0}: true, 97 [2]int{2, 4}: true, 98 MyArray([2]int{2, 4}): true, 99 EmptyStruct{}: true, 100 MyStruct{ 101 "bravo", [2]int{2, 3}, make(chan float64), 102 }: true, 103 MyStruct{ 104 "alpha", [2]int{3, 3}, make(chan float64), 105 }: true, 106 }, 107 want: []interface{}{ 108 nil, false, true, 109 -555, -55, -5, uint(1), uint(11), uint(111), 110 math.Inf(-1), 1.2345, 12.345, 123.45, 1234.5, math.Inf(+1), 111 (0 + 0i), (0 + 1i), (0 + 2i), (0 + 3i), (1 + 0i), (2 + 0i), 112 [2]int{2, 3}, [2]int{2, 4}, [2]int{4, 0}, MyArray([2]int{2, 4}), 113 make(chan bool), make(chan bool), make(chan int), make(chan interface{}), 114 new(int), new(int), 115 "abc", "abcd", "abcde", "bar", "foo", 116 MyString("abc"), MyString("abcd"), MyString("abcde"), 117 EmptyStruct{}, 118 MyStruct{"alpha", [2]int{3, 3}, make(chan float64)}, 119 MyStruct{"bravo", [2]int{2, 3}, make(chan float64)}, 120 }, 121 }, { 122 // NaN values cannot be properly deduplicated. 123 // This is okay since map entries with NaN in the keys cannot be 124 // retrieved anyways. 125 in: map[interface{}]bool{ 126 math.NaN(): true, 127 math.NaN(): true, 128 complex(0, math.NaN()): true, 129 complex(0, math.NaN()): true, 130 complex(math.NaN(), 0): true, 131 complex(math.NaN(), 0): true, 132 complex(math.NaN(), math.NaN()): true, 133 }, 134 want: []interface{}{ 135 math.NaN(), 136 complex(math.NaN(), math.NaN()), 137 complex(math.NaN(), 0), 138 complex(0, math.NaN()), 139 }, 140 }} 141 142 for i, tt := range tests { 143 // Intentionally pass the map via an unexported field to detect panics. 144 // Unfortunately, we cannot actually test the keys without using unsafe. 145 v := reflect.ValueOf(struct{ x map[interface{}]bool }{tt.in}).Field(0) 146 value.SortKeys(append(v.MapKeys(), v.MapKeys()...)) 147 148 // Try again, with keys that have read-write access in reflect. 149 v = reflect.ValueOf(tt.in) 150 keys := append(v.MapKeys(), v.MapKeys()...) 151 var got []interface{} 152 for _, k := range value.SortKeys(keys) { 153 got = append(got, k.Interface()) 154 } 155 if d := cmp.Diff(got, tt.want, opts...); d != "" { 156 t.Errorf("test %d, Sort() mismatch (-got +want):\n%s", i, d) 157 } 158 } 159} 160