1
2
3
4
5 package fmtsort_test
6
7 import (
8 "fmt"
9 "math"
10 "reflect"
11 "strings"
12 "testing"
13
14 "github.com/rogpeppe/go-internal/fmtsort"
15 )
16
17 var compareTests = [][]reflect.Value{
18 ct(reflect.TypeOf(int(0)), -1, 0, 1),
19 ct(reflect.TypeOf(int8(0)), -1, 0, 1),
20 ct(reflect.TypeOf(int16(0)), -1, 0, 1),
21 ct(reflect.TypeOf(int32(0)), -1, 0, 1),
22 ct(reflect.TypeOf(int64(0)), -1, 0, 1),
23 ct(reflect.TypeOf(uint(0)), 0, 1, 5),
24 ct(reflect.TypeOf(uint8(0)), 0, 1, 5),
25 ct(reflect.TypeOf(uint16(0)), 0, 1, 5),
26 ct(reflect.TypeOf(uint32(0)), 0, 1, 5),
27 ct(reflect.TypeOf(uint64(0)), 0, 1, 5),
28 ct(reflect.TypeOf(uintptr(0)), 0, 1, 5),
29 ct(reflect.TypeOf(string("")), "", "a", "ab"),
30 ct(reflect.TypeOf(float32(0)), math.NaN(), math.Inf(-1), -1e10, 0, 1e10, math.Inf(1)),
31 ct(reflect.TypeOf(float64(0)), math.NaN(), math.Inf(-1), -1e10, 0, 1e10, math.Inf(1)),
32 ct(reflect.TypeOf(complex64(0+1i)), -1-1i, -1+0i, -1+1i, 0-1i, 0+0i, 0+1i, 1-1i, 1+0i, 1+1i),
33 ct(reflect.TypeOf(complex128(0+1i)), -1-1i, -1+0i, -1+1i, 0-1i, 0+0i, 0+1i, 1-1i, 1+0i, 1+1i),
34 ct(reflect.TypeOf(false), false, true),
35 ct(reflect.TypeOf(&ints[0]), &ints[0], &ints[1], &ints[2]),
36 ct(reflect.TypeOf(chans[0]), chans[0], chans[1], chans[2]),
37 ct(reflect.TypeOf(toy{}), toy{0, 1}, toy{0, 2}, toy{1, -1}, toy{1, 1}),
38 ct(reflect.TypeOf([2]int{}), [2]int{1, 1}, [2]int{1, 2}, [2]int{2, 0}),
39 ct(reflect.TypeOf(interface{}(interface{}(0))), iFace, 1, 2, 3),
40 }
41
42 var iFace interface{}
43
44 func ct(typ reflect.Type, args ...interface{}) []reflect.Value {
45 value := make([]reflect.Value, len(args))
46 for i, v := range args {
47 x := reflect.ValueOf(v)
48 if !x.IsValid() {
49 x = reflect.Zero(typ)
50 } else {
51 x = x.Convert(typ)
52 }
53 value[i] = x
54 }
55 return value
56 }
57
58 func TestCompare(t *testing.T) {
59 for _, test := range compareTests {
60 for i, v0 := range test {
61 for j, v1 := range test {
62 c := fmtsort.Compare(v0, v1)
63 var expect int
64 switch {
65 case i == j:
66 expect = 0
67
68 if typ := v0.Type(); (typ.Kind() == reflect.Float32 || typ.Kind() == reflect.Float64) && math.IsNaN(v0.Float()) {
69 expect = -1
70 }
71 case i < j:
72 expect = -1
73 case i > j:
74 expect = 1
75 }
76 if c != expect {
77 t.Errorf("%s: compare(%v,%v)=%d; expect %d", v0.Type(), v0, v1, c, expect)
78 }
79 }
80 }
81 }
82 }
83
84 type sortTest struct {
85 data interface{}
86 print string
87 printBrokenNaNs string
88 }
89
90 var sortTests = []sortTest{
91 {
92 data: map[int]string{7: "bar", -3: "foo"},
93 print: "-3:foo 7:bar",
94 },
95 {
96 data: map[uint8]string{7: "bar", 3: "foo"},
97 print: "3:foo 7:bar",
98 },
99 {
100 data: map[string]string{"7": "bar", "3": "foo"},
101 print: "3:foo 7:bar",
102 },
103 {
104 data: map[float64]string{7: "bar", -3: "foo", math.NaN(): "nan", math.Inf(0): "inf"},
105 print: "NaN:nan -3:foo 7:bar +Inf:inf",
106 printBrokenNaNs: "NaN: -3:foo 7:bar +Inf:inf",
107 },
108 {
109 data: map[complex128]string{7 + 2i: "bar2", 7 + 1i: "bar", -3: "foo", complex(math.NaN(), 0i): "nan", complex(math.Inf(0), 0i): "inf"},
110 print: "(NaN+0i):nan (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
111 printBrokenNaNs: "(NaN+0i): (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
112 },
113 {
114 data: map[bool]string{true: "true", false: "false"},
115 print: "false:false true:true",
116 },
117 {
118 data: chanMap(),
119 print: "CHAN0:0 CHAN1:1 CHAN2:2",
120 },
121 {
122 data: pointerMap(),
123 print: "PTR0:0 PTR1:1 PTR2:2",
124 },
125 {
126 data: map[toy]string{toy{7, 2}: "72", toy{7, 1}: "71", toy{3, 4}: "34"},
127 print: "{3 4}:34 {7 1}:71 {7 2}:72",
128 },
129 {
130 data: map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
131 print: "[3 4]:34 [7 1]:71 [7 2]:72",
132 },
133 }
134
135 func sprint(data interface{}) string {
136 om := fmtsort.Sort(reflect.ValueOf(data))
137 if om == nil {
138 return "nil"
139 }
140 b := new(strings.Builder)
141 for i, key := range om.Key {
142 if i > 0 {
143 b.WriteRune(' ')
144 }
145 b.WriteString(sprintKey(key))
146 b.WriteRune(':')
147 b.WriteString(fmt.Sprint(om.Value[i]))
148 }
149 return b.String()
150 }
151
152
153
154
155
156 func sprintKey(key reflect.Value) string {
157 switch str := key.Type().String(); str {
158 case "*int":
159 ptr := key.Interface().(*int)
160 for i := range ints {
161 if ptr == &ints[i] {
162 return fmt.Sprintf("PTR%d", i)
163 }
164 }
165 return "PTR???"
166 case "chan int":
167 c := key.Interface().(chan int)
168 for i := range chans {
169 if c == chans[i] {
170 return fmt.Sprintf("CHAN%d", i)
171 }
172 }
173 return "CHAN???"
174 default:
175 return fmt.Sprint(key)
176 }
177 }
178
179 var (
180 ints [3]int
181 chans = [3]chan int{make(chan int), make(chan int), make(chan int)}
182 )
183
184 func pointerMap() map[*int]string {
185 m := make(map[*int]string)
186 for i := 2; i >= 0; i-- {
187 m[&ints[i]] = fmt.Sprint(i)
188 }
189 return m
190 }
191
192 func chanMap() map[chan int]string {
193 m := make(map[chan int]string)
194 for i := 2; i >= 0; i-- {
195 m[chans[i]] = fmt.Sprint(i)
196 }
197 return m
198 }
199
200 type toy struct {
201 A int
202 b int
203 }
204
205 func TestOrder(t *testing.T) {
206 for _, test := range sortTests {
207 got := sprint(test.data)
208 want := test.print
209 if fmtsort.BrokenNaNs && test.printBrokenNaNs != "" {
210 want = test.printBrokenNaNs
211 }
212 if got != want {
213 t.Errorf("%s: got %q, want %q", reflect.TypeOf(test.data), got, want)
214 }
215 }
216 }
217
218 func TestInterface(t *testing.T) {
219
220
221
222 m := map[interface{}]string{
223 [2]int{1, 0}: "",
224 [2]int{0, 1}: "",
225 true: "",
226 false: "",
227 3.1: "",
228 2.1: "",
229 1.1: "",
230 math.NaN(): "",
231 3: "",
232 2: "",
233 1: "",
234 "c": "",
235 "b": "",
236 "a": "",
237 struct{ x, y int }{1, 0}: "",
238 struct{ x, y int }{0, 1}: "",
239 }
240 got := sprint(m)
241 typeGroups := []string{
242 "NaN: 1.1: 2.1: 3.1:",
243 "false: true:",
244 "1: 2: 3:",
245 "a: b: c:",
246 "[0 1]: [1 0]:",
247 "{0 1}: {1 0}:",
248 }
249 for _, g := range typeGroups {
250 if !strings.Contains(got, g) {
251 t.Errorf("sorted map should contain %q", g)
252 }
253 }
254 }
255
View as plain text