You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

160 lines
4.7 KiB

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