aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/google/go-cmp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/go-cmp')
-rw-r--r--vendor/github.com/google/go-cmp/cmp/compare.go557
-rw-r--r--vendor/github.com/google/go-cmp/cmp/export_panic.go (renamed from vendor/github.com/google/go-cmp/cmp/unsafe_panic.go)6
-rw-r--r--vendor/github.com/google/go-cmp/cmp/export_unsafe.go (renamed from vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go)8
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go2
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go4
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go31
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go9
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go10
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go10
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/function/func.go64
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/value/format.go277
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go23
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go26
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/value/sort.go9
-rw-r--r--vendor/github.com/google/go-cmp/cmp/internal/value/zero.go45
-rw-r--r--vendor/github.com/google/go-cmp/cmp/options.go255
-rw-r--r--vendor/github.com/google/go-cmp/cmp/path.go339
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report.go51
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report_compare.go296
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report_reflect.go279
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report_slices.go333
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report_text.go382
-rw-r--r--vendor/github.com/google/go-cmp/cmp/report_value.go121
-rw-r--r--vendor/github.com/google/go-cmp/cmp/reporter.go53
24 files changed, 2315 insertions, 875 deletions
diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go
index 7e215f2..2133562 100644
--- a/vendor/github.com/google/go-cmp/cmp/compare.go
+++ b/vendor/github.com/google/go-cmp/cmp/compare.go
@@ -29,26 +29,17 @@ package cmp
29import ( 29import (
30 "fmt" 30 "fmt"
31 "reflect" 31 "reflect"
32 "strings"
32 33
33 "github.com/google/go-cmp/cmp/internal/diff" 34 "github.com/google/go-cmp/cmp/internal/diff"
35 "github.com/google/go-cmp/cmp/internal/flags"
34 "github.com/google/go-cmp/cmp/internal/function" 36 "github.com/google/go-cmp/cmp/internal/function"
35 "github.com/google/go-cmp/cmp/internal/value" 37 "github.com/google/go-cmp/cmp/internal/value"
36) 38)
37 39
38// BUG(dsnet): Maps with keys containing NaN values cannot be properly compared due to
39// the reflection package's inability to retrieve such entries. Equal will panic
40// anytime it comes across a NaN key, but this behavior may change.
41//
42// See https://golang.org/issue/11104 for more details.
43
44var nothing = reflect.Value{}
45
46// Equal reports whether x and y are equal by recursively applying the 40// Equal reports whether x and y are equal by recursively applying the
47// following rules in the given order to x and y and all of their sub-values: 41// following rules in the given order to x and y and all of their sub-values:
48// 42//
49// • If two values are not of the same type, then they are never equal
50// and the overall result is false.
51//
52// • Let S be the set of all Ignore, Transformer, and Comparer options that 43// • Let S be the set of all Ignore, Transformer, and Comparer options that
53// remain after applying all path filters, value filters, and type filters. 44// remain after applying all path filters, value filters, and type filters.
54// If at least one Ignore exists in S, then the comparison is ignored. 45// If at least one Ignore exists in S, then the comparison is ignored.
@@ -61,43 +52,79 @@ var nothing = reflect.Value{}
61// 52//
62// • If the values have an Equal method of the form "(T) Equal(T) bool" or 53// • If the values have an Equal method of the form "(T) Equal(T) bool" or
63// "(T) Equal(I) bool" where T is assignable to I, then use the result of 54// "(T) Equal(I) bool" where T is assignable to I, then use the result of
64// x.Equal(y) even if x or y is nil. 55// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
65// Otherwise, no such method exists and evaluation proceeds to the next rule. 56// evaluation proceeds to the next rule.
66// 57//
67// • Lastly, try to compare x and y based on their basic kinds. 58// • Lastly, try to compare x and y based on their basic kinds.
68// Simple kinds like booleans, integers, floats, complex numbers, strings, and 59// Simple kinds like booleans, integers, floats, complex numbers, strings, and
69// channels are compared using the equivalent of the == operator in Go. 60// channels are compared using the equivalent of the == operator in Go.
70// Functions are only equal if they are both nil, otherwise they are unequal. 61// Functions are only equal if they are both nil, otherwise they are unequal.
71// Pointers are equal if the underlying values they point to are also equal.
72// Interfaces are equal if their underlying concrete values are also equal.
73// 62//
74// Structs are equal if all of their fields are equal. If a struct contains 63// Structs are equal if recursively calling Equal on all fields report equal.
75// unexported fields, Equal panics unless the AllowUnexported option is used or 64// If a struct contains unexported fields, Equal panics unless an Ignore option
76// an Ignore option (e.g., cmpopts.IgnoreUnexported) ignores that field. 65// (e.g., cmpopts.IgnoreUnexported) ignores that field or the AllowUnexported
66// option explicitly permits comparing the unexported field.
67//
68// Slices are equal if they are both nil or both non-nil, where recursively
69// calling Equal on all non-ignored slice or array elements report equal.
70// Empty non-nil slices and nil slices are not equal; to equate empty slices,
71// consider using cmpopts.EquateEmpty.
77// 72//
78// Arrays, slices, and maps are equal if they are both nil or both non-nil 73// Maps are equal if they are both nil or both non-nil, where recursively
79// with the same length and the elements at each index or key are equal. 74// calling Equal on all non-ignored map entries report equal.
80// Note that a non-nil empty slice and a nil slice are not equal.
81// To equate empty slices and maps, consider using cmpopts.EquateEmpty.
82// Map keys are equal according to the == operator. 75// Map keys are equal according to the == operator.
83// To use custom comparisons for map keys, consider using cmpopts.SortMaps. 76// To use custom comparisons for map keys, consider using cmpopts.SortMaps.
77// Empty non-nil maps and nil maps are not equal; to equate empty maps,
78// consider using cmpopts.EquateEmpty.
79//
80// Pointers and interfaces are equal if they are both nil or both non-nil,
81// where they have the same underlying concrete type and recursively
82// calling Equal on the underlying values reports equal.
84func Equal(x, y interface{}, opts ...Option) bool { 83func Equal(x, y interface{}, opts ...Option) bool {
84 vx := reflect.ValueOf(x)
85 vy := reflect.ValueOf(y)
86
87 // If the inputs are different types, auto-wrap them in an empty interface
88 // so that they have the same parent type.
89 var t reflect.Type
90 if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
91 t = reflect.TypeOf((*interface{})(nil)).Elem()
92 if vx.IsValid() {
93 vvx := reflect.New(t).Elem()
94 vvx.Set(vx)
95 vx = vvx
96 }
97 if vy.IsValid() {
98 vvy := reflect.New(t).Elem()
99 vvy.Set(vy)
100 vy = vvy
101 }
102 } else {
103 t = vx.Type()
104 }
105
85 s := newState(opts) 106 s := newState(opts)
86 s.compareAny(reflect.ValueOf(x), reflect.ValueOf(y)) 107 s.compareAny(&pathStep{t, vx, vy})
87 return s.result.Equal() 108 return s.result.Equal()
88} 109}
89 110
90// Diff returns a human-readable report of the differences between two values. 111// Diff returns a human-readable report of the differences between two values.
91// It returns an empty string if and only if Equal returns true for the same 112// It returns an empty string if and only if Equal returns true for the same
92// input values and options. The output string will use the "-" symbol to 113// input values and options.
93// indicate elements removed from x, and the "+" symbol to indicate elements 114//
94// added to y. 115// The output is displayed as a literal in pseudo-Go syntax.
116// At the start of each line, a "-" prefix indicates an element removed from x,
117// a "+" prefix to indicates an element added to y, and the lack of a prefix
118// indicates an element common to both x and y. If possible, the output
119// uses fmt.Stringer.String or error.Error methods to produce more humanly
120// readable outputs. In such cases, the string is prefixed with either an
121// 's' or 'e' character, respectively, to indicate that the method was called.
95// 122//
96// Do not depend on this output being stable. 123// Do not depend on this output being stable. If you need the ability to
124// programmatically interpret the difference, consider using a custom Reporter.
97func Diff(x, y interface{}, opts ...Option) string { 125func Diff(x, y interface{}, opts ...Option) string {
98 r := new(defaultReporter) 126 r := new(defaultReporter)
99 opts = Options{Options(opts), r} 127 eq := Equal(x, y, Options(opts), Reporter(r))
100 eq := Equal(x, y, opts...)
101 d := r.String() 128 d := r.String()
102 if (d == "") != eq { 129 if (d == "") != eq {
103 panic("inconsistent difference and equality results") 130 panic("inconsistent difference and equality results")
@@ -108,9 +135,13 @@ func Diff(x, y interface{}, opts ...Option) string {
108type state struct { 135type state struct {
109 // These fields represent the "comparison state". 136 // These fields represent the "comparison state".
110 // Calling statelessCompare must not result in observable changes to these. 137 // Calling statelessCompare must not result in observable changes to these.
111 result diff.Result // The current result of comparison 138 result diff.Result // The current result of comparison
112 curPath Path // The current path in the value tree 139 curPath Path // The current path in the value tree
113 reporter reporter // Optional reporter used for difference formatting 140 reporters []reporter // Optional reporters
141
142 // recChecker checks for infinite cycles applying the same set of
143 // transformers upon the output of itself.
144 recChecker recChecker
114 145
115 // dynChecker triggers pseudo-random checks for option correctness. 146 // dynChecker triggers pseudo-random checks for option correctness.
116 // It is safe for statelessCompare to mutate this value. 147 // It is safe for statelessCompare to mutate this value.
@@ -122,10 +153,9 @@ type state struct {
122} 153}
123 154
124func newState(opts []Option) *state { 155func newState(opts []Option) *state {
125 s := new(state) 156 // Always ensure a validator option exists to validate the inputs.
126 for _, opt := range opts { 157 s := &state{opts: Options{validator{}}}
127 s.processOption(opt) 158 s.processOption(Options(opts))
128 }
129 return s 159 return s
130} 160}
131 161
@@ -152,10 +182,7 @@ func (s *state) processOption(opt Option) {
152 s.exporters[t] = true 182 s.exporters[t] = true
153 } 183 }
154 case reporter: 184 case reporter:
155 if s.reporter != nil { 185 s.reporters = append(s.reporters, opt)
156 panic("difference reporter already registered")
157 }
158 s.reporter = opt
159 default: 186 default:
160 panic(fmt.Sprintf("unknown option %T", opt)) 187 panic(fmt.Sprintf("unknown option %T", opt))
161 } 188 }
@@ -164,153 +191,88 @@ func (s *state) processOption(opt Option) {
164// statelessCompare compares two values and returns the result. 191// statelessCompare compares two values and returns the result.
165// This function is stateless in that it does not alter the current result, 192// This function is stateless in that it does not alter the current result,
166// or output to any registered reporters. 193// or output to any registered reporters.
167func (s *state) statelessCompare(vx, vy reflect.Value) diff.Result { 194func (s *state) statelessCompare(step PathStep) diff.Result {
168 // We do not save and restore the curPath because all of the compareX 195 // We do not save and restore the curPath because all of the compareX
169 // methods should properly push and pop from the path. 196 // methods should properly push and pop from the path.
170 // It is an implementation bug if the contents of curPath differs from 197 // It is an implementation bug if the contents of curPath differs from
171 // when calling this function to when returning from it. 198 // when calling this function to when returning from it.
172 199
173 oldResult, oldReporter := s.result, s.reporter 200 oldResult, oldReporters := s.result, s.reporters
174 s.result = diff.Result{} // Reset result 201 s.result = diff.Result{} // Reset result
175 s.reporter = nil // Remove reporter to avoid spurious printouts 202 s.reporters = nil // Remove reporters to avoid spurious printouts
176 s.compareAny(vx, vy) 203 s.compareAny(step)
177 res := s.result 204 res := s.result
178 s.result, s.reporter = oldResult, oldReporter 205 s.result, s.reporters = oldResult, oldReporters
179 return res 206 return res
180} 207}
181 208
182func (s *state) compareAny(vx, vy reflect.Value) { 209func (s *state) compareAny(step PathStep) {
183 // TODO: Support cyclic data structures. 210 // Update the path stack.
184 211 s.curPath.push(step)
185 // Rule 0: Differing types are never equal. 212 defer s.curPath.pop()
186 if !vx.IsValid() || !vy.IsValid() { 213 for _, r := range s.reporters {
187 s.report(vx.IsValid() == vy.IsValid(), vx, vy) 214 r.PushStep(step)
188 return 215 defer r.PopStep()
189 }
190 if vx.Type() != vy.Type() {
191 s.report(false, vx, vy) // Possible for path to be empty
192 return
193 }
194 t := vx.Type()
195 if len(s.curPath) == 0 {
196 s.curPath.push(&pathStep{typ: t})
197 defer s.curPath.pop()
198 } 216 }
199 vx, vy = s.tryExporting(vx, vy) 217 s.recChecker.Check(s.curPath)
218
219 // Obtain the current type and values.
220 t := step.Type()
221 vx, vy := step.Values()
200 222
201 // Rule 1: Check whether an option applies on this node in the value tree. 223 // Rule 1: Check whether an option applies on this node in the value tree.
202 if s.tryOptions(vx, vy, t) { 224 if s.tryOptions(t, vx, vy) {
203 return 225 return
204 } 226 }
205 227
206 // Rule 2: Check whether the type has a valid Equal method. 228 // Rule 2: Check whether the type has a valid Equal method.
207 if s.tryMethod(vx, vy, t) { 229 if s.tryMethod(t, vx, vy) {
208 return 230 return
209 } 231 }
210 232
211 // Rule 3: Recursively descend into each value's underlying kind. 233 // Rule 3: Compare based on the underlying kind.
212 switch t.Kind() { 234 switch t.Kind() {
213 case reflect.Bool: 235 case reflect.Bool:
214 s.report(vx.Bool() == vy.Bool(), vx, vy) 236 s.report(vx.Bool() == vy.Bool(), 0)
215 return
216 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 237 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
217 s.report(vx.Int() == vy.Int(), vx, vy) 238 s.report(vx.Int() == vy.Int(), 0)
218 return
219 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 239 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
220 s.report(vx.Uint() == vy.Uint(), vx, vy) 240 s.report(vx.Uint() == vy.Uint(), 0)
221 return
222 case reflect.Float32, reflect.Float64: 241 case reflect.Float32, reflect.Float64:
223 s.report(vx.Float() == vy.Float(), vx, vy) 242 s.report(vx.Float() == vy.Float(), 0)
224 return
225 case reflect.Complex64, reflect.Complex128: 243 case reflect.Complex64, reflect.Complex128:
226 s.report(vx.Complex() == vy.Complex(), vx, vy) 244 s.report(vx.Complex() == vy.Complex(), 0)
227 return
228 case reflect.String: 245 case reflect.String:
229 s.report(vx.String() == vy.String(), vx, vy) 246 s.report(vx.String() == vy.String(), 0)
230 return
231 case reflect.Chan, reflect.UnsafePointer: 247 case reflect.Chan, reflect.UnsafePointer:
232 s.report(vx.Pointer() == vy.Pointer(), vx, vy) 248 s.report(vx.Pointer() == vy.Pointer(), 0)
233 return
234 case reflect.Func: 249 case reflect.Func:
235 s.report(vx.IsNil() && vy.IsNil(), vx, vy) 250 s.report(vx.IsNil() && vy.IsNil(), 0)
236 return 251 case reflect.Struct:
252 s.compareStruct(t, vx, vy)
253 case reflect.Slice, reflect.Array:
254 s.compareSlice(t, vx, vy)
255 case reflect.Map:
256 s.compareMap(t, vx, vy)
237 case reflect.Ptr: 257 case reflect.Ptr:
238 if vx.IsNil() || vy.IsNil() { 258 s.comparePtr(t, vx, vy)
239 s.report(vx.IsNil() && vy.IsNil(), vx, vy)
240 return
241 }
242 s.curPath.push(&indirect{pathStep{t.Elem()}})
243 defer s.curPath.pop()
244 s.compareAny(vx.Elem(), vy.Elem())
245 return
246 case reflect.Interface: 259 case reflect.Interface:
247 if vx.IsNil() || vy.IsNil() { 260 s.compareInterface(t, vx, vy)
248 s.report(vx.IsNil() && vy.IsNil(), vx, vy)
249 return
250 }
251 if vx.Elem().Type() != vy.Elem().Type() {
252 s.report(false, vx.Elem(), vy.Elem())
253 return
254 }
255 s.curPath.push(&typeAssertion{pathStep{vx.Elem().Type()}})
256 defer s.curPath.pop()
257 s.compareAny(vx.Elem(), vy.Elem())
258 return
259 case reflect.Slice:
260 if vx.IsNil() || vy.IsNil() {
261 s.report(vx.IsNil() && vy.IsNil(), vx, vy)
262 return
263 }
264 fallthrough
265 case reflect.Array:
266 s.compareArray(vx, vy, t)
267 return
268 case reflect.Map:
269 s.compareMap(vx, vy, t)
270 return
271 case reflect.Struct:
272 s.compareStruct(vx, vy, t)
273 return
274 default: 261 default:
275 panic(fmt.Sprintf("%v kind not handled", t.Kind())) 262 panic(fmt.Sprintf("%v kind not handled", t.Kind()))
276 } 263 }
277} 264}
278 265
279func (s *state) tryExporting(vx, vy reflect.Value) (reflect.Value, reflect.Value) { 266func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool {
280 if sf, ok := s.curPath[len(s.curPath)-1].(*structField); ok && sf.unexported {
281 if sf.force {
282 // Use unsafe pointer arithmetic to get read-write access to an
283 // unexported field in the struct.
284 vx = unsafeRetrieveField(sf.pvx, sf.field)
285 vy = unsafeRetrieveField(sf.pvy, sf.field)
286 } else {
287 // We are not allowed to export the value, so invalidate them
288 // so that tryOptions can panic later if not explicitly ignored.
289 vx = nothing
290 vy = nothing
291 }
292 }
293 return vx, vy
294}
295
296func (s *state) tryOptions(vx, vy reflect.Value, t reflect.Type) bool {
297 // If there were no FilterValues, we will not detect invalid inputs,
298 // so manually check for them and append invalid if necessary.
299 // We still evaluate the options since an ignore can override invalid.
300 opts := s.opts
301 if !vx.IsValid() || !vy.IsValid() {
302 opts = Options{opts, invalid{}}
303 }
304
305 // Evaluate all filters and apply the remaining options. 267 // Evaluate all filters and apply the remaining options.
306 if opt := opts.filter(s, vx, vy, t); opt != nil { 268 if opt := s.opts.filter(s, t, vx, vy); opt != nil {
307 opt.apply(s, vx, vy) 269 opt.apply(s, vx, vy)
308 return true 270 return true
309 } 271 }
310 return false 272 return false
311} 273}
312 274
313func (s *state) tryMethod(vx, vy reflect.Value, t reflect.Type) bool { 275func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool {
314 // Check if this type even has an Equal method. 276 // Check if this type even has an Equal method.
315 m, ok := t.MethodByName("Equal") 277 m, ok := t.MethodByName("Equal")
316 if !ok || !function.IsType(m.Type, function.EqualAssignable) { 278 if !ok || !function.IsType(m.Type, function.EqualAssignable) {
@@ -318,11 +280,11 @@ func (s *state) tryMethod(vx, vy reflect.Value, t reflect.Type) bool {
318 } 280 }
319 281
320 eq := s.callTTBFunc(m.Func, vx, vy) 282 eq := s.callTTBFunc(m.Func, vx, vy)
321 s.report(eq, vx, vy) 283 s.report(eq, reportByMethod)
322 return true 284 return true
323} 285}
324 286
325func (s *state) callTRFunc(f, v reflect.Value) reflect.Value { 287func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value {
326 v = sanitizeValue(v, f.Type().In(0)) 288 v = sanitizeValue(v, f.Type().In(0))
327 if !s.dynChecker.Next() { 289 if !s.dynChecker.Next() {
328 return f.Call([]reflect.Value{v})[0] 290 return f.Call([]reflect.Value{v})[0]
@@ -333,15 +295,15 @@ func (s *state) callTRFunc(f, v reflect.Value) reflect.Value {
333 // unsafe mutations to the input. 295 // unsafe mutations to the input.
334 c := make(chan reflect.Value) 296 c := make(chan reflect.Value)
335 go detectRaces(c, f, v) 297 go detectRaces(c, f, v)
298 got := <-c
336 want := f.Call([]reflect.Value{v})[0] 299 want := f.Call([]reflect.Value{v})[0]
337 if got := <-c; !s.statelessCompare(got, want).Equal() { 300 if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() {
338 // To avoid false-positives with non-reflexive equality operations, 301 // To avoid false-positives with non-reflexive equality operations,
339 // we sanity check whether a value is equal to itself. 302 // we sanity check whether a value is equal to itself.
340 if !s.statelessCompare(want, want).Equal() { 303 if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() {
341 return want 304 return want
342 } 305 }
343 fn := getFuncName(f.Pointer()) 306 panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f)))
344 panic(fmt.Sprintf("non-deterministic function detected: %s", fn))
345 } 307 }
346 return want 308 return want
347} 309}
@@ -359,10 +321,10 @@ func (s *state) callTTBFunc(f, x, y reflect.Value) bool {
359 // unsafe mutations to the input. 321 // unsafe mutations to the input.
360 c := make(chan reflect.Value) 322 c := make(chan reflect.Value)
361 go detectRaces(c, f, y, x) 323 go detectRaces(c, f, y, x)
324 got := <-c
362 want := f.Call([]reflect.Value{x, y})[0].Bool() 325 want := f.Call([]reflect.Value{x, y})[0].Bool()
363 if got := <-c; !got.IsValid() || got.Bool() != want { 326 if !got.IsValid() || got.Bool() != want {
364 fn := getFuncName(f.Pointer()) 327 panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f)))
365 panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", fn))
366 } 328 }
367 return want 329 return want
368} 330}
@@ -380,140 +342,241 @@ func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) {
380// assuming that T is assignable to R. 342// assuming that T is assignable to R.
381// Otherwise, it returns the input value as is. 343// Otherwise, it returns the input value as is.
382func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { 344func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
383 // TODO(dsnet): Remove this hacky workaround. 345 // TODO(dsnet): Workaround for reflect bug (https://golang.org/issue/22143).
384 // See https://golang.org/issue/22143 346 if !flags.AtLeastGo110 {
385 if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { 347 if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
386 return reflect.New(t).Elem() 348 return reflect.New(t).Elem()
349 }
387 } 350 }
388 return v 351 return v
389} 352}
390 353
391func (s *state) compareArray(vx, vy reflect.Value, t reflect.Type) { 354func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
392 step := &sliceIndex{pathStep{t.Elem()}, 0, 0} 355 var vax, vay reflect.Value // Addressable versions of vx and vy
393 s.curPath.push(step)
394 356
395 // Compute an edit-script for slices vx and vy. 357 step := StructField{&structField{}}
396 es := diff.Difference(vx.Len(), vy.Len(), func(ix, iy int) diff.Result { 358 for i := 0; i < t.NumField(); i++ {
397 step.xkey, step.ykey = ix, iy 359 step.typ = t.Field(i).Type
398 return s.statelessCompare(vx.Index(ix), vy.Index(iy)) 360 step.vx = vx.Field(i)
399 }) 361 step.vy = vy.Field(i)
362 step.name = t.Field(i).Name
363 step.idx = i
364 step.unexported = !isExported(step.name)
365 if step.unexported {
366 if step.name == "_" {
367 continue
368 }
369 // Defer checking of unexported fields until later to give an
370 // Ignore a chance to ignore the field.
371 if !vax.IsValid() || !vay.IsValid() {
372 // For retrieveUnexportedField to work, the parent struct must
373 // be addressable. Create a new copy of the values if
374 // necessary to make them addressable.
375 vax = makeAddressable(vx)
376 vay = makeAddressable(vy)
377 }
378 step.mayForce = s.exporters[t]
379 step.pvx = vax
380 step.pvy = vay
381 step.field = t.Field(i)
382 }
383 s.compareAny(step)
384 }
385}
400 386
401 // Report the entire slice as is if the arrays are of primitive kind, 387func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) {
402 // and the arrays are different enough. 388 isSlice := t.Kind() == reflect.Slice
403 isPrimitive := false 389 if isSlice && (vx.IsNil() || vy.IsNil()) {
404 switch t.Elem().Kind() { 390 s.report(vx.IsNil() && vy.IsNil(), 0)
405 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
406 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
407 reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
408 isPrimitive = true
409 }
410 if isPrimitive && es.Dist() > (vx.Len()+vy.Len())/4 {
411 s.curPath.pop() // Pop first since we are reporting the whole slice
412 s.report(false, vx, vy)
413 return 391 return
414 } 392 }
415 393
416 // Replay the edit-script. 394 // TODO: Support cyclic data structures.
395
396 step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}}}
397 withIndexes := func(ix, iy int) SliceIndex {
398 if ix >= 0 {
399 step.vx, step.xkey = vx.Index(ix), ix
400 } else {
401 step.vx, step.xkey = reflect.Value{}, -1
402 }
403 if iy >= 0 {
404 step.vy, step.ykey = vy.Index(iy), iy
405 } else {
406 step.vy, step.ykey = reflect.Value{}, -1
407 }
408 return step
409 }
410
411 // Ignore options are able to ignore missing elements in a slice.
412 // However, detecting these reliably requires an optimal differencing
413 // algorithm, for which diff.Difference is not.
414 //
415 // Instead, we first iterate through both slices to detect which elements
416 // would be ignored if standing alone. The index of non-discarded elements
417 // are stored in a separate slice, which diffing is then performed on.
418 var indexesX, indexesY []int
419 var ignoredX, ignoredY []bool
420 for ix := 0; ix < vx.Len(); ix++ {
421 ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0
422 if !ignored {
423 indexesX = append(indexesX, ix)
424 }
425 ignoredX = append(ignoredX, ignored)
426 }
427 for iy := 0; iy < vy.Len(); iy++ {
428 ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0
429 if !ignored {
430 indexesY = append(indexesY, iy)
431 }
432 ignoredY = append(ignoredY, ignored)
433 }
434
435 // Compute an edit-script for slices vx and vy (excluding ignored elements).
436 edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result {
437 return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy]))
438 })
439
440 // Replay the ignore-scripts and the edit-script.
417 var ix, iy int 441 var ix, iy int
418 for _, e := range es { 442 for ix < vx.Len() || iy < vy.Len() {
443 var e diff.EditType
444 switch {
445 case ix < len(ignoredX) && ignoredX[ix]:
446 e = diff.UniqueX
447 case iy < len(ignoredY) && ignoredY[iy]:
448 e = diff.UniqueY
449 default:
450 e, edits = edits[0], edits[1:]
451 }
419 switch e { 452 switch e {
420 case diff.UniqueX: 453 case diff.UniqueX:
421 step.xkey, step.ykey = ix, -1 454 s.compareAny(withIndexes(ix, -1))
422 s.report(false, vx.Index(ix), nothing)
423 ix++ 455 ix++
424 case diff.UniqueY: 456 case diff.UniqueY:
425 step.xkey, step.ykey = -1, iy 457 s.compareAny(withIndexes(-1, iy))
426 s.report(false, nothing, vy.Index(iy))
427 iy++ 458 iy++
428 default: 459 default:
429 step.xkey, step.ykey = ix, iy 460 s.compareAny(withIndexes(ix, iy))
430 if e == diff.Identity {
431 s.report(true, vx.Index(ix), vy.Index(iy))
432 } else {
433 s.compareAny(vx.Index(ix), vy.Index(iy))
434 }
435 ix++ 461 ix++
436 iy++ 462 iy++
437 } 463 }
438 } 464 }
439 s.curPath.pop()
440 return
441} 465}
442 466
443func (s *state) compareMap(vx, vy reflect.Value, t reflect.Type) { 467func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) {
444 if vx.IsNil() || vy.IsNil() { 468 if vx.IsNil() || vy.IsNil() {
445 s.report(vx.IsNil() && vy.IsNil(), vx, vy) 469 s.report(vx.IsNil() && vy.IsNil(), 0)
446 return 470 return
447 } 471 }
448 472
473 // TODO: Support cyclic data structures.
474
449 // We combine and sort the two map keys so that we can perform the 475 // We combine and sort the two map keys so that we can perform the
450 // comparisons in a deterministic order. 476 // comparisons in a deterministic order.
451 step := &mapIndex{pathStep: pathStep{t.Elem()}} 477 step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}}
452 s.curPath.push(step)
453 defer s.curPath.pop()
454 for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) { 478 for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) {
479 step.vx = vx.MapIndex(k)
480 step.vy = vy.MapIndex(k)
455 step.key = k 481 step.key = k
456 vvx := vx.MapIndex(k) 482 if !step.vx.IsValid() && !step.vy.IsValid() {
457 vvy := vy.MapIndex(k) 483 // It is possible for both vx and vy to be invalid if the
458 switch { 484 // key contained a NaN value in it.
459 case vvx.IsValid() && vvy.IsValid(): 485 //
460 s.compareAny(vvx, vvy) 486 // Even with the ability to retrieve NaN keys in Go 1.12,
461 case vvx.IsValid() && !vvy.IsValid(): 487 // there still isn't a sensible way to compare the values since
462 s.report(false, vvx, nothing) 488 // a NaN key may map to multiple unordered values.
463 case !vvx.IsValid() && vvy.IsValid(): 489 // The most reasonable way to compare NaNs would be to compare the
464 s.report(false, nothing, vvy) 490 // set of values. However, this is impossible to do efficiently
465 default: 491 // since set equality is provably an O(n^2) operation given only
466 // It is possible for both vvx and vvy to be invalid if the 492 // an Equal function. If we had a Less function or Hash function,
467 // key contained a NaN value in it. There is no way in 493 // this could be done in O(n*log(n)) or O(n), respectively.
468 // reflection to be able to retrieve these values. 494 //
469 // See https://golang.org/issue/11104 495 // Rather than adding complex logic to deal with NaNs, make it
470 panic(fmt.Sprintf("%#v has map key with NaNs", s.curPath)) 496 // the user's responsibility to compare such obscure maps.
497 const help = "consider providing a Comparer to compare the map"
498 panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help))
471 } 499 }
500 s.compareAny(step)
472 } 501 }
473} 502}
474 503
475func (s *state) compareStruct(vx, vy reflect.Value, t reflect.Type) { 504func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) {
476 var vax, vay reflect.Value // Addressable versions of vx and vy 505 if vx.IsNil() || vy.IsNil() {
506 s.report(vx.IsNil() && vy.IsNil(), 0)
507 return
508 }
477 509
478 step := &structField{} 510 // TODO: Support cyclic data structures.
479 s.curPath.push(step) 511
480 defer s.curPath.pop() 512 vx, vy = vx.Elem(), vy.Elem()
481 for i := 0; i < t.NumField(); i++ { 513 s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}})
482 vvx := vx.Field(i) 514}
483 vvy := vy.Field(i) 515
484 step.typ = t.Field(i).Type 516func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) {
485 step.name = t.Field(i).Name 517 if vx.IsNil() || vy.IsNil() {
486 step.idx = i 518 s.report(vx.IsNil() && vy.IsNil(), 0)
487 step.unexported = !isExported(step.name) 519 return
488 if step.unexported { 520 }
489 // Defer checking of unexported fields until later to give an 521 vx, vy = vx.Elem(), vy.Elem()
490 // Ignore a chance to ignore the field. 522 if vx.Type() != vy.Type() {
491 if !vax.IsValid() || !vay.IsValid() { 523 s.report(false, 0)
492 // For unsafeRetrieveField to work, the parent struct must 524 return
493 // be addressable. Create a new copy of the values if 525 }
494 // necessary to make them addressable. 526 s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}})
495 vax = makeAddressable(vx) 527}
496 vay = makeAddressable(vy) 528
497 } 529func (s *state) report(eq bool, rf resultFlags) {
498 step.force = s.exporters[t] 530 if rf&reportByIgnore == 0 {
499 step.pvx = vax 531 if eq {
500 step.pvy = vay 532 s.result.NumSame++
501 step.field = t.Field(i) 533 rf |= reportEqual
534 } else {
535 s.result.NumDiff++
536 rf |= reportUnequal
502 } 537 }
503 s.compareAny(vvx, vvy) 538 }
539 for _, r := range s.reporters {
540 r.Report(Result{flags: rf})
504 } 541 }
505} 542}
506 543
507// report records the result of a single comparison. 544// recChecker tracks the state needed to periodically perform checks that
508// It also calls Report if any reporter is registered. 545// user provided transformers are not stuck in an infinitely recursive cycle.
509func (s *state) report(eq bool, vx, vy reflect.Value) { 546type recChecker struct{ next int }
510 if eq { 547
511 s.result.NSame++ 548// Check scans the Path for any recursive transformers and panics when any
512 } else { 549// recursive transformers are detected. Note that the presence of a
513 s.result.NDiff++ 550// recursive Transformer does not necessarily imply an infinite cycle.
551// As such, this check only activates after some minimal number of path steps.
552func (rc *recChecker) Check(p Path) {
553 const minLen = 1 << 16
554 if rc.next == 0 {
555 rc.next = minLen
556 }
557 if len(p) < rc.next {
558 return
559 }
560 rc.next <<= 1
561
562 // Check whether the same transformer has appeared at least twice.
563 var ss []string
564 m := map[Option]int{}
565 for _, ps := range p {
566 if t, ok := ps.(Transform); ok {
567 t := t.Option()
568 if m[t] == 1 { // Transformer was used exactly once before
569 tf := t.(*transformer).fnc.Type()
570 ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0)))
571 }
572 m[t]++
573 }
514 } 574 }
515 if s.reporter != nil { 575 if len(ss) > 0 {
516 s.reporter.Report(vx, vy, eq, s.curPath) 576 const warning = "recursive set of Transformers detected"
577 const help = "consider using cmpopts.AcyclicTransformer"
578 set := strings.Join(ss, "\n\t")
579 panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help))
517 } 580 }
518} 581}
519 582
diff --git a/vendor/github.com/google/go-cmp/cmp/unsafe_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go
index d1518eb..abc3a1c 100644
--- a/vendor/github.com/google/go-cmp/cmp/unsafe_panic.go
+++ b/vendor/github.com/google/go-cmp/cmp/export_panic.go
@@ -2,7 +2,7 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE.md file. 3// license that can be found in the LICENSE.md file.
4 4
5// +build purego appengine js 5// +build purego
6 6
7package cmp 7package cmp
8 8
@@ -10,6 +10,6 @@ import "reflect"
10 10
11const supportAllowUnexported = false 11const supportAllowUnexported = false
12 12
13func unsafeRetrieveField(reflect.Value, reflect.StructField) reflect.Value { 13func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value {
14 panic("unsafeRetrieveField is not implemented") 14 panic("retrieveUnexportedField is not implemented")
15} 15}
diff --git a/vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go
index 579b655..59d4ee9 100644
--- a/vendor/github.com/google/go-cmp/cmp/unsafe_reflect.go
+++ b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go
@@ -2,7 +2,7 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE.md file. 3// license that can be found in the LICENSE.md file.
4 4
5// +build !purego,!appengine,!js 5// +build !purego
6 6
7package cmp 7package cmp
8 8
@@ -13,11 +13,11 @@ import (
13 13
14const supportAllowUnexported = true 14const supportAllowUnexported = true
15 15
16// unsafeRetrieveField uses unsafe to forcibly retrieve any field from a struct 16// retrieveUnexportedField uses unsafe to forcibly retrieve any field from
17// such that the value has read-write permissions. 17// a struct such that the value has read-write permissions.
18// 18//
19// The parent struct, v, must be addressable, while f must be a StructField 19// The parent struct, v, must be addressable, while f must be a StructField
20// describing the field to retrieve. 20// describing the field to retrieve.
21func unsafeRetrieveField(v reflect.Value, f reflect.StructField) reflect.Value { 21func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value {
22 return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem() 22 return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem()
23} 23}
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
index 42afa49..fe98dcc 100644
--- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
+++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go
@@ -2,7 +2,7 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE.md file. 3// license that can be found in the LICENSE.md file.
4 4
5// +build !debug 5// +build !cmp_debug
6 6
7package diff 7package diff
8 8
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
index fd9f7f1..597b6ae 100644
--- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
+++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go
@@ -2,7 +2,7 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE.md file. 3// license that can be found in the LICENSE.md file.
4 4
5// +build debug 5// +build cmp_debug
6 6
7package diff 7package diff
8 8
@@ -14,7 +14,7 @@ import (
14) 14)
15 15
16// The algorithm can be seen running in real-time by enabling debugging: 16// The algorithm can be seen running in real-time by enabling debugging:
17// go test -tags=debug -v 17// go test -tags=cmp_debug -v
18// 18//
19// Example output: 19// Example output:
20// === RUN TestDifference/#34 20// === RUN TestDifference/#34
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
index 260befe..3d2e426 100644
--- a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
+++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go
@@ -85,22 +85,31 @@ func (es EditScript) LenY() int { return len(es) - es.stats().NX }
85type EqualFunc func(ix int, iy int) Result 85type EqualFunc func(ix int, iy int) Result
86 86
87// Result is the result of comparison. 87// Result is the result of comparison.
88// NSame is the number of sub-elements that are equal. 88// NumSame is the number of sub-elements that are equal.
89// NDiff is the number of sub-elements that are not equal. 89// NumDiff is the number of sub-elements that are not equal.
90type Result struct{ NSame, NDiff int } 90type Result struct{ NumSame, NumDiff int }
91
92// BoolResult returns a Result that is either Equal or not Equal.
93func BoolResult(b bool) Result {
94 if b {
95 return Result{NumSame: 1} // Equal, Similar
96 } else {
97 return Result{NumDiff: 2} // Not Equal, not Similar
98 }
99}
91 100
92// Equal indicates whether the symbols are equal. Two symbols are equal 101// Equal indicates whether the symbols are equal. Two symbols are equal
93// if and only if NDiff == 0. If Equal, then they are also Similar. 102// if and only if NumDiff == 0. If Equal, then they are also Similar.
94func (r Result) Equal() bool { return r.NDiff == 0 } 103func (r Result) Equal() bool { return r.NumDiff == 0 }
95 104
96// Similar indicates whether two symbols are similar and may be represented 105// Similar indicates whether two symbols are similar and may be represented
97// by using the Modified type. As a special case, we consider binary comparisons 106// by using the Modified type. As a special case, we consider binary comparisons
98// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. 107// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar.
99// 108//
100// The exact ratio of NSame to NDiff to determine similarity may change. 109// The exact ratio of NumSame to NumDiff to determine similarity may change.
101func (r Result) Similar() bool { 110func (r Result) Similar() bool {
102 // Use NSame+1 to offset NSame so that binary comparisons are similar. 111 // Use NumSame+1 to offset NumSame so that binary comparisons are similar.
103 return r.NSame+1 >= r.NDiff 112 return r.NumSame+1 >= r.NumDiff
104} 113}
105 114
106// Difference reports whether two lists of lengths nx and ny are equal 115// Difference reports whether two lists of lengths nx and ny are equal
@@ -191,9 +200,9 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
191 // that two lists commonly differ because elements were added to the front 200 // that two lists commonly differ because elements were added to the front
192 // or end of the other list. 201 // or end of the other list.
193 // 202 //
194 // Running the tests with the "debug" build tag prints a visualization of 203 // Running the tests with the "cmp_debug" build tag prints a visualization
195 // the algorithm running in real-time. This is educational for understanding 204 // of the algorithm running in real-time. This is educational for
196 // how the algorithm works. See debug_enable.go. 205 // understanding how the algorithm works. See debug_enable.go.
197 f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) 206 f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es)
198 for { 207 for {
199 // Forward search from the beginning. 208 // Forward search from the beginning.
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
new file mode 100644
index 0000000..a9e7fc0
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go
@@ -0,0 +1,9 @@
1// Copyright 2019, 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
5package flags
6
7// Deterministic controls whether the output of Diff should be deterministic.
8// This is only used for testing.
9var Deterministic bool
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
new file mode 100644
index 0000000..01aed0a
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go
@@ -0,0 +1,10 @@
1// Copyright 2019, 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
5// +build !go1.10
6
7package flags
8
9// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10.
10const AtLeastGo110 = false
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
new file mode 100644
index 0000000..c0b667f
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go
@@ -0,0 +1,10 @@
1// Copyright 2019, 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
5// +build go1.10
6
7package flags
8
9// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10.
10const AtLeastGo110 = true
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go
index 4c35ff1..ace1dbe 100644
--- a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go
+++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go
@@ -2,25 +2,34 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE.md file. 3// license that can be found in the LICENSE.md file.
4 4
5// Package function identifies function types. 5// Package function provides functionality for identifying function types.
6package function 6package function
7 7
8import "reflect" 8import (
9 "reflect"
10 "regexp"
11 "runtime"
12 "strings"
13)
9 14
10type funcType int 15type funcType int
11 16
12const ( 17const (
13 _ funcType = iota 18 _ funcType = iota
14 19
20 tbFunc // func(T) bool
15 ttbFunc // func(T, T) bool 21 ttbFunc // func(T, T) bool
22 trbFunc // func(T, R) bool
16 tibFunc // func(T, I) bool 23 tibFunc // func(T, I) bool
17 trFunc // func(T) R 24 trFunc // func(T) R
18 25
19 Equal = ttbFunc // func(T, T) bool 26 Equal = ttbFunc // func(T, T) bool
20 EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool 27 EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool
21 Transformer = trFunc // func(T) R 28 Transformer = trFunc // func(T) R
22 ValueFilter = ttbFunc // func(T, T) bool 29 ValueFilter = ttbFunc // func(T, T) bool
23 Less = ttbFunc // func(T, T) bool 30 Less = ttbFunc // func(T, T) bool
31 ValuePredicate = tbFunc // func(T) bool
32 KeyValuePredicate = trbFunc // func(T, R) bool
24) 33)
25 34
26var boolType = reflect.TypeOf(true) 35var boolType = reflect.TypeOf(true)
@@ -32,10 +41,18 @@ func IsType(t reflect.Type, ft funcType) bool {
32 } 41 }
33 ni, no := t.NumIn(), t.NumOut() 42 ni, no := t.NumIn(), t.NumOut()
34 switch ft { 43 switch ft {
44 case tbFunc: // func(T) bool
45 if ni == 1 && no == 1 && t.Out(0) == boolType {
46 return true
47 }
35 case ttbFunc: // func(T, T) bool 48 case ttbFunc: // func(T, T) bool
36 if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { 49 if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType {
37 return true 50 return true
38 } 51 }
52 case trbFunc: // func(T, R) bool
53 if ni == 2 && no == 1 && t.Out(0) == boolType {
54 return true
55 }
39 case tibFunc: // func(T, I) bool 56 case tibFunc: // func(T, I) bool
40 if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { 57 if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType {
41 return true 58 return true
@@ -47,3 +64,36 @@ func IsType(t reflect.Type, ft funcType) bool {
47 } 64 }
48 return false 65 return false
49} 66}
67
68var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`)
69
70// NameOf returns the name of the function value.
71func NameOf(v reflect.Value) string {
72 fnc := runtime.FuncForPC(v.Pointer())
73 if fnc == nil {
74 return "<unknown>"
75 }
76 fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm"
77
78 // Method closures have a "-fm" suffix.
79 fullName = strings.TrimSuffix(fullName, "-fm")
80
81 var name string
82 for len(fullName) > 0 {
83 inParen := strings.HasSuffix(fullName, ")")
84 fullName = strings.TrimSuffix(fullName, ")")
85
86 s := lastIdentRx.FindString(fullName)
87 if s == "" {
88 break
89 }
90 name = s + "." + name
91 fullName = strings.TrimSuffix(fullName, s)
92
93 if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 {
94 fullName = fullName[:i]
95 }
96 fullName = strings.TrimSuffix(fullName, ".")
97 }
98 return strings.TrimSuffix(name, ".")
99}
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/format.go b/vendor/github.com/google/go-cmp/cmp/internal/value/format.go
deleted file mode 100644
index 657e508..0000000
--- a/vendor/github.com/google/go-cmp/cmp/internal/value/format.go
+++ /dev/null
@@ -1,277 +0,0 @@
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
5// Package value provides functionality for reflect.Value types.
6package value
7
8import (
9 "fmt"
10 "reflect"
11 "strconv"
12 "strings"
13 "unicode"
14)
15
16var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
17
18// Format formats the value v as a string.
19//
20// This is similar to fmt.Sprintf("%+v", v) except this:
21// * Prints the type unless it can be elided
22// * Avoids printing struct fields that are zero
23// * Prints a nil-slice as being nil, not empty
24// * Prints map entries in deterministic order
25func Format(v reflect.Value, conf FormatConfig) string {
26 conf.printType = true
27 conf.followPointers = true
28 conf.realPointers = true
29 return formatAny(v, conf, nil)
30}
31
32type FormatConfig struct {
33 UseStringer bool // Should the String method be used if available?
34 printType bool // Should we print the type before the value?
35 PrintPrimitiveType bool // Should we print the type of primitives?
36 followPointers bool // Should we recursively follow pointers?
37 realPointers bool // Should we print the real address of pointers?
38}
39
40func formatAny(v reflect.Value, conf FormatConfig, visited map[uintptr]bool) string {
41 // TODO: Should this be a multi-line printout in certain situations?
42
43 if !v.IsValid() {
44 return "<non-existent>"
45 }
46 if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
47 if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
48 return "<nil>"
49 }
50
51 const stringerPrefix = "s" // Indicates that the String method was used
52 s := v.Interface().(fmt.Stringer).String()
53 return stringerPrefix + formatString(s)
54 }
55
56 switch v.Kind() {
57 case reflect.Bool:
58 return formatPrimitive(v.Type(), v.Bool(), conf)
59 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
60 return formatPrimitive(v.Type(), v.Int(), conf)
61 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
62 if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
63 // Unnamed uints are usually bytes or words, so use hexadecimal.
64 return formatPrimitive(v.Type(), formatHex(v.Uint()), conf)
65 }
66 return formatPrimitive(v.Type(), v.Uint(), conf)
67 case reflect.Float32, reflect.Float64:
68 return formatPrimitive(v.Type(), v.Float(), conf)
69 case reflect.Complex64, reflect.Complex128:
70 return formatPrimitive(v.Type(), v.Complex(), conf)
71 case reflect.String:
72 return formatPrimitive(v.Type(), formatString(v.String()), conf)
73 case reflect.UnsafePointer, reflect.Chan, reflect.Func:
74 return formatPointer(v, conf)
75 case reflect.Ptr:
76 if v.IsNil() {
77 if conf.printType {
78 return fmt.Sprintf("(%v)(nil)", v.Type())
79 }
80 return "<nil>"
81 }
82 if visited[v.Pointer()] || !conf.followPointers {
83 return formatPointer(v, conf)
84 }
85 visited = insertPointer(visited, v.Pointer())
86 return "&" + formatAny(v.Elem(), conf, visited)
87 case reflect.Interface:
88 if v.IsNil() {
89 if conf.printType {
90 return fmt.Sprintf("%v(nil)", v.Type())
91 }
92 return "<nil>"
93 }
94 return formatAny(v.Elem(), conf, visited)
95 case reflect.Slice:
96 if v.IsNil() {
97 if conf.printType {
98 return fmt.Sprintf("%v(nil)", v.Type())
99 }
100 return "<nil>"
101 }
102 if visited[v.Pointer()] {
103 return formatPointer(v, conf)
104 }
105 visited = insertPointer(visited, v.Pointer())
106 fallthrough
107 case reflect.Array:
108 var ss []string
109 subConf := conf
110 subConf.printType = v.Type().Elem().Kind() == reflect.Interface
111 for i := 0; i < v.Len(); i++ {
112 s := formatAny(v.Index(i), subConf, visited)
113 ss = append(ss, s)
114 }
115 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
116 if conf.printType {
117 return v.Type().String() + s
118 }
119 return s
120 case reflect.Map:
121 if v.IsNil() {
122 if conf.printType {
123 return fmt.Sprintf("%v(nil)", v.Type())
124 }
125 return "<nil>"
126 }
127 if visited[v.Pointer()] {
128 return formatPointer(v, conf)
129 }
130 visited = insertPointer(visited, v.Pointer())
131
132 var ss []string
133 keyConf, valConf := conf, conf
134 keyConf.printType = v.Type().Key().Kind() == reflect.Interface
135 keyConf.followPointers = false
136 valConf.printType = v.Type().Elem().Kind() == reflect.Interface
137 for _, k := range SortKeys(v.MapKeys()) {
138 sk := formatAny(k, keyConf, visited)
139 sv := formatAny(v.MapIndex(k), valConf, visited)
140 ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
141 }
142 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
143 if conf.printType {
144 return v.Type().String() + s
145 }
146 return s
147 case reflect.Struct:
148 var ss []string
149 subConf := conf
150 subConf.printType = true
151 for i := 0; i < v.NumField(); i++ {
152 vv := v.Field(i)
153 if isZero(vv) {
154 continue // Elide zero value fields
155 }
156 name := v.Type().Field(i).Name
157 subConf.UseStringer = conf.UseStringer
158 s := formatAny(vv, subConf, visited)
159 ss = append(ss, fmt.Sprintf("%s: %s", name, s))
160 }
161 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
162 if conf.printType {
163 return v.Type().String() + s
164 }
165 return s
166 default:
167 panic(fmt.Sprintf("%v kind not handled", v.Kind()))
168 }
169}
170
171func formatString(s string) string {
172 // Use quoted string if it the same length as a raw string literal.
173 // Otherwise, attempt to use the raw string form.
174 qs := strconv.Quote(s)
175 if len(qs) == 1+len(s)+1 {
176 return qs
177 }
178
179 // Disallow newlines to ensure output is a single line.
180 // Only allow printable runes for readability purposes.
181 rawInvalid := func(r rune) bool {
182 return r == '`' || r == '\n' || !unicode.IsPrint(r)
183 }
184 if strings.IndexFunc(s, rawInvalid) < 0 {
185 return "`" + s + "`"
186 }
187 return qs
188}
189
190func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string {
191 if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") {
192 return fmt.Sprintf("%v(%v)", t, v)
193 }
194 return fmt.Sprintf("%v", v)
195}
196
197func formatPointer(v reflect.Value, conf FormatConfig) string {
198 p := v.Pointer()
199 if !conf.realPointers {
200 p = 0 // For deterministic printing purposes
201 }
202 s := formatHex(uint64(p))
203 if conf.printType {
204 return fmt.Sprintf("(%v)(%s)", v.Type(), s)
205 }
206 return s
207}
208
209func formatHex(u uint64) string {
210 var f string
211 switch {
212 case u <= 0xff:
213 f = "0x%02x"
214 case u <= 0xffff:
215 f = "0x%04x"
216 case u <= 0xffffff:
217 f = "0x%06x"
218 case u <= 0xffffffff:
219 f = "0x%08x"
220 case u <= 0xffffffffff:
221 f = "0x%010x"
222 case u <= 0xffffffffffff:
223 f = "0x%012x"
224 case u <= 0xffffffffffffff:
225 f = "0x%014x"
226 case u <= 0xffffffffffffffff:
227 f = "0x%016x"
228 }
229 return fmt.Sprintf(f, u)
230}
231
232// insertPointer insert p into m, allocating m if necessary.
233func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
234 if m == nil {
235 m = make(map[uintptr]bool)
236 }
237 m[p] = true
238 return m
239}
240
241// isZero reports whether v is the zero value.
242// This does not rely on Interface and so can be used on unexported fields.
243func isZero(v reflect.Value) bool {
244 switch v.Kind() {
245 case reflect.Bool:
246 return v.Bool() == false
247 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
248 return v.Int() == 0
249 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
250 return v.Uint() == 0
251 case reflect.Float32, reflect.Float64:
252 return v.Float() == 0
253 case reflect.Complex64, reflect.Complex128:
254 return v.Complex() == 0
255 case reflect.String:
256 return v.String() == ""
257 case reflect.UnsafePointer:
258 return v.Pointer() == 0
259 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
260 return v.IsNil()
261 case reflect.Array:
262 for i := 0; i < v.Len(); i++ {
263 if !isZero(v.Index(i)) {
264 return false
265 }
266 }
267 return true
268 case reflect.Struct:
269 for i := 0; i < v.NumField(); i++ {
270 if !isZero(v.Field(i)) {
271 return false
272 }
273 }
274 return true
275 }
276 return false
277}
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
new file mode 100644
index 0000000..0a01c47
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go
@@ -0,0 +1,23 @@
1// Copyright 2018, 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
5// +build purego
6
7package value
8
9import "reflect"
10
11// Pointer is an opaque typed pointer and is guaranteed to be comparable.
12type Pointer struct {
13 p uintptr
14 t reflect.Type
15}
16
17// PointerOf returns a Pointer from v, which must be a
18// reflect.Ptr, reflect.Slice, or reflect.Map.
19func PointerOf(v reflect.Value) Pointer {
20 // NOTE: Storing a pointer as an uintptr is technically incorrect as it
21 // assumes that the GC implementation does not use a moving collector.
22 return Pointer{v.Pointer(), v.Type()}
23}
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
new file mode 100644
index 0000000..da134ae
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go
@@ -0,0 +1,26 @@
1// Copyright 2018, 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
5// +build !purego
6
7package value
8
9import (
10 "reflect"
11 "unsafe"
12)
13
14// Pointer is an opaque typed pointer and is guaranteed to be comparable.
15type Pointer struct {
16 p unsafe.Pointer
17 t reflect.Type
18}
19
20// PointerOf returns a Pointer from v, which must be a
21// reflect.Ptr, reflect.Slice, or reflect.Map.
22func PointerOf(v reflect.Value) Pointer {
23 // The proper representation of a pointer is unsafe.Pointer,
24 // which is necessary if the GC ever uses a moving collector.
25 return Pointer{unsafe.Pointer(v.Pointer()), v.Type()}
26}
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
index fe8aa27..938f646 100644
--- a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
+++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go
@@ -19,7 +19,7 @@ func SortKeys(vs []reflect.Value) []reflect.Value {
19 } 19 }
20 20
21 // Sort the map keys. 21 // Sort the map keys.
22 sort.Sort(valueSorter(vs)) 22 sort.Slice(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) })
23 23
24 // Deduplicate keys (fails for NaNs). 24 // Deduplicate keys (fails for NaNs).
25 vs2 := vs[:1] 25 vs2 := vs[:1]
@@ -31,13 +31,6 @@ func SortKeys(vs []reflect.Value) []reflect.Value {
31 return vs2 31 return vs2
32} 32}
33 33
34// TODO: Use sort.Slice once Google AppEngine is on Go1.8 or above.
35type valueSorter []reflect.Value
36
37func (vs valueSorter) Len() int { return len(vs) }
38func (vs valueSorter) Less(i, j int) bool { return isLess(vs[i], vs[j]) }
39func (vs valueSorter) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
40
41// isLess is a generic function for sorting arbitrary map keys. 34// isLess is a generic function for sorting arbitrary map keys.
42// The inputs must be of the same type and must be comparable. 35// The inputs must be of the same type and must be comparable.
43func isLess(x, y reflect.Value) bool { 36func isLess(x, y reflect.Value) bool {
diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
new file mode 100644
index 0000000..d13a12c
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go
@@ -0,0 +1,45 @@
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
5package value
6
7import "reflect"
8
9// IsZero reports whether v is the zero value.
10// This does not rely on Interface and so can be used on unexported fields.
11func IsZero(v reflect.Value) bool {
12 switch v.Kind() {
13 case reflect.Bool:
14 return v.Bool() == false
15 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
16 return v.Int() == 0
17 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
18 return v.Uint() == 0
19 case reflect.Float32, reflect.Float64:
20 return v.Float() == 0
21 case reflect.Complex64, reflect.Complex128:
22 return v.Complex() == 0
23 case reflect.String:
24 return v.String() == ""
25 case reflect.UnsafePointer:
26 return v.Pointer() == 0
27 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
28 return v.IsNil()
29 case reflect.Array:
30 for i := 0; i < v.Len(); i++ {
31 if !IsZero(v.Index(i)) {
32 return false
33 }
34 }
35 return true
36 case reflect.Struct:
37 for i := 0; i < v.NumField(); i++ {
38 if !IsZero(v.Field(i)) {
39 return false
40 }
41 }
42 return true
43 }
44 return false
45}
diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go
index 91d4b06..7934481 100644
--- a/vendor/github.com/google/go-cmp/cmp/options.go
+++ b/vendor/github.com/google/go-cmp/cmp/options.go
@@ -7,7 +7,7 @@ package cmp
7import ( 7import (
8 "fmt" 8 "fmt"
9 "reflect" 9 "reflect"
10 "runtime" 10 "regexp"
11 "strings" 11 "strings"
12 12
13 "github.com/google/go-cmp/cmp/internal/function" 13 "github.com/google/go-cmp/cmp/internal/function"
@@ -29,11 +29,11 @@ type Option interface {
29 // An Options is returned only if multiple comparers or transformers 29 // An Options is returned only if multiple comparers or transformers
30 // can apply simultaneously and will only contain values of those types 30 // can apply simultaneously and will only contain values of those types
31 // or sub-Options containing values of those types. 31 // or sub-Options containing values of those types.
32 filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption 32 filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption
33} 33}
34 34
35// applicableOption represents the following types: 35// applicableOption represents the following types:
36// Fundamental: ignore | invalid | *comparer | *transformer 36// Fundamental: ignore | validator | *comparer | *transformer
37// Grouping: Options 37// Grouping: Options
38type applicableOption interface { 38type applicableOption interface {
39 Option 39 Option
@@ -43,7 +43,7 @@ type applicableOption interface {
43} 43}
44 44
45// coreOption represents the following types: 45// coreOption represents the following types:
46// Fundamental: ignore | invalid | *comparer | *transformer 46// Fundamental: ignore | validator | *comparer | *transformer
47// Filters: *pathFilter | *valuesFilter 47// Filters: *pathFilter | *valuesFilter
48type coreOption interface { 48type coreOption interface {
49 Option 49 Option
@@ -63,19 +63,19 @@ func (core) isCore() {}
63// on all individual options held within. 63// on all individual options held within.
64type Options []Option 64type Options []Option
65 65
66func (opts Options) filter(s *state, vx, vy reflect.Value, t reflect.Type) (out applicableOption) { 66func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) {
67 for _, opt := range opts { 67 for _, opt := range opts {
68 switch opt := opt.filter(s, vx, vy, t); opt.(type) { 68 switch opt := opt.filter(s, t, vx, vy); opt.(type) {
69 case ignore: 69 case ignore:
70 return ignore{} // Only ignore can short-circuit evaluation 70 return ignore{} // Only ignore can short-circuit evaluation
71 case invalid: 71 case validator:
72 out = invalid{} // Takes precedence over comparer or transformer 72 out = validator{} // Takes precedence over comparer or transformer
73 case *comparer, *transformer, Options: 73 case *comparer, *transformer, Options:
74 switch out.(type) { 74 switch out.(type) {
75 case nil: 75 case nil:
76 out = opt 76 out = opt
77 case invalid: 77 case validator:
78 // Keep invalid 78 // Keep validator
79 case *comparer, *transformer, Options: 79 case *comparer, *transformer, Options:
80 out = Options{out, opt} // Conflicting comparers or transformers 80 out = Options{out, opt} // Conflicting comparers or transformers
81 } 81 }
@@ -106,6 +106,11 @@ func (opts Options) String() string {
106// FilterPath returns a new Option where opt is only evaluated if filter f 106// FilterPath returns a new Option where opt is only evaluated if filter f
107// returns true for the current Path in the value tree. 107// returns true for the current Path in the value tree.
108// 108//
109// This filter is called even if a slice element or map entry is missing and
110// provides an opportunity to ignore such cases. The filter function must be
111// symmetric such that the filter result is identical regardless of whether the
112// missing value is from x or y.
113//
109// The option passed in may be an Ignore, Transformer, Comparer, Options, or 114// The option passed in may be an Ignore, Transformer, Comparer, Options, or
110// a previously filtered Option. 115// a previously filtered Option.
111func FilterPath(f func(Path) bool, opt Option) Option { 116func FilterPath(f func(Path) bool, opt Option) Option {
@@ -124,22 +129,22 @@ type pathFilter struct {
124 opt Option 129 opt Option
125} 130}
126 131
127func (f pathFilter) filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption { 132func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption {
128 if f.fnc(s.curPath) { 133 if f.fnc(s.curPath) {
129 return f.opt.filter(s, vx, vy, t) 134 return f.opt.filter(s, t, vx, vy)
130 } 135 }
131 return nil 136 return nil
132} 137}
133 138
134func (f pathFilter) String() string { 139func (f pathFilter) String() string {
135 fn := getFuncName(reflect.ValueOf(f.fnc).Pointer()) 140 return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt)
136 return fmt.Sprintf("FilterPath(%s, %v)", fn, f.opt)
137} 141}
138 142
139// FilterValues returns a new Option where opt is only evaluated if filter f, 143// FilterValues returns a new Option where opt is only evaluated if filter f,
140// which is a function of the form "func(T, T) bool", returns true for the 144// which is a function of the form "func(T, T) bool", returns true for the
141// current pair of values being compared. If the type of the values is not 145// current pair of values being compared. If either value is invalid or
142// assignable to T, then this filter implicitly returns false. 146// the type of the values is not assignable to T, then this filter implicitly
147// returns false.
143// 148//
144// The filter function must be 149// The filter function must be
145// symmetric (i.e., agnostic to the order of the inputs) and 150// symmetric (i.e., agnostic to the order of the inputs) and
@@ -171,19 +176,18 @@ type valuesFilter struct {
171 opt Option 176 opt Option
172} 177}
173 178
174func (f valuesFilter) filter(s *state, vx, vy reflect.Value, t reflect.Type) applicableOption { 179func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption {
175 if !vx.IsValid() || !vy.IsValid() { 180 if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() {
176 return invalid{} 181 return nil
177 } 182 }
178 if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) { 183 if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) {
179 return f.opt.filter(s, vx, vy, t) 184 return f.opt.filter(s, t, vx, vy)
180 } 185 }
181 return nil 186 return nil
182} 187}
183 188
184func (f valuesFilter) String() string { 189func (f valuesFilter) String() string {
185 fn := getFuncName(f.fnc.Pointer()) 190 return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt)
186 return fmt.Sprintf("FilterValues(%s, %v)", fn, f.opt)
187} 191}
188 192
189// Ignore is an Option that causes all comparisons to be ignored. 193// Ignore is an Option that causes all comparisons to be ignored.
@@ -194,20 +198,45 @@ func Ignore() Option { return ignore{} }
194type ignore struct{ core } 198type ignore struct{ core }
195 199
196func (ignore) isFiltered() bool { return false } 200func (ignore) isFiltered() bool { return false }
197func (ignore) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption { return ignore{} } 201func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} }
198func (ignore) apply(_ *state, _, _ reflect.Value) { return } 202func (ignore) apply(s *state, _, _ reflect.Value) { s.report(true, reportByIgnore) }
199func (ignore) String() string { return "Ignore()" } 203func (ignore) String() string { return "Ignore()" }
200 204
201// invalid is a sentinel Option type to indicate that some options could not 205// validator is a sentinel Option type to indicate that some options could not
202// be evaluated due to unexported fields. 206// be evaluated due to unexported fields, missing slice elements, or
203type invalid struct{ core } 207// missing map entries. Both values are validator only for unexported fields.
208type validator struct{ core }
209
210func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption {
211 if !vx.IsValid() || !vy.IsValid() {
212 return validator{}
213 }
214 if !vx.CanInterface() || !vy.CanInterface() {
215 return validator{}
216 }
217 return nil
218}
219func (validator) apply(s *state, vx, vy reflect.Value) {
220 // Implies missing slice element or map entry.
221 if !vx.IsValid() || !vy.IsValid() {
222 s.report(vx.IsValid() == vy.IsValid(), 0)
223 return
224 }
225
226 // Unable to Interface implies unexported field without visibility access.
227 if !vx.CanInterface() || !vy.CanInterface() {
228 const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider AllowUnexported or cmpopts.IgnoreUnexported"
229 panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
230 }
204 231
205func (invalid) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption { return invalid{} } 232 panic("not reachable")
206func (invalid) apply(s *state, _, _ reflect.Value) {
207 const help = "consider using AllowUnexported or cmpopts.IgnoreUnexported"
208 panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
209} 233}
210 234
235// identRx represents a valid identifier according to the Go specification.
236const identRx = `[_\p{L}][_\p{L}\p{N}]*`
237
238var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`)
239
211// Transformer returns an Option that applies a transformation function that 240// Transformer returns an Option that applies a transformation function that
212// converts values of a certain type into that of another. 241// converts values of a certain type into that of another.
213// 242//
@@ -220,18 +249,25 @@ func (invalid) apply(s *state, _, _ reflect.Value) {
220// input and output types are the same), an implicit filter is added such that 249// input and output types are the same), an implicit filter is added such that
221// a transformer is applicable only if that exact transformer is not already 250// a transformer is applicable only if that exact transformer is not already
222// in the tail of the Path since the last non-Transform step. 251// in the tail of the Path since the last non-Transform step.
252// For situations where the implicit filter is still insufficient,
253// consider using cmpopts.AcyclicTransformer, which adds a filter
254// to prevent the transformer from being recursively applied upon itself.
223// 255//
224// The name is a user provided label that is used as the Transform.Name in the 256// The name is a user provided label that is used as the Transform.Name in the
225// transformation PathStep. If empty, an arbitrary name is used. 257// transformation PathStep (and eventually shown in the Diff output).
258// The name must be a valid identifier or qualified identifier in Go syntax.
259// If empty, an arbitrary name is used.
226func Transformer(name string, f interface{}) Option { 260func Transformer(name string, f interface{}) Option {
227 v := reflect.ValueOf(f) 261 v := reflect.ValueOf(f)
228 if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { 262 if !function.IsType(v.Type(), function.Transformer) || v.IsNil() {
229 panic(fmt.Sprintf("invalid transformer function: %T", f)) 263 panic(fmt.Sprintf("invalid transformer function: %T", f))
230 } 264 }
231 if name == "" { 265 if name == "" {
232 name = "λ" // Lambda-symbol as place-holder for anonymous transformer 266 name = function.NameOf(v)
233 } 267 if !identsRx.MatchString(name) {
234 if !isValid(name) { 268 name = "λ" // Lambda-symbol as placeholder name
269 }
270 } else if !identsRx.MatchString(name) {
235 panic(fmt.Sprintf("invalid name: %q", name)) 271 panic(fmt.Sprintf("invalid name: %q", name))
236 } 272 }
237 tr := &transformer{name: name, fnc: reflect.ValueOf(f)} 273 tr := &transformer{name: name, fnc: reflect.ValueOf(f)}
@@ -250,9 +286,9 @@ type transformer struct {
250 286
251func (tr *transformer) isFiltered() bool { return tr.typ != nil } 287func (tr *transformer) isFiltered() bool { return tr.typ != nil }
252 288
253func (tr *transformer) filter(s *state, _, _ reflect.Value, t reflect.Type) applicableOption { 289func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption {
254 for i := len(s.curPath) - 1; i >= 0; i-- { 290 for i := len(s.curPath) - 1; i >= 0; i-- {
255 if t, ok := s.curPath[i].(*transform); !ok { 291 if t, ok := s.curPath[i].(Transform); !ok {
256 break // Hit most recent non-Transform step 292 break // Hit most recent non-Transform step
257 } else if tr == t.trans { 293 } else if tr == t.trans {
258 return nil // Cannot directly use same Transform 294 return nil // Cannot directly use same Transform
@@ -265,18 +301,15 @@ func (tr *transformer) filter(s *state, _, _ reflect.Value, t reflect.Type) appl
265} 301}
266 302
267func (tr *transformer) apply(s *state, vx, vy reflect.Value) { 303func (tr *transformer) apply(s *state, vx, vy reflect.Value) {
268 // Update path before calling the Transformer so that dynamic checks 304 step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}}
269 // will use the updated path. 305 vvx := s.callTRFunc(tr.fnc, vx, step)
270 s.curPath.push(&transform{pathStep{tr.fnc.Type().Out(0)}, tr}) 306 vvy := s.callTRFunc(tr.fnc, vy, step)
271 defer s.curPath.pop() 307 step.vx, step.vy = vvx, vvy
272 308 s.compareAny(step)
273 vx = s.callTRFunc(tr.fnc, vx)
274 vy = s.callTRFunc(tr.fnc, vy)
275 s.compareAny(vx, vy)
276} 309}
277 310
278func (tr transformer) String() string { 311func (tr transformer) String() string {
279 return fmt.Sprintf("Transformer(%s, %s)", tr.name, getFuncName(tr.fnc.Pointer())) 312 return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc))
280} 313}
281 314
282// Comparer returns an Option that determines whether two values are equal 315// Comparer returns an Option that determines whether two values are equal
@@ -311,7 +344,7 @@ type comparer struct {
311 344
312func (cm *comparer) isFiltered() bool { return cm.typ != nil } 345func (cm *comparer) isFiltered() bool { return cm.typ != nil }
313 346
314func (cm *comparer) filter(_ *state, _, _ reflect.Value, t reflect.Type) applicableOption { 347func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption {
315 if cm.typ == nil || t.AssignableTo(cm.typ) { 348 if cm.typ == nil || t.AssignableTo(cm.typ) {
316 return cm 349 return cm
317 } 350 }
@@ -320,11 +353,11 @@ func (cm *comparer) filter(_ *state, _, _ reflect.Value, t reflect.Type) applica
320 353
321func (cm *comparer) apply(s *state, vx, vy reflect.Value) { 354func (cm *comparer) apply(s *state, vx, vy reflect.Value) {
322 eq := s.callTTBFunc(cm.fnc, vx, vy) 355 eq := s.callTTBFunc(cm.fnc, vx, vy)
323 s.report(eq, vx, vy) 356 s.report(eq, reportByFunc)
324} 357}
325 358
326func (cm comparer) String() string { 359func (cm comparer) String() string {
327 return fmt.Sprintf("Comparer(%s)", getFuncName(cm.fnc.Pointer())) 360 return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc))
328} 361}
329 362
330// AllowUnexported returns an Option that forcibly allows operations on 363// AllowUnexported returns an Option that forcibly allows operations on
@@ -338,7 +371,7 @@ func (cm comparer) String() string {
338// defined in an internal package where the semantic meaning of an unexported 371// defined in an internal package where the semantic meaning of an unexported
339// field is in the control of the user. 372// field is in the control of the user.
340// 373//
341// For some cases, a custom Comparer should be used instead that defines 374// In many cases, a custom Comparer should be used instead that defines
342// equality as a function of the public API of a type rather than the underlying 375// equality as a function of the public API of a type rather than the underlying
343// unexported implementation. 376// unexported implementation.
344// 377//
@@ -370,27 +403,92 @@ func AllowUnexported(types ...interface{}) Option {
370 403
371type visibleStructs map[reflect.Type]bool 404type visibleStructs map[reflect.Type]bool
372 405
373func (visibleStructs) filter(_ *state, _, _ reflect.Value, _ reflect.Type) applicableOption { 406func (visibleStructs) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
374 panic("not implemented") 407 panic("not implemented")
375} 408}
376 409
377// reporter is an Option that configures how differences are reported. 410// Result represents the comparison result for a single node and
378type reporter interface { 411// is provided by cmp when calling Result (see Reporter).
379 // TODO: Not exported yet. 412type Result struct {
413 _ [0]func() // Make Result incomparable
414 flags resultFlags
415}
416
417// Equal reports whether the node was determined to be equal or not.
418// As a special case, ignored nodes are considered equal.
419func (r Result) Equal() bool {
420 return r.flags&(reportEqual|reportByIgnore) != 0
421}
422
423// ByIgnore reports whether the node is equal because it was ignored.
424// This never reports true if Equal reports false.
425func (r Result) ByIgnore() bool {
426 return r.flags&reportByIgnore != 0
427}
428
429// ByMethod reports whether the Equal method determined equality.
430func (r Result) ByMethod() bool {
431 return r.flags&reportByMethod != 0
432}
433
434// ByFunc reports whether a Comparer function determined equality.
435func (r Result) ByFunc() bool {
436 return r.flags&reportByFunc != 0
437}
438
439type resultFlags uint
440
441const (
442 _ resultFlags = (1 << iota) / 2
443
444 reportEqual
445 reportUnequal
446 reportByIgnore
447 reportByMethod
448 reportByFunc
449)
450
451// Reporter is an Option that can be passed to Equal. When Equal traverses
452// the value trees, it calls PushStep as it descends into each node in the
453// tree and PopStep as it ascend out of the node. The leaves of the tree are
454// either compared (determined to be equal or not equal) or ignored and reported
455// as such by calling the Report method.
456func Reporter(r interface {
457 // PushStep is called when a tree-traversal operation is performed.
458 // The PathStep itself is only valid until the step is popped.
459 // The PathStep.Values are valid for the duration of the entire traversal
460 // and must not be mutated.
461 //
462 // Equal always calls PushStep at the start to provide an operation-less
463 // PathStep used to report the root values.
380 // 464 //
381 // Perhaps add PushStep and PopStep and change Report to only accept 465 // Within a slice, the exact set of inserted, removed, or modified elements
382 // a PathStep instead of the full-path? Adding a PushStep and PopStep makes 466 // is unspecified and may change in future implementations.
383 // it clear that we are traversing the value tree in a depth-first-search 467 // The entries of a map are iterated through in an unspecified order.
384 // manner, which has an effect on how values are printed. 468 PushStep(PathStep)
469
470 // Report is called exactly once on leaf nodes to report whether the
471 // comparison identified the node as equal, unequal, or ignored.
472 // A leaf node is one that is immediately preceded by and followed by
473 // a pair of PushStep and PopStep calls.
474 Report(Result)
475
476 // PopStep ascends back up the value tree.
477 // There is always a matching pop call for every push call.
478 PopStep()
479}) Option {
480 return reporter{r}
481}
385 482
386 Option 483type reporter struct{ reporterIface }
484type reporterIface interface {
485 PushStep(PathStep)
486 Report(Result)
487 PopStep()
488}
387 489
388 // Report is called for every comparison made and will be provided with 490func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
389 // the two values being compared, the equality result, and the 491 panic("not implemented")
390 // current path in the value tree. It is possible for x or y to be an
391 // invalid reflect.Value if one of the values is non-existent;
392 // which is possible with maps and slices.
393 Report(x, y reflect.Value, eq bool, p Path)
394} 492}
395 493
396// normalizeOption normalizes the input options such that all Options groups 494// normalizeOption normalizes the input options such that all Options groups
@@ -424,30 +522,3 @@ func flattenOptions(dst, src Options) Options {
424 } 522 }
425 return dst 523 return dst
426} 524}
427
428// getFuncName returns a short function name from the pointer.
429// The string parsing logic works up until Go1.9.
430func getFuncName(p uintptr) string {
431 fnc := runtime.FuncForPC(p)
432 if fnc == nil {
433 return "<unknown>"
434 }
435 name := fnc.Name() // E.g., "long/path/name/mypkg.(mytype).(long/path/name/mypkg.myfunc)-fm"
436 if strings.HasSuffix(name, ")-fm") || strings.HasSuffix(name, ")·fm") {
437 // Strip the package name from method name.
438 name = strings.TrimSuffix(name, ")-fm")
439 name = strings.TrimSuffix(name, ")·fm")
440 if i := strings.LastIndexByte(name, '('); i >= 0 {
441 methodName := name[i+1:] // E.g., "long/path/name/mypkg.myfunc"
442 if j := strings.LastIndexByte(methodName, '.'); j >= 0 {
443 methodName = methodName[j+1:] // E.g., "myfunc"
444 }
445 name = name[:i] + methodName // E.g., "long/path/name/mypkg.(mytype)." + "myfunc"
446 }
447 }
448 if i := strings.LastIndexByte(name, '/'); i >= 0 {
449 // Strip the package name.
450 name = name[i+1:] // E.g., "mypkg.(mytype).myfunc"
451 }
452 return name
453}
diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go
index c08a3cf..96fffd2 100644
--- a/vendor/github.com/google/go-cmp/cmp/path.go
+++ b/vendor/github.com/google/go-cmp/cmp/path.go
@@ -12,80 +12,52 @@ import (
12 "unicode/utf8" 12 "unicode/utf8"
13) 13)
14 14
15type ( 15// Path is a list of PathSteps describing the sequence of operations to get
16 // Path is a list of PathSteps describing the sequence of operations to get 16// from some root type to the current position in the value tree.
17 // from some root type to the current position in the value tree. 17// The first Path element is always an operation-less PathStep that exists
18 // The first Path element is always an operation-less PathStep that exists 18// simply to identify the initial type.
19 // simply to identify the initial type. 19//
20 // 20// When traversing structs with embedded structs, the embedded struct will
21 // When traversing structs with embedded structs, the embedded struct will 21// always be accessed as a field before traversing the fields of the
22 // always be accessed as a field before traversing the fields of the 22// embedded struct themselves. That is, an exported field from the
23 // embedded struct themselves. That is, an exported field from the 23// embedded struct will never be accessed directly from the parent struct.
24 // embedded struct will never be accessed directly from the parent struct. 24type Path []PathStep
25 Path []PathStep
26
27 // PathStep is a union-type for specific operations to traverse
28 // a value's tree structure. Users of this package never need to implement
29 // these types as values of this type will be returned by this package.
30 PathStep interface {
31 String() string
32 Type() reflect.Type // Resulting type after performing the path step
33 isPathStep()
34 }
35 25
36 // SliceIndex is an index operation on a slice or array at some index Key. 26// PathStep is a union-type for specific operations to traverse
37 SliceIndex interface { 27// a value's tree structure. Users of this package never need to implement
38 PathStep 28// these types as values of this type will be returned by this package.
39 Key() int // May return -1 if in a split state 29//
40 30// Implementations of this interface are
41 // SplitKeys returns the indexes for indexing into slices in the 31// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform.
42 // x and y values, respectively. These indexes may differ due to the 32type PathStep interface {
43 // insertion or removal of an element in one of the slices, causing 33 String() string
44 // all of the indexes to be shifted. If an index is -1, then that
45 // indicates that the element does not exist in the associated slice.
46 //
47 // Key is guaranteed to return -1 if and only if the indexes returned
48 // by SplitKeys are not the same. SplitKeys will never return -1 for
49 // both indexes.
50 SplitKeys() (x int, y int)
51
52 isSliceIndex()
53 }
54 // MapIndex is an index operation on a map at some index Key.
55 MapIndex interface {
56 PathStep
57 Key() reflect.Value
58 isMapIndex()
59 }
60 // TypeAssertion represents a type assertion on an interface.
61 TypeAssertion interface {
62 PathStep
63 isTypeAssertion()
64 }
65 // StructField represents a struct field access on a field called Name.
66 StructField interface {
67 PathStep
68 Name() string
69 Index() int
70 isStructField()
71 }
72 // Indirect represents pointer indirection on the parent type.
73 Indirect interface {
74 PathStep
75 isIndirect()
76 }
77 // Transform is a transformation from the parent type to the current type.
78 Transform interface {
79 PathStep
80 Name() string
81 Func() reflect.Value
82 34
83 // Option returns the originally constructed Transformer option. 35 // Type is the resulting type after performing the path step.
84 // The == operator can be used to detect the exact option used. 36 Type() reflect.Type
85 Option() Option
86 37
87 isTransform() 38 // Values is the resulting values after performing the path step.
88 } 39 // The type of each valid value is guaranteed to be identical to Type.
40 //
41 // In some cases, one or both may be invalid or have restrictions:
42 // • For StructField, both are not interface-able if the current field
43 // is unexported and the struct type is not explicitly permitted by
44 // AllowUnexported to traverse unexported fields.
45 // • For SliceIndex, one may be invalid if an element is missing from
46 // either the x or y slice.
47 // • For MapIndex, one may be invalid if an entry is missing from
48 // either the x or y map.
49 //
50 // The provided values must not be mutated.
51 Values() (vx, vy reflect.Value)
52}
53
54var (
55 _ PathStep = StructField{}
56 _ PathStep = SliceIndex{}
57 _ PathStep = MapIndex{}
58 _ PathStep = Indirect{}
59 _ PathStep = TypeAssertion{}
60 _ PathStep = Transform{}
89) 61)
90 62
91func (pa *Path) push(s PathStep) { 63func (pa *Path) push(s PathStep) {
@@ -124,7 +96,7 @@ func (pa Path) Index(i int) PathStep {
124func (pa Path) String() string { 96func (pa Path) String() string {
125 var ss []string 97 var ss []string
126 for _, s := range pa { 98 for _, s := range pa {
127 if _, ok := s.(*structField); ok { 99 if _, ok := s.(StructField); ok {
128 ss = append(ss, s.String()) 100 ss = append(ss, s.String())
129 } 101 }
130 } 102 }
@@ -144,13 +116,13 @@ func (pa Path) GoString() string {
144 nextStep = pa[i+1] 116 nextStep = pa[i+1]
145 } 117 }
146 switch s := s.(type) { 118 switch s := s.(type) {
147 case *indirect: 119 case Indirect:
148 numIndirect++ 120 numIndirect++
149 pPre, pPost := "(", ")" 121 pPre, pPost := "(", ")"
150 switch nextStep.(type) { 122 switch nextStep.(type) {
151 case *indirect: 123 case Indirect:
152 continue // Next step is indirection, so let them batch up 124 continue // Next step is indirection, so let them batch up
153 case *structField: 125 case StructField:
154 numIndirect-- // Automatic indirection on struct fields 126 numIndirect-- // Automatic indirection on struct fields
155 case nil: 127 case nil:
156 pPre, pPost = "", "" // Last step; no need for parenthesis 128 pPre, pPost = "", "" // Last step; no need for parenthesis
@@ -161,19 +133,10 @@ func (pa Path) GoString() string {
161 } 133 }
162 numIndirect = 0 134 numIndirect = 0
163 continue 135 continue
164 case *transform: 136 case Transform:
165 ssPre = append(ssPre, s.trans.name+"(") 137 ssPre = append(ssPre, s.trans.name+"(")
166 ssPost = append(ssPost, ")") 138 ssPost = append(ssPost, ")")
167 continue 139 continue
168 case *typeAssertion:
169 // As a special-case, elide type assertions on anonymous types
170 // since they are typically generated dynamically and can be very
171 // verbose. For example, some transforms return interface{} because
172 // of Go's lack of generics, but typically take in and return the
173 // exact same concrete type.
174 if s.Type().PkgPath() == "" {
175 continue
176 }
177 } 140 }
178 ssPost = append(ssPost, s.String()) 141 ssPost = append(ssPost, s.String())
179 } 142 }
@@ -183,44 +146,13 @@ func (pa Path) GoString() string {
183 return strings.Join(ssPre, "") + strings.Join(ssPost, "") 146 return strings.Join(ssPre, "") + strings.Join(ssPost, "")
184} 147}
185 148
186type ( 149type pathStep struct {
187 pathStep struct { 150 typ reflect.Type
188 typ reflect.Type 151 vx, vy reflect.Value
189 } 152}
190
191 sliceIndex struct {
192 pathStep
193 xkey, ykey int
194 }
195 mapIndex struct {
196 pathStep
197 key reflect.Value
198 }
199 typeAssertion struct {
200 pathStep
201 }
202 structField struct {
203 pathStep
204 name string
205 idx int
206
207 // These fields are used for forcibly accessing an unexported field.
208 // pvx, pvy, and field are only valid if unexported is true.
209 unexported bool
210 force bool // Forcibly allow visibility
211 pvx, pvy reflect.Value // Parent values
212 field reflect.StructField // Field information
213 }
214 indirect struct {
215 pathStep
216 }
217 transform struct {
218 pathStep
219 trans *transformer
220 }
221)
222 153
223func (ps pathStep) Type() reflect.Type { return ps.typ } 154func (ps pathStep) Type() reflect.Type { return ps.typ }
155func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy }
224func (ps pathStep) String() string { 156func (ps pathStep) String() string {
225 if ps.typ == nil { 157 if ps.typ == nil {
226 return "<nil>" 158 return "<nil>"
@@ -232,7 +164,54 @@ func (ps pathStep) String() string {
232 return fmt.Sprintf("{%s}", s) 164 return fmt.Sprintf("{%s}", s)
233} 165}
234 166
235func (si sliceIndex) String() string { 167// StructField represents a struct field access on a field called Name.
168type StructField struct{ *structField }
169type structField struct {
170 pathStep
171 name string
172 idx int
173
174 // These fields are used for forcibly accessing an unexported field.
175 // pvx, pvy, and field are only valid if unexported is true.
176 unexported bool
177 mayForce bool // Forcibly allow visibility
178 pvx, pvy reflect.Value // Parent values
179 field reflect.StructField // Field information
180}
181
182func (sf StructField) Type() reflect.Type { return sf.typ }
183func (sf StructField) Values() (vx, vy reflect.Value) {
184 if !sf.unexported {
185 return sf.vx, sf.vy // CanInterface reports true
186 }
187
188 // Forcibly obtain read-write access to an unexported struct field.
189 if sf.mayForce {
190 vx = retrieveUnexportedField(sf.pvx, sf.field)
191 vy = retrieveUnexportedField(sf.pvy, sf.field)
192 return vx, vy // CanInterface reports true
193 }
194 return sf.vx, sf.vy // CanInterface reports false
195}
196func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) }
197
198// Name is the field name.
199func (sf StructField) Name() string { return sf.name }
200
201// Index is the index of the field in the parent struct type.
202// See reflect.Type.Field.
203func (sf StructField) Index() int { return sf.idx }
204
205// SliceIndex is an index operation on a slice or array at some index Key.
206type SliceIndex struct{ *sliceIndex }
207type sliceIndex struct {
208 pathStep
209 xkey, ykey int
210}
211
212func (si SliceIndex) Type() reflect.Type { return si.typ }
213func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy }
214func (si SliceIndex) String() string {
236 switch { 215 switch {
237 case si.xkey == si.ykey: 216 case si.xkey == si.ykey:
238 return fmt.Sprintf("[%d]", si.xkey) 217 return fmt.Sprintf("[%d]", si.xkey)
@@ -247,63 +226,83 @@ func (si sliceIndex) String() string {
247 return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) 226 return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
248 } 227 }
249} 228}
250func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
251func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
252func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
253func (in indirect) String() string { return "*" }
254func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
255 229
256func (si sliceIndex) Key() int { 230// Key is the index key; it may return -1 if in a split state
231func (si SliceIndex) Key() int {
257 if si.xkey != si.ykey { 232 if si.xkey != si.ykey {
258 return -1 233 return -1
259 } 234 }
260 return si.xkey 235 return si.xkey
261} 236}
262func (si sliceIndex) SplitKeys() (x, y int) { return si.xkey, si.ykey }
263func (mi mapIndex) Key() reflect.Value { return mi.key }
264func (sf structField) Name() string { return sf.name }
265func (sf structField) Index() int { return sf.idx }
266func (tf transform) Name() string { return tf.trans.name }
267func (tf transform) Func() reflect.Value { return tf.trans.fnc }
268func (tf transform) Option() Option { return tf.trans }
269
270func (pathStep) isPathStep() {}
271func (sliceIndex) isSliceIndex() {}
272func (mapIndex) isMapIndex() {}
273func (typeAssertion) isTypeAssertion() {}
274func (structField) isStructField() {}
275func (indirect) isIndirect() {}
276func (transform) isTransform() {}
277 237
278var ( 238// SplitKeys are the indexes for indexing into slices in the
279 _ SliceIndex = sliceIndex{} 239// x and y values, respectively. These indexes may differ due to the
280 _ MapIndex = mapIndex{} 240// insertion or removal of an element in one of the slices, causing
281 _ TypeAssertion = typeAssertion{} 241// all of the indexes to be shifted. If an index is -1, then that
282 _ StructField = structField{} 242// indicates that the element does not exist in the associated slice.
283 _ Indirect = indirect{} 243//
284 _ Transform = transform{} 244// Key is guaranteed to return -1 if and only if the indexes returned
285 245// by SplitKeys are not the same. SplitKeys will never return -1 for
286 _ PathStep = sliceIndex{} 246// both indexes.
287 _ PathStep = mapIndex{} 247func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey }
288 _ PathStep = typeAssertion{} 248
289 _ PathStep = structField{} 249// MapIndex is an index operation on a map at some index Key.
290 _ PathStep = indirect{} 250type MapIndex struct{ *mapIndex }
291 _ PathStep = transform{} 251type mapIndex struct {
292) 252 pathStep
253 key reflect.Value
254}
255
256func (mi MapIndex) Type() reflect.Type { return mi.typ }
257func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy }
258func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
259
260// Key is the value of the map key.
261func (mi MapIndex) Key() reflect.Value { return mi.key }
262
263// Indirect represents pointer indirection on the parent type.
264type Indirect struct{ *indirect }
265type indirect struct {
266 pathStep
267}
268
269func (in Indirect) Type() reflect.Type { return in.typ }
270func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy }
271func (in Indirect) String() string { return "*" }
272
273// TypeAssertion represents a type assertion on an interface.
274type TypeAssertion struct{ *typeAssertion }
275type typeAssertion struct {
276 pathStep
277}
278
279func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
280func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
281func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
282
283// Transform is a transformation from the parent type to the current type.
284type Transform struct{ *transform }
285type transform struct {
286 pathStep
287 trans *transformer
288}
289
290func (tf Transform) Type() reflect.Type { return tf.typ }
291func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy }
292func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
293
294// Name is the name of the Transformer.
295func (tf Transform) Name() string { return tf.trans.name }
296
297// Func is the function pointer to the transformer function.
298func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
299
300// Option returns the originally constructed Transformer option.
301// The == operator can be used to detect the exact option used.
302func (tf Transform) Option() Option { return tf.trans }
293 303
294// isExported reports whether the identifier is exported. 304// isExported reports whether the identifier is exported.
295func isExported(id string) bool { 305func isExported(id string) bool {
296 r, _ := utf8.DecodeRuneInString(id) 306 r, _ := utf8.DecodeRuneInString(id)
297 return unicode.IsUpper(r) 307 return unicode.IsUpper(r)
298} 308}
299
300// isValid reports whether the identifier is valid.
301// Empty and underscore-only strings are not valid.
302func isValid(id string) bool {
303 ok := id != "" && id != "_"
304 for j, c := range id {
305 ok = ok && (j > 0 || !unicode.IsDigit(c))
306 ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
307 }
308 return ok
309}
diff --git a/vendor/github.com/google/go-cmp/cmp/report.go b/vendor/github.com/google/go-cmp/cmp/report.go
new file mode 100644
index 0000000..6ddf299
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report.go
@@ -0,0 +1,51 @@
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
5package cmp
6
7// defaultReporter implements the reporter interface.
8//
9// As Equal serially calls the PushStep, Report, and PopStep methods, the
10// defaultReporter constructs a tree-based representation of the compared value
11// and the result of each comparison (see valueNode).
12//
13// When the String method is called, the FormatDiff method transforms the
14// valueNode tree into a textNode tree, which is a tree-based representation
15// of the textual output (see textNode).
16//
17// Lastly, the textNode.String method produces the final report as a string.
18type defaultReporter struct {
19 root *valueNode
20 curr *valueNode
21}
22
23func (r *defaultReporter) PushStep(ps PathStep) {
24 r.curr = r.curr.PushStep(ps)
25 if r.root == nil {
26 r.root = r.curr
27 }
28}
29func (r *defaultReporter) Report(rs Result) {
30 r.curr.Report(rs)
31}
32func (r *defaultReporter) PopStep() {
33 r.curr = r.curr.PopStep()
34}
35
36// String provides a full report of the differences detected as a structured
37// literal in pseudo-Go syntax. String may only be called after the entire tree
38// has been traversed.
39func (r *defaultReporter) String() string {
40 assert(r.root != nil && r.curr == nil)
41 if r.root.NumDiff == 0 {
42 return ""
43 }
44 return formatOptions{}.FormatDiff(r.root).String()
45}
46
47func assert(ok bool) {
48 if !ok {
49 panic("assertion failure")
50 }
51}
diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go
new file mode 100644
index 0000000..05efb99
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go
@@ -0,0 +1,296 @@
1// Copyright 2019, 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
5package cmp
6
7import (
8 "fmt"
9 "reflect"
10
11 "github.com/google/go-cmp/cmp/internal/value"
12)
13
14// TODO: Enforce limits?
15// * Enforce maximum number of records to print per node?
16// * Enforce maximum size in bytes allowed?
17// * As a heuristic, use less verbosity for equal nodes than unequal nodes.
18// TODO: Enforce unique outputs?
19// * Avoid Stringer methods if it results in same output?
20// * Print pointer address if outputs still equal?
21
22// numContextRecords is the number of surrounding equal records to print.
23const numContextRecords = 2
24
25type diffMode byte
26
27const (
28 diffUnknown diffMode = 0
29 diffIdentical diffMode = ' '
30 diffRemoved diffMode = '-'
31 diffInserted diffMode = '+'
32)
33
34type typeMode int
35
36const (
37 // emitType always prints the type.
38 emitType typeMode = iota
39 // elideType never prints the type.
40 elideType
41 // autoType prints the type only for composite kinds
42 // (i.e., structs, slices, arrays, and maps).
43 autoType
44)
45
46type formatOptions struct {
47 // DiffMode controls the output mode of FormatDiff.
48 //
49 // If diffUnknown, then produce a diff of the x and y values.
50 // If diffIdentical, then emit values as if they were equal.
51 // If diffRemoved, then only emit x values (ignoring y values).
52 // If diffInserted, then only emit y values (ignoring x values).
53 DiffMode diffMode
54
55 // TypeMode controls whether to print the type for the current node.
56 //
57 // As a general rule of thumb, we always print the type of the next node
58 // after an interface, and always elide the type of the next node after
59 // a slice or map node.
60 TypeMode typeMode
61
62 // formatValueOptions are options specific to printing reflect.Values.
63 formatValueOptions
64}
65
66func (opts formatOptions) WithDiffMode(d diffMode) formatOptions {
67 opts.DiffMode = d
68 return opts
69}
70func (opts formatOptions) WithTypeMode(t typeMode) formatOptions {
71 opts.TypeMode = t
72 return opts
73}
74
75// FormatDiff converts a valueNode tree into a textNode tree, where the later
76// is a textual representation of the differences detected in the former.
77func (opts formatOptions) FormatDiff(v *valueNode) textNode {
78 // Check whether we have specialized formatting for this node.
79 // This is not necessary, but helpful for producing more readable outputs.
80 if opts.CanFormatDiffSlice(v) {
81 return opts.FormatDiffSlice(v)
82 }
83
84 // For leaf nodes, format the value based on the reflect.Values alone.
85 if v.MaxDepth == 0 {
86 switch opts.DiffMode {
87 case diffUnknown, diffIdentical:
88 // Format Equal.
89 if v.NumDiff == 0 {
90 outx := opts.FormatValue(v.ValueX, visitedPointers{})
91 outy := opts.FormatValue(v.ValueY, visitedPointers{})
92 if v.NumIgnored > 0 && v.NumSame == 0 {
93 return textEllipsis
94 } else if outx.Len() < outy.Len() {
95 return outx
96 } else {
97 return outy
98 }
99 }
100
101 // Format unequal.
102 assert(opts.DiffMode == diffUnknown)
103 var list textList
104 outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{})
105 outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{})
106 if outx != nil {
107 list = append(list, textRecord{Diff: '-', Value: outx})
108 }
109 if outy != nil {
110 list = append(list, textRecord{Diff: '+', Value: outy})
111 }
112 return opts.WithTypeMode(emitType).FormatType(v.Type, list)
113 case diffRemoved:
114 return opts.FormatValue(v.ValueX, visitedPointers{})
115 case diffInserted:
116 return opts.FormatValue(v.ValueY, visitedPointers{})
117 default:
118 panic("invalid diff mode")
119 }
120 }
121
122 // Descend into the child value node.
123 if v.TransformerName != "" {
124 out := opts.WithTypeMode(emitType).FormatDiff(v.Value)
125 out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"}
126 return opts.FormatType(v.Type, out)
127 } else {
128 switch k := v.Type.Kind(); k {
129 case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map:
130 return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k))
131 case reflect.Ptr:
132 return textWrap{"&", opts.FormatDiff(v.Value), ""}
133 case reflect.Interface:
134 return opts.WithTypeMode(emitType).FormatDiff(v.Value)
135 default:
136 panic(fmt.Sprintf("%v cannot have children", k))
137 }
138 }
139}
140
141func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode {
142 // Derive record name based on the data structure kind.
143 var name string
144 var formatKey func(reflect.Value) string
145 switch k {
146 case reflect.Struct:
147 name = "field"
148 opts = opts.WithTypeMode(autoType)
149 formatKey = func(v reflect.Value) string { return v.String() }
150 case reflect.Slice, reflect.Array:
151 name = "element"
152 opts = opts.WithTypeMode(elideType)
153 formatKey = func(reflect.Value) string { return "" }
154 case reflect.Map:
155 name = "entry"
156 opts = opts.WithTypeMode(elideType)
157 formatKey = formatMapKey
158 }
159
160 // Handle unification.
161 switch opts.DiffMode {
162 case diffIdentical, diffRemoved, diffInserted:
163 var list textList
164 var deferredEllipsis bool // Add final "..." to indicate records were dropped
165 for _, r := range recs {
166 // Elide struct fields that are zero value.
167 if k == reflect.Struct {
168 var isZero bool
169 switch opts.DiffMode {
170 case diffIdentical:
171 isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueX)
172 case diffRemoved:
173 isZero = value.IsZero(r.Value.ValueX)
174 case diffInserted:
175 isZero = value.IsZero(r.Value.ValueY)
176 }
177 if isZero {
178 continue
179 }
180 }
181 // Elide ignored nodes.
182 if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 {
183 deferredEllipsis = !(k == reflect.Slice || k == reflect.Array)
184 if !deferredEllipsis {
185 list.AppendEllipsis(diffStats{})
186 }
187 continue
188 }
189 if out := opts.FormatDiff(r.Value); out != nil {
190 list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
191 }
192 }
193 if deferredEllipsis {
194 list.AppendEllipsis(diffStats{})
195 }
196 return textWrap{"{", list, "}"}
197 case diffUnknown:
198 default:
199 panic("invalid diff mode")
200 }
201
202 // Handle differencing.
203 var list textList
204 groups := coalesceAdjacentRecords(name, recs)
205 for i, ds := range groups {
206 // Handle equal records.
207 if ds.NumDiff() == 0 {
208 // Compute the number of leading and trailing records to print.
209 var numLo, numHi int
210 numEqual := ds.NumIgnored + ds.NumIdentical
211 for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 {
212 if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
213 break
214 }
215 numLo++
216 }
217 for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 {
218 if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 {
219 break
220 }
221 numHi++
222 }
223 if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 {
224 numHi++ // Avoid pointless coalescing of a single equal record
225 }
226
227 // Format the equal values.
228 for _, r := range recs[:numLo] {
229 out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value)
230 list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
231 }
232 if numEqual > numLo+numHi {
233 ds.NumIdentical -= numLo + numHi
234 list.AppendEllipsis(ds)
235 }
236 for _, r := range recs[numEqual-numHi : numEqual] {
237 out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value)
238 list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
239 }
240 recs = recs[numEqual:]
241 continue
242 }
243
244 // Handle unequal records.
245 for _, r := range recs[:ds.NumDiff()] {
246 switch {
247 case opts.CanFormatDiffSlice(r.Value):
248 out := opts.FormatDiffSlice(r.Value)
249 list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
250 case r.Value.NumChildren == r.Value.MaxDepth:
251 outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value)
252 outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value)
253 if outx != nil {
254 list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
255 }
256 if outy != nil {
257 list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
258 }
259 default:
260 out := opts.FormatDiff(r.Value)
261 list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
262 }
263 }
264 recs = recs[ds.NumDiff():]
265 }
266 assert(len(recs) == 0)
267 return textWrap{"{", list, "}"}
268}
269
270// coalesceAdjacentRecords coalesces the list of records into groups of
271// adjacent equal, or unequal counts.
272func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) {
273 var prevCase int // Arbitrary index into which case last occurred
274 lastStats := func(i int) *diffStats {
275 if prevCase != i {
276 groups = append(groups, diffStats{Name: name})
277 prevCase = i
278 }
279 return &groups[len(groups)-1]
280 }
281 for _, r := range recs {
282 switch rv := r.Value; {
283 case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0:
284 lastStats(1).NumIgnored++
285 case rv.NumDiff == 0:
286 lastStats(1).NumIdentical++
287 case rv.NumDiff > 0 && !rv.ValueY.IsValid():
288 lastStats(2).NumRemoved++
289 case rv.NumDiff > 0 && !rv.ValueX.IsValid():
290 lastStats(2).NumInserted++
291 default:
292 lastStats(2).NumModified++
293 }
294 }
295 return groups
296}
diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go
new file mode 100644
index 0000000..5521c60
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go
@@ -0,0 +1,279 @@
1// Copyright 2019, 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
5package cmp
6
7import (
8 "fmt"
9 "reflect"
10 "strconv"
11 "strings"
12 "unicode"
13
14 "github.com/google/go-cmp/cmp/internal/flags"
15 "github.com/google/go-cmp/cmp/internal/value"
16)
17
18type formatValueOptions struct {
19 // AvoidStringer controls whether to avoid calling custom stringer
20 // methods like error.Error or fmt.Stringer.String.
21 AvoidStringer bool
22
23 // ShallowPointers controls whether to avoid descending into pointers.
24 // Useful when printing map keys, where pointer comparison is performed
25 // on the pointer address rather than the pointed-at value.
26 ShallowPointers bool
27
28 // PrintAddresses controls whether to print the address of all pointers,
29 // slice elements, and maps.
30 PrintAddresses bool
31}
32
33// FormatType prints the type as if it were wrapping s.
34// This may return s as-is depending on the current type and TypeMode mode.
35func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
36 // Check whether to emit the type or not.
37 switch opts.TypeMode {
38 case autoType:
39 switch t.Kind() {
40 case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map:
41 if s.Equal(textNil) {
42 return s
43 }
44 default:
45 return s
46 }
47 case elideType:
48 return s
49 }
50
51 // Determine the type label, applying special handling for unnamed types.
52 typeName := t.String()
53 if t.Name() == "" {
54 // According to Go grammar, certain type literals contain symbols that
55 // do not strongly bind to the next lexicographical token (e.g., *T).
56 switch t.Kind() {
57 case reflect.Chan, reflect.Func, reflect.Ptr:
58 typeName = "(" + typeName + ")"
59 }
60 typeName = strings.Replace(typeName, "struct {", "struct{", -1)
61 typeName = strings.Replace(typeName, "interface {", "interface{", -1)
62 }
63
64 // Avoid wrap the value in parenthesis if unnecessary.
65 if s, ok := s.(textWrap); ok {
66 hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")")
67 hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}")
68 if hasParens || hasBraces {
69 return textWrap{typeName, s, ""}
70 }
71 }
72 return textWrap{typeName + "(", s, ")"}
73}
74
75// FormatValue prints the reflect.Value, taking extra care to avoid descending
76// into pointers already in m. As pointers are visited, m is also updated.
77func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) {
78 if !v.IsValid() {
79 return nil
80 }
81 t := v.Type()
82
83 // Check whether there is an Error or String method to call.
84 if !opts.AvoidStringer && v.CanInterface() {
85 // Avoid calling Error or String methods on nil receivers since many
86 // implementations crash when doing so.
87 if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() {
88 switch v := v.Interface().(type) {
89 case error:
90 return textLine("e" + formatString(v.Error()))
91 case fmt.Stringer:
92 return textLine("s" + formatString(v.String()))
93 }
94 }
95 }
96
97 // Check whether to explicitly wrap the result with the type.
98 var skipType bool
99 defer func() {
100 if !skipType {
101 out = opts.FormatType(t, out)
102 }
103 }()
104
105 var ptr string
106 switch t.Kind() {
107 case reflect.Bool:
108 return textLine(fmt.Sprint(v.Bool()))
109 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
110 return textLine(fmt.Sprint(v.Int()))
111 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
112 // Unnamed uints are usually bytes or words, so use hexadecimal.
113 if t.PkgPath() == "" || t.Kind() == reflect.Uintptr {
114 return textLine(formatHex(v.Uint()))
115 }
116 return textLine(fmt.Sprint(v.Uint()))
117 case reflect.Float32, reflect.Float64:
118 return textLine(fmt.Sprint(v.Float()))
119 case reflect.Complex64, reflect.Complex128:
120 return textLine(fmt.Sprint(v.Complex()))
121 case reflect.String:
122 return textLine(formatString(v.String()))
123 case reflect.UnsafePointer, reflect.Chan, reflect.Func:
124 return textLine(formatPointer(v))
125 case reflect.Struct:
126 var list textList
127 for i := 0; i < v.NumField(); i++ {
128 vv := v.Field(i)
129 if value.IsZero(vv) {
130 continue // Elide fields with zero values
131 }
132 s := opts.WithTypeMode(autoType).FormatValue(vv, m)
133 list = append(list, textRecord{Key: t.Field(i).Name, Value: s})
134 }
135 return textWrap{"{", list, "}"}
136 case reflect.Slice:
137 if v.IsNil() {
138 return textNil
139 }
140 if opts.PrintAddresses {
141 ptr = formatPointer(v)
142 }
143 fallthrough
144 case reflect.Array:
145 var list textList
146 for i := 0; i < v.Len(); i++ {
147 vi := v.Index(i)
148 if vi.CanAddr() { // Check for cyclic elements
149 p := vi.Addr()
150 if m.Visit(p) {
151 var out textNode
152 out = textLine(formatPointer(p))
153 out = opts.WithTypeMode(emitType).FormatType(p.Type(), out)
154 out = textWrap{"*", out, ""}
155 list = append(list, textRecord{Value: out})
156 continue
157 }
158 }
159 s := opts.WithTypeMode(elideType).FormatValue(vi, m)
160 list = append(list, textRecord{Value: s})
161 }
162 return textWrap{ptr + "{", list, "}"}
163 case reflect.Map:
164 if v.IsNil() {
165 return textNil
166 }
167 if m.Visit(v) {
168 return textLine(formatPointer(v))
169 }
170
171 var list textList
172 for _, k := range value.SortKeys(v.MapKeys()) {
173 sk := formatMapKey(k)
174 sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m)
175 list = append(list, textRecord{Key: sk, Value: sv})
176 }
177 if opts.PrintAddresses {
178 ptr = formatPointer(v)
179 }
180 return textWrap{ptr + "{", list, "}"}
181 case reflect.Ptr:
182 if v.IsNil() {
183 return textNil
184 }
185 if m.Visit(v) || opts.ShallowPointers {
186 return textLine(formatPointer(v))
187 }
188 if opts.PrintAddresses {
189 ptr = formatPointer(v)
190 }
191 skipType = true // Let the underlying value print the type instead
192 return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""}
193 case reflect.Interface:
194 if v.IsNil() {
195 return textNil
196 }
197 // Interfaces accept different concrete types,
198 // so configure the underlying value to explicitly print the type.
199 skipType = true // Print the concrete type instead
200 return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m)
201 default:
202 panic(fmt.Sprintf("%v kind not handled", v.Kind()))
203 }
204}
205
206// formatMapKey formats v as if it were a map key.
207// The result is guaranteed to be a single line.
208func formatMapKey(v reflect.Value) string {
209 var opts formatOptions
210 opts.TypeMode = elideType
211 opts.AvoidStringer = true
212 opts.ShallowPointers = true
213 s := opts.FormatValue(v, visitedPointers{}).String()
214 return strings.TrimSpace(s)
215}
216
217// formatString prints s as a double-quoted or backtick-quoted string.
218func formatString(s string) string {
219 // Use quoted string if it the same length as a raw string literal.
220 // Otherwise, attempt to use the raw string form.
221 qs := strconv.Quote(s)
222 if len(qs) == 1+len(s)+1 {
223 return qs
224 }
225
226 // Disallow newlines to ensure output is a single line.
227 // Only allow printable runes for readability purposes.
228 rawInvalid := func(r rune) bool {
229 return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t')
230 }
231 if strings.IndexFunc(s, rawInvalid) < 0 {
232 return "`" + s + "`"
233 }
234 return qs
235}
236
237// formatHex prints u as a hexadecimal integer in Go notation.
238func formatHex(u uint64) string {
239 var f string
240 switch {
241 case u <= 0xff:
242 f = "0x%02x"
243 case u <= 0xffff:
244 f = "0x%04x"
245 case u <= 0xffffff:
246 f = "0x%06x"
247 case u <= 0xffffffff:
248 f = "0x%08x"
249 case u <= 0xffffffffff:
250 f = "0x%010x"
251 case u <= 0xffffffffffff:
252 f = "0x%012x"
253 case u <= 0xffffffffffffff:
254 f = "0x%014x"
255 case u <= 0xffffffffffffffff:
256 f = "0x%016x"
257 }
258 return fmt.Sprintf(f, u)
259}
260
261// formatPointer prints the address of the pointer.
262func formatPointer(v reflect.Value) string {
263 p := v.Pointer()
264 if flags.Deterministic {
265 p = 0xdeadf00f // Only used for stable testing purposes
266 }
267 return fmt.Sprintf("⟪0x%x⟫", p)
268}
269
270type visitedPointers map[value.Pointer]struct{}
271
272// Visit inserts pointer v into the visited map and reports whether it had
273// already been visited before.
274func (m visitedPointers) Visit(v reflect.Value) bool {
275 p := value.PointerOf(v)
276 _, visited := m[p]
277 m[p] = struct{}{}
278 return visited
279}
diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go
new file mode 100644
index 0000000..8cb3265
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go
@@ -0,0 +1,333 @@
1// Copyright 2019, 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
5package cmp
6
7import (
8 "bytes"
9 "fmt"
10 "reflect"
11 "strings"
12 "unicode"
13 "unicode/utf8"
14
15 "github.com/google/go-cmp/cmp/internal/diff"
16)
17
18// CanFormatDiffSlice reports whether we support custom formatting for nodes
19// that are slices of primitive kinds or strings.
20func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
21 switch {
22 case opts.DiffMode != diffUnknown:
23 return false // Must be formatting in diff mode
24 case v.NumDiff == 0:
25 return false // No differences detected
26 case v.NumIgnored+v.NumCompared+v.NumTransformed > 0:
27 // TODO: Handle the case where someone uses bytes.Equal on a large slice.
28 return false // Some custom option was used to determined equality
29 case !v.ValueX.IsValid() || !v.ValueY.IsValid():
30 return false // Both values must be valid
31 }
32
33 switch t := v.Type; t.Kind() {
34 case reflect.String:
35 case reflect.Array, reflect.Slice:
36 // Only slices of primitive types have specialized handling.
37 switch t.Elem().Kind() {
38 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
39 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
40 reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
41 default:
42 return false
43 }
44
45 // If a sufficient number of elements already differ,
46 // use specialized formatting even if length requirement is not met.
47 if v.NumDiff > v.NumSame {
48 return true
49 }
50 default:
51 return false
52 }
53
54 // Use specialized string diffing for longer slices or strings.
55 const minLength = 64
56 return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength
57}
58
59// FormatDiffSlice prints a diff for the slices (or strings) represented by v.
60// This provides custom-tailored logic to make printing of differences in
61// textual strings and slices of primitive kinds more readable.
62func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
63 assert(opts.DiffMode == diffUnknown)
64 t, vx, vy := v.Type, v.ValueX, v.ValueY
65
66 // Auto-detect the type of the data.
67 var isLinedText, isText, isBinary bool
68 var sx, sy string
69 switch {
70 case t.Kind() == reflect.String:
71 sx, sy = vx.String(), vy.String()
72 isText = true // Initial estimate, verify later
73 case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)):
74 sx, sy = string(vx.Bytes()), string(vy.Bytes())
75 isBinary = true // Initial estimate, verify later
76 case t.Kind() == reflect.Array:
77 // Arrays need to be addressable for slice operations to work.
78 vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem()
79 vx2.Set(vx)
80 vy2.Set(vy)
81 vx, vy = vx2, vy2
82 }
83 if isText || isBinary {
84 var numLines, lastLineIdx, maxLineLen int
85 isBinary = false
86 for i, r := range sx + sy {
87 if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError {
88 isBinary = true
89 break
90 }
91 if r == '\n' {
92 if maxLineLen < i-lastLineIdx {
93 lastLineIdx = i - lastLineIdx
94 }
95 lastLineIdx = i + 1
96 numLines++
97 }
98 }
99 isText = !isBinary
100 isLinedText = isText && numLines >= 4 && maxLineLen <= 256
101 }
102
103 // Format the string into printable records.
104 var list textList
105 var delim string
106 switch {
107 // If the text appears to be multi-lined text,
108 // then perform differencing across individual lines.
109 case isLinedText:
110 ssx := strings.Split(sx, "\n")
111 ssy := strings.Split(sy, "\n")
112 list = opts.formatDiffSlice(
113 reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line",
114 func(v reflect.Value, d diffMode) textRecord {
115 s := formatString(v.Index(0).String())
116 return textRecord{Diff: d, Value: textLine(s)}
117 },
118 )
119 delim = "\n"
120 // If the text appears to be single-lined text,
121 // then perform differencing in approximately fixed-sized chunks.
122 // The output is printed as quoted strings.
123 case isText:
124 list = opts.formatDiffSlice(
125 reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte",
126 func(v reflect.Value, d diffMode) textRecord {
127 s := formatString(v.String())
128 return textRecord{Diff: d, Value: textLine(s)}
129 },
130 )
131 delim = ""
132 // If the text appears to be binary data,
133 // then perform differencing in approximately fixed-sized chunks.
134 // The output is inspired by hexdump.
135 case isBinary:
136 list = opts.formatDiffSlice(
137 reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte",
138 func(v reflect.Value, d diffMode) textRecord {
139 var ss []string
140 for i := 0; i < v.Len(); i++ {
141 ss = append(ss, formatHex(v.Index(i).Uint()))
142 }
143 s := strings.Join(ss, ", ")
144 comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String())))
145 return textRecord{Diff: d, Value: textLine(s), Comment: comment}
146 },
147 )
148 // For all other slices of primitive types,
149 // then perform differencing in approximately fixed-sized chunks.
150 // The size of each chunk depends on the width of the element kind.
151 default:
152 var chunkSize int
153 if t.Elem().Kind() == reflect.Bool {
154 chunkSize = 16
155 } else {
156 switch t.Elem().Bits() {
157 case 8:
158 chunkSize = 16
159 case 16:
160 chunkSize = 12
161 case 32:
162 chunkSize = 8
163 default:
164 chunkSize = 8
165 }
166 }
167 list = opts.formatDiffSlice(
168 vx, vy, chunkSize, t.Elem().Kind().String(),
169 func(v reflect.Value, d diffMode) textRecord {
170 var ss []string
171 for i := 0; i < v.Len(); i++ {
172 switch t.Elem().Kind() {
173 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
174 ss = append(ss, fmt.Sprint(v.Index(i).Int()))
175 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
176 ss = append(ss, formatHex(v.Index(i).Uint()))
177 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
178 ss = append(ss, fmt.Sprint(v.Index(i).Interface()))
179 }
180 }
181 s := strings.Join(ss, ", ")
182 return textRecord{Diff: d, Value: textLine(s)}
183 },
184 )
185 }
186
187 // Wrap the output with appropriate type information.
188 var out textNode = textWrap{"{", list, "}"}
189 if !isText {
190 // The "{...}" byte-sequence literal is not valid Go syntax for strings.
191 // Emit the type for extra clarity (e.g. "string{...}").
192 if t.Kind() == reflect.String {
193 opts = opts.WithTypeMode(emitType)
194 }
195 return opts.FormatType(t, out)
196 }
197 switch t.Kind() {
198 case reflect.String:
199 out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)}
200 if t != reflect.TypeOf(string("")) {
201 out = opts.FormatType(t, out)
202 }
203 case reflect.Slice:
204 out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)}
205 if t != reflect.TypeOf([]byte(nil)) {
206 out = opts.FormatType(t, out)
207 }
208 }
209 return out
210}
211
212// formatASCII formats s as an ASCII string.
213// This is useful for printing binary strings in a semi-legible way.
214func formatASCII(s string) string {
215 b := bytes.Repeat([]byte{'.'}, len(s))
216 for i := 0; i < len(s); i++ {
217 if ' ' <= s[i] && s[i] <= '~' {
218 b[i] = s[i]
219 }
220 }
221 return string(b)
222}
223
224func (opts formatOptions) formatDiffSlice(
225 vx, vy reflect.Value, chunkSize int, name string,
226 makeRec func(reflect.Value, diffMode) textRecord,
227) (list textList) {
228 es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result {
229 return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface())
230 })
231
232 appendChunks := func(v reflect.Value, d diffMode) int {
233 n0 := v.Len()
234 for v.Len() > 0 {
235 n := chunkSize
236 if n > v.Len() {
237 n = v.Len()
238 }
239 list = append(list, makeRec(v.Slice(0, n), d))
240 v = v.Slice(n, v.Len())
241 }
242 return n0 - v.Len()
243 }
244
245 groups := coalesceAdjacentEdits(name, es)
246 groups = coalesceInterveningIdentical(groups, chunkSize/4)
247 for i, ds := range groups {
248 // Print equal.
249 if ds.NumDiff() == 0 {
250 // Compute the number of leading and trailing equal bytes to print.
251 var numLo, numHi int
252 numEqual := ds.NumIgnored + ds.NumIdentical
253 for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 {
254 numLo++
255 }
256 for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 {
257 numHi++
258 }
259 if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 {
260 numHi = numEqual - numLo // Avoid pointless coalescing of single equal row
261 }
262
263 // Print the equal bytes.
264 appendChunks(vx.Slice(0, numLo), diffIdentical)
265 if numEqual > numLo+numHi {
266 ds.NumIdentical -= numLo + numHi
267 list.AppendEllipsis(ds)
268 }
269 appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical)
270 vx = vx.Slice(numEqual, vx.Len())
271 vy = vy.Slice(numEqual, vy.Len())
272 continue
273 }
274
275 // Print unequal.
276 nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved)
277 vx = vx.Slice(nx, vx.Len())
278 ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
279 vy = vy.Slice(ny, vy.Len())
280 }
281 assert(vx.Len() == 0 && vy.Len() == 0)
282 return list
283}
284
285// coalesceAdjacentEdits coalesces the list of edits into groups of adjacent
286// equal or unequal counts.
287func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
288 var prevCase int // Arbitrary index into which case last occurred
289 lastStats := func(i int) *diffStats {
290 if prevCase != i {
291 groups = append(groups, diffStats{Name: name})
292 prevCase = i
293 }
294 return &groups[len(groups)-1]
295 }
296 for _, e := range es {
297 switch e {
298 case diff.Identity:
299 lastStats(1).NumIdentical++
300 case diff.UniqueX:
301 lastStats(2).NumRemoved++
302 case diff.UniqueY:
303 lastStats(2).NumInserted++
304 case diff.Modified:
305 lastStats(2).NumModified++
306 }
307 }
308 return groups
309}
310
311// coalesceInterveningIdentical coalesces sufficiently short (<= windowSize)
312// equal groups into adjacent unequal groups that currently result in a
313// dual inserted/removed printout. This acts as a high-pass filter to smooth
314// out high-frequency changes within the windowSize.
315func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
316 groups, groupsOrig := groups[:0], groups
317 for i, ds := range groupsOrig {
318 if len(groups) >= 2 && ds.NumDiff() > 0 {
319 prev := &groups[len(groups)-2] // Unequal group
320 curr := &groups[len(groups)-1] // Equal group
321 next := &groupsOrig[i] // Unequal group
322 hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0
323 hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0
324 if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize {
325 *prev = (*prev).Append(*curr).Append(*next)
326 groups = groups[:len(groups)-1] // Truncate off equal group
327 continue
328 }
329 }
330 groups = append(groups, ds)
331 }
332 return groups
333}
diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go
new file mode 100644
index 0000000..80605d0
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report_text.go
@@ -0,0 +1,382 @@
1// Copyright 2019, 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
5package cmp
6
7import (
8 "bytes"
9 "fmt"
10 "math/rand"
11 "strings"
12 "time"
13
14 "github.com/google/go-cmp/cmp/internal/flags"
15)
16
17var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
18
19type indentMode int
20
21func (n indentMode) appendIndent(b []byte, d diffMode) []byte {
22 if flags.Deterministic || randBool {
23 // Use regular spaces (U+0020).
24 switch d {
25 case diffUnknown, diffIdentical:
26 b = append(b, " "...)
27 case diffRemoved:
28 b = append(b, "- "...)
29 case diffInserted:
30 b = append(b, "+ "...)
31 }
32 } else {
33 // Use non-breaking spaces (U+00a0).
34 switch d {
35 case diffUnknown, diffIdentical:
36 b = append(b, "  "...)
37 case diffRemoved:
38 b = append(b, "- "...)
39 case diffInserted:
40 b = append(b, "+ "...)
41 }
42 }
43 return repeatCount(n).appendChar(b, '\t')
44}
45
46type repeatCount int
47
48func (n repeatCount) appendChar(b []byte, c byte) []byte {
49 for ; n > 0; n-- {
50 b = append(b, c)
51 }
52 return b
53}
54
55// textNode is a simplified tree-based representation of structured text.
56// Possible node types are textWrap, textList, or textLine.
57type textNode interface {
58 // Len reports the length in bytes of a single-line version of the tree.
59 // Nested textRecord.Diff and textRecord.Comment fields are ignored.
60 Len() int
61 // Equal reports whether the two trees are structurally identical.
62 // Nested textRecord.Diff and textRecord.Comment fields are compared.
63 Equal(textNode) bool
64 // String returns the string representation of the text tree.
65 // It is not guaranteed that len(x.String()) == x.Len(),
66 // nor that x.String() == y.String() implies that x.Equal(y).
67 String() string
68
69 // formatCompactTo formats the contents of the tree as a single-line string
70 // to the provided buffer. Any nested textRecord.Diff and textRecord.Comment
71 // fields are ignored.
72 //
73 // However, not all nodes in the tree should be collapsed as a single-line.
74 // If a node can be collapsed as a single-line, it is replaced by a textLine
75 // node. Since the top-level node cannot replace itself, this also returns
76 // the current node itself.
77 //
78 // This does not mutate the receiver.
79 formatCompactTo([]byte, diffMode) ([]byte, textNode)
80 // formatExpandedTo formats the contents of the tree as a multi-line string
81 // to the provided buffer. In order for column alignment to operate well,
82 // formatCompactTo must be called before calling formatExpandedTo.
83 formatExpandedTo([]byte, diffMode, indentMode) []byte
84}
85
86// textWrap is a wrapper that concatenates a prefix and/or a suffix
87// to the underlying node.
88type textWrap struct {
89 Prefix string // e.g., "bytes.Buffer{"
90 Value textNode // textWrap | textList | textLine
91 Suffix string // e.g., "}"
92}
93
94func (s textWrap) Len() int {
95 return len(s.Prefix) + s.Value.Len() + len(s.Suffix)
96}
97func (s1 textWrap) Equal(s2 textNode) bool {
98 if s2, ok := s2.(textWrap); ok {
99 return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix
100 }
101 return false
102}
103func (s textWrap) String() string {
104 var d diffMode
105 var n indentMode
106 _, s2 := s.formatCompactTo(nil, d)
107 b := n.appendIndent(nil, d) // Leading indent
108 b = s2.formatExpandedTo(b, d, n) // Main body
109 b = append(b, '\n') // Trailing newline
110 return string(b)
111}
112func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
113 n0 := len(b) // Original buffer length
114 b = append(b, s.Prefix...)
115 b, s.Value = s.Value.formatCompactTo(b, d)
116 b = append(b, s.Suffix...)
117 if _, ok := s.Value.(textLine); ok {
118 return b, textLine(b[n0:])
119 }
120 return b, s
121}
122func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
123 b = append(b, s.Prefix...)
124 b = s.Value.formatExpandedTo(b, d, n)
125 b = append(b, s.Suffix...)
126 return b
127}
128
129// textList is a comma-separated list of textWrap or textLine nodes.
130// The list may be formatted as multi-lines or single-line at the discretion
131// of the textList.formatCompactTo method.
132type textList []textRecord
133type textRecord struct {
134 Diff diffMode // e.g., 0 or '-' or '+'
135 Key string // e.g., "MyField"
136 Value textNode // textWrap | textLine
137 Comment fmt.Stringer // e.g., "6 identical fields"
138}
139
140// AppendEllipsis appends a new ellipsis node to the list if none already
141// exists at the end. If cs is non-zero it coalesces the statistics with the
142// previous diffStats.
143func (s *textList) AppendEllipsis(ds diffStats) {
144 hasStats := ds != diffStats{}
145 if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
146 if hasStats {
147 *s = append(*s, textRecord{Value: textEllipsis, Comment: ds})
148 } else {
149 *s = append(*s, textRecord{Value: textEllipsis})
150 }
151 return
152 }
153 if hasStats {
154 (*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds)
155 }
156}
157
158func (s textList) Len() (n int) {
159 for i, r := range s {
160 n += len(r.Key)
161 if r.Key != "" {
162 n += len(": ")
163 }
164 n += r.Value.Len()
165 if i < len(s)-1 {
166 n += len(", ")
167 }
168 }
169 return n
170}
171
172func (s1 textList) Equal(s2 textNode) bool {
173 if s2, ok := s2.(textList); ok {
174 if len(s1) != len(s2) {
175 return false
176 }
177 for i := range s1 {
178 r1, r2 := s1[i], s2[i]
179 if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) {
180 return false
181 }
182 }
183 return true
184 }
185 return false
186}
187
188func (s textList) String() string {
189 return textWrap{"{", s, "}"}.String()
190}
191
192func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
193 s = append(textList(nil), s...) // Avoid mutating original
194
195 // Determine whether we can collapse this list as a single line.
196 n0 := len(b) // Original buffer length
197 var multiLine bool
198 for i, r := range s {
199 if r.Diff == diffInserted || r.Diff == diffRemoved {
200 multiLine = true
201 }
202 b = append(b, r.Key...)
203 if r.Key != "" {
204 b = append(b, ": "...)
205 }
206 b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff)
207 if _, ok := s[i].Value.(textLine); !ok {
208 multiLine = true
209 }
210 if r.Comment != nil {
211 multiLine = true
212 }
213 if i < len(s)-1 {
214 b = append(b, ", "...)
215 }
216 }
217 // Force multi-lined output when printing a removed/inserted node that
218 // is sufficiently long.
219 if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 {
220 multiLine = true
221 }
222 if !multiLine {
223 return b, textLine(b[n0:])
224 }
225 return b, s
226}
227
228func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
229 alignKeyLens := s.alignLens(
230 func(r textRecord) bool {
231 _, isLine := r.Value.(textLine)
232 return r.Key == "" || !isLine
233 },
234 func(r textRecord) int { return len(r.Key) },
235 )
236 alignValueLens := s.alignLens(
237 func(r textRecord) bool {
238 _, isLine := r.Value.(textLine)
239 return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil
240 },
241 func(r textRecord) int { return len(r.Value.(textLine)) },
242 )
243
244 // Format the list as a multi-lined output.
245 n++
246 for i, r := range s {
247 b = n.appendIndent(append(b, '\n'), d|r.Diff)
248 if r.Key != "" {
249 b = append(b, r.Key+": "...)
250 }
251 b = alignKeyLens[i].appendChar(b, ' ')
252
253 b = r.Value.formatExpandedTo(b, d|r.Diff, n)
254 if !r.Value.Equal(textEllipsis) {
255 b = append(b, ',')
256 }
257 b = alignValueLens[i].appendChar(b, ' ')
258
259 if r.Comment != nil {
260 b = append(b, " // "+r.Comment.String()...)
261 }
262 }
263 n--
264
265 return n.appendIndent(append(b, '\n'), d)
266}
267
268func (s textList) alignLens(
269 skipFunc func(textRecord) bool,
270 lenFunc func(textRecord) int,
271) []repeatCount {
272 var startIdx, endIdx, maxLen int
273 lens := make([]repeatCount, len(s))
274 for i, r := range s {
275 if skipFunc(r) {
276 for j := startIdx; j < endIdx && j < len(s); j++ {
277 lens[j] = repeatCount(maxLen - lenFunc(s[j]))
278 }
279 startIdx, endIdx, maxLen = i+1, i+1, 0
280 } else {
281 if maxLen < lenFunc(r) {
282 maxLen = lenFunc(r)
283 }
284 endIdx = i + 1
285 }
286 }
287 for j := startIdx; j < endIdx && j < len(s); j++ {
288 lens[j] = repeatCount(maxLen - lenFunc(s[j]))
289 }
290 return lens
291}
292
293// textLine is a single-line segment of text and is always a leaf node
294// in the textNode tree.
295type textLine []byte
296
297var (
298 textNil = textLine("nil")
299 textEllipsis = textLine("...")
300)
301
302func (s textLine) Len() int {
303 return len(s)
304}
305func (s1 textLine) Equal(s2 textNode) bool {
306 if s2, ok := s2.(textLine); ok {
307 return bytes.Equal([]byte(s1), []byte(s2))
308 }
309 return false
310}
311func (s textLine) String() string {
312 return string(s)
313}
314func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
315 return append(b, s...), s
316}
317func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte {
318 return append(b, s...)
319}
320
321type diffStats struct {
322 Name string
323 NumIgnored int
324 NumIdentical int
325 NumRemoved int
326 NumInserted int
327 NumModified int
328}
329
330func (s diffStats) NumDiff() int {
331 return s.NumRemoved + s.NumInserted + s.NumModified
332}
333
334func (s diffStats) Append(ds diffStats) diffStats {
335 assert(s.Name == ds.Name)
336 s.NumIgnored += ds.NumIgnored
337 s.NumIdentical += ds.NumIdentical
338 s.NumRemoved += ds.NumRemoved
339 s.NumInserted += ds.NumInserted
340 s.NumModified += ds.NumModified
341 return s
342}
343
344// String prints a humanly-readable summary of coalesced records.
345//
346// Example:
347// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
348func (s diffStats) String() string {
349 var ss []string
350 var sum int
351 labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"}
352 counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified}
353 for i, n := range counts {
354 if n > 0 {
355 ss = append(ss, fmt.Sprintf("%d %v", n, labels[i]))
356 }
357 sum += n
358 }
359
360 // Pluralize the name (adjusting for some obscure English grammar rules).
361 name := s.Name
362 if sum > 1 {
363 name = name + "s"
364 if strings.HasSuffix(name, "ys") {
365 name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries"
366 }
367 }
368
369 // Format the list according to English grammar (with Oxford comma).
370 switch n := len(ss); n {
371 case 0:
372 return ""
373 case 1, 2:
374 return strings.Join(ss, " and ") + " " + name
375 default:
376 return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name
377 }
378}
379
380type commentString string
381
382func (s commentString) String() string { return string(s) }
diff --git a/vendor/github.com/google/go-cmp/cmp/report_value.go b/vendor/github.com/google/go-cmp/cmp/report_value.go
new file mode 100644
index 0000000..83031a7
--- /dev/null
+++ b/vendor/github.com/google/go-cmp/cmp/report_value.go
@@ -0,0 +1,121 @@
1// Copyright 2019, 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
5package cmp
6
7import "reflect"
8
9// valueNode represents a single node within a report, which is a
10// structured representation of the value tree, containing information
11// regarding which nodes are equal or not.
12type valueNode struct {
13 parent *valueNode
14
15 Type reflect.Type
16 ValueX reflect.Value
17 ValueY reflect.Value
18
19 // NumSame is the number of leaf nodes that are equal.
20 // All descendants are equal only if NumDiff is 0.
21 NumSame int
22 // NumDiff is the number of leaf nodes that are not equal.
23 NumDiff int
24 // NumIgnored is the number of leaf nodes that are ignored.
25 NumIgnored int
26 // NumCompared is the number of leaf nodes that were compared
27 // using an Equal method or Comparer function.
28 NumCompared int
29 // NumTransformed is the number of non-leaf nodes that were transformed.
30 NumTransformed int
31 // NumChildren is the number of transitive descendants of this node.
32 // This counts from zero; thus, leaf nodes have no descendants.
33 NumChildren int
34 // MaxDepth is the maximum depth of the tree. This counts from zero;
35 // thus, leaf nodes have a depth of zero.
36 MaxDepth int
37
38 // Records is a list of struct fields, slice elements, or map entries.
39 Records []reportRecord // If populated, implies Value is not populated
40
41 // Value is the result of a transformation, pointer indirect, of
42 // type assertion.
43 Value *valueNode // If populated, implies Records is not populated
44
45 // TransformerName is the name of the transformer.
46 TransformerName string // If non-empty, implies Value is populated
47}
48type reportRecord struct {
49 Key reflect.Value // Invalid for slice element
50 Value *valueNode
51}
52
53func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) {
54 vx, vy := ps.Values()
55 child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy}
56 switch s := ps.(type) {
57 case StructField:
58 assert(parent.Value == nil)
59 parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child})
60 case SliceIndex:
61 assert(parent.Value == nil)
62 parent.Records = append(parent.Records, reportRecord{Value: child})
63 case MapIndex:
64 assert(parent.Value == nil)
65 parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child})
66 case Indirect:
67 assert(parent.Value == nil && parent.Records == nil)
68 parent.Value = child
69 case TypeAssertion:
70 assert(parent.Value == nil && parent.Records == nil)
71 parent.Value = child
72 case Transform:
73 assert(parent.Value == nil && parent.Records == nil)
74 parent.Value = child
75 parent.TransformerName = s.Name()
76 parent.NumTransformed++
77 default:
78 assert(parent == nil) // Must be the root step
79 }
80 return child
81}
82
83func (r *valueNode) Report(rs Result) {
84 assert(r.MaxDepth == 0) // May only be called on leaf nodes
85
86 if rs.ByIgnore() {
87 r.NumIgnored++
88 } else {
89 if rs.Equal() {
90 r.NumSame++
91 } else {
92 r.NumDiff++
93 }
94 }
95 assert(r.NumSame+r.NumDiff+r.NumIgnored == 1)
96
97 if rs.ByMethod() {
98 r.NumCompared++
99 }
100 if rs.ByFunc() {
101 r.NumCompared++
102 }
103 assert(r.NumCompared <= 1)
104}
105
106func (child *valueNode) PopStep() (parent *valueNode) {
107 if child.parent == nil {
108 return nil
109 }
110 parent = child.parent
111 parent.NumSame += child.NumSame
112 parent.NumDiff += child.NumDiff
113 parent.NumIgnored += child.NumIgnored
114 parent.NumCompared += child.NumCompared
115 parent.NumTransformed += child.NumTransformed
116 parent.NumChildren += child.NumChildren + 1
117 if parent.MaxDepth < child.MaxDepth+1 {
118 parent.MaxDepth = child.MaxDepth + 1
119 }
120 return parent
121}
diff --git a/vendor/github.com/google/go-cmp/cmp/reporter.go b/vendor/github.com/google/go-cmp/cmp/reporter.go
deleted file mode 100644
index 20e9f18..0000000
--- a/vendor/github.com/google/go-cmp/cmp/reporter.go
+++ /dev/null
@@ -1,53 +0,0 @@
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
5package cmp
6
7import (
8 "fmt"
9 "reflect"
10 "strings"
11
12 "github.com/google/go-cmp/cmp/internal/value"
13)
14
15type defaultReporter struct {
16 Option
17 diffs []string // List of differences, possibly truncated
18 ndiffs int // Total number of differences
19 nbytes int // Number of bytes in diffs
20 nlines int // Number of lines in diffs
21}
22
23var _ reporter = (*defaultReporter)(nil)
24
25func (r *defaultReporter) Report(x, y reflect.Value, eq bool, p Path) {
26 if eq {
27 return // Ignore equal results
28 }
29 const maxBytes = 4096
30 const maxLines = 256
31 r.ndiffs++
32 if r.nbytes < maxBytes && r.nlines < maxLines {
33 sx := value.Format(x, value.FormatConfig{UseStringer: true})
34 sy := value.Format(y, value.FormatConfig{UseStringer: true})
35 if sx == sy {
36 // Unhelpful output, so use more exact formatting.
37 sx = value.Format(x, value.FormatConfig{PrintPrimitiveType: true})
38 sy = value.Format(y, value.FormatConfig{PrintPrimitiveType: true})
39 }
40 s := fmt.Sprintf("%#v:\n\t-: %s\n\t+: %s\n", p, sx, sy)
41 r.diffs = append(r.diffs, s)
42 r.nbytes += len(s)
43 r.nlines += strings.Count(s, "\n")
44 }
45}
46
47func (r *defaultReporter) String() string {
48 s := strings.Join(r.diffs, "")
49 if r.ndiffs == len(r.diffs) {
50 return s
51 }
52 return fmt.Sprintf("%s... %d more differences ...", s, r.ndiffs-len(r.diffs))
53}