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.
 
 
 

217 lines
6.4 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 cmp
  5. import (
  6. "io"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. ts "github.com/google/go-cmp/cmp/internal/teststructs"
  11. )
  12. // Test that the creation of Option values with non-sensible inputs produces
  13. // a run-time panic with a decent error message
  14. func TestOptionPanic(t *testing.T) {
  15. type myBool bool
  16. tests := []struct {
  17. label string // Test description
  18. fnc interface{} // Option function to call
  19. args []interface{} // Arguments to pass in
  20. wantPanic string // Expected panic message
  21. }{{
  22. label: "AllowUnexported",
  23. fnc: AllowUnexported,
  24. args: []interface{}{},
  25. }, {
  26. label: "AllowUnexported",
  27. fnc: AllowUnexported,
  28. args: []interface{}{1},
  29. wantPanic: "invalid struct type",
  30. }, {
  31. label: "AllowUnexported",
  32. fnc: AllowUnexported,
  33. args: []interface{}{ts.StructA{}},
  34. }, {
  35. label: "AllowUnexported",
  36. fnc: AllowUnexported,
  37. args: []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}},
  38. }, {
  39. label: "AllowUnexported",
  40. fnc: AllowUnexported,
  41. args: []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}},
  42. wantPanic: "invalid struct type",
  43. }, {
  44. label: "Comparer",
  45. fnc: Comparer,
  46. args: []interface{}{5},
  47. wantPanic: "invalid comparer function",
  48. }, {
  49. label: "Comparer",
  50. fnc: Comparer,
  51. args: []interface{}{func(x, y interface{}) bool { return true }},
  52. }, {
  53. label: "Comparer",
  54. fnc: Comparer,
  55. args: []interface{}{func(x, y io.Reader) bool { return true }},
  56. }, {
  57. label: "Comparer",
  58. fnc: Comparer,
  59. args: []interface{}{func(x, y io.Reader) myBool { return true }},
  60. wantPanic: "invalid comparer function",
  61. }, {
  62. label: "Comparer",
  63. fnc: Comparer,
  64. args: []interface{}{func(x string, y interface{}) bool { return true }},
  65. wantPanic: "invalid comparer function",
  66. }, {
  67. label: "Comparer",
  68. fnc: Comparer,
  69. args: []interface{}{(func(int, int) bool)(nil)},
  70. wantPanic: "invalid comparer function",
  71. }, {
  72. label: "Transformer",
  73. fnc: Transformer,
  74. args: []interface{}{"", 0},
  75. wantPanic: "invalid transformer function",
  76. }, {
  77. label: "Transformer",
  78. fnc: Transformer,
  79. args: []interface{}{"", func(int) int { return 0 }},
  80. }, {
  81. label: "Transformer",
  82. fnc: Transformer,
  83. args: []interface{}{"", func(bool) bool { return true }},
  84. }, {
  85. label: "Transformer",
  86. fnc: Transformer,
  87. args: []interface{}{"", func(int) bool { return true }},
  88. }, {
  89. label: "Transformer",
  90. fnc: Transformer,
  91. args: []interface{}{"", func(int, int) bool { return true }},
  92. wantPanic: "invalid transformer function",
  93. }, {
  94. label: "Transformer",
  95. fnc: Transformer,
  96. args: []interface{}{"", (func(int) uint)(nil)},
  97. wantPanic: "invalid transformer function",
  98. }, {
  99. label: "Transformer",
  100. fnc: Transformer,
  101. args: []interface{}{"Func", func(Path) Path { return nil }},
  102. }, {
  103. label: "Transformer",
  104. fnc: Transformer,
  105. args: []interface{}{"世界", func(int) bool { return true }},
  106. }, {
  107. label: "Transformer",
  108. fnc: Transformer,
  109. args: []interface{}{"/*", func(int) bool { return true }},
  110. wantPanic: "invalid name",
  111. }, {
  112. label: "Transformer",
  113. fnc: Transformer,
  114. args: []interface{}{"_", func(int) bool { return true }},
  115. }, {
  116. label: "FilterPath",
  117. fnc: FilterPath,
  118. args: []interface{}{(func(Path) bool)(nil), Ignore()},
  119. wantPanic: "invalid path filter function",
  120. }, {
  121. label: "FilterPath",
  122. fnc: FilterPath,
  123. args: []interface{}{func(Path) bool { return true }, Ignore()},
  124. }, {
  125. label: "FilterPath",
  126. fnc: FilterPath,
  127. args: []interface{}{func(Path) bool { return true }, Reporter(&defaultReporter{})},
  128. wantPanic: "invalid option type",
  129. }, {
  130. label: "FilterPath",
  131. fnc: FilterPath,
  132. args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}},
  133. }, {
  134. label: "FilterPath",
  135. fnc: FilterPath,
  136. args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}},
  137. wantPanic: "invalid option type",
  138. }, {
  139. label: "FilterValues",
  140. fnc: FilterValues,
  141. args: []interface{}{0, Ignore()},
  142. wantPanic: "invalid values filter function",
  143. }, {
  144. label: "FilterValues",
  145. fnc: FilterValues,
  146. args: []interface{}{func(x, y int) bool { return true }, Ignore()},
  147. }, {
  148. label: "FilterValues",
  149. fnc: FilterValues,
  150. args: []interface{}{func(x, y interface{}) bool { return true }, Ignore()},
  151. }, {
  152. label: "FilterValues",
  153. fnc: FilterValues,
  154. args: []interface{}{func(x, y interface{}) myBool { return true }, Ignore()},
  155. wantPanic: "invalid values filter function",
  156. }, {
  157. label: "FilterValues",
  158. fnc: FilterValues,
  159. args: []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()},
  160. wantPanic: "invalid values filter function",
  161. }, {
  162. label: "FilterValues",
  163. fnc: FilterValues,
  164. args: []interface{}{(func(int, int) bool)(nil), Ignore()},
  165. wantPanic: "invalid values filter function",
  166. }, {
  167. label: "FilterValues",
  168. fnc: FilterValues,
  169. args: []interface{}{func(int, int) bool { return true }, Reporter(&defaultReporter{})},
  170. wantPanic: "invalid option type",
  171. }, {
  172. label: "FilterValues",
  173. fnc: FilterValues,
  174. args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}},
  175. }, {
  176. label: "FilterValues",
  177. fnc: FilterValues,
  178. args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}},
  179. wantPanic: "invalid option type",
  180. }}
  181. for _, tt := range tests {
  182. t.Run(tt.label, func(t *testing.T) {
  183. var gotPanic string
  184. func() {
  185. defer func() {
  186. if ex := recover(); ex != nil {
  187. if s, ok := ex.(string); ok {
  188. gotPanic = s
  189. } else {
  190. panic(ex)
  191. }
  192. }
  193. }()
  194. var vargs []reflect.Value
  195. for _, arg := range tt.args {
  196. vargs = append(vargs, reflect.ValueOf(arg))
  197. }
  198. reflect.ValueOf(tt.fnc).Call(vargs)
  199. }()
  200. if tt.wantPanic == "" {
  201. if gotPanic != "" {
  202. t.Fatalf("unexpected panic message: %s", gotPanic)
  203. }
  204. } else {
  205. if !strings.Contains(gotPanic, tt.wantPanic) {
  206. t.Fatalf("panic message:\ngot: %s\nwant: %s", gotPanic, tt.wantPanic)
  207. }
  208. }
  209. })
  210. }
  211. }