aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/google
diff options
context:
space:
mode:
authorAlexandre Garand <alexandre.garand@fretlink.com>2019-08-09 15:59:15 +0200
committerAlexandre Garand <alexandre.garand@fretlink.com>2019-08-09 16:39:21 +0200
commit863486a6b71ed0e562a3965bed56465d007b1418 (patch)
treee93f6a687695af86d54237ec9f575d4ef104222d /vendor/github.com/google
parent49c1c7b4dc69ffb9ab52330e6dc52ccdd6351087 (diff)
downloadterraform-provider-statuscake-863486a6b71ed0e562a3965bed56465d007b1418.tar.gz
terraform-provider-statuscake-863486a6b71ed0e562a3965bed56465d007b1418.tar.zst
terraform-provider-statuscake-863486a6b71ed0e562a3965bed56465d007b1418.zip
update vendor and go.modadd_contact_groups
Diffstat (limited to 'vendor/github.com/google')
-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
-rw-r--r--vendor/github.com/google/go-querystring/LICENSE27
-rw-r--r--vendor/github.com/google/go-querystring/query/encode.go320
26 files changed, 2662 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}
diff --git a/vendor/github.com/google/go-querystring/LICENSE b/vendor/github.com/google/go-querystring/LICENSE
new file mode 100644
index 0000000..ae121a1
--- /dev/null
+++ b/vendor/github.com/google/go-querystring/LICENSE
@@ -0,0 +1,27 @@
1Copyright (c) 2013 Google. All rights reserved.
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are
5met:
6
7 * Redistributions of source code must retain the above copyright
8notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10copyright notice, this list of conditions and the following disclaimer
11in the documentation and/or other materials provided with the
12distribution.
13 * Neither the name of Google Inc. nor the names of its
14contributors may be used to endorse or promote products derived from
15this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/google/go-querystring/query/encode.go b/vendor/github.com/google/go-querystring/query/encode.go
new file mode 100644
index 0000000..37080b1
--- /dev/null
+++ b/vendor/github.com/google/go-querystring/query/encode.go
@@ -0,0 +1,320 @@
1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package query implements encoding of structs into URL query parameters.
6//
7// As a simple example:
8//
9// type Options struct {
10// Query string `url:"q"`
11// ShowAll bool `url:"all"`
12// Page int `url:"page"`
13// }
14//
15// opt := Options{ "foo", true, 2 }
16// v, _ := query.Values(opt)
17// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
18//
19// The exact mapping between Go values and url.Values is described in the
20// documentation for the Values() function.
21package query
22
23import (
24 "bytes"
25 "fmt"
26 "net/url"
27 "reflect"
28 "strconv"
29 "strings"
30 "time"
31)
32
33var timeType = reflect.TypeOf(time.Time{})
34
35var encoderType = reflect.TypeOf(new(Encoder)).Elem()
36
37// Encoder is an interface implemented by any type that wishes to encode
38// itself into URL values in a non-standard way.
39type Encoder interface {
40 EncodeValues(key string, v *url.Values) error
41}
42
43// Values returns the url.Values encoding of v.
44//
45// Values expects to be passed a struct, and traverses it recursively using the
46// following encoding rules.
47//
48// Each exported struct field is encoded as a URL parameter unless
49//
50// - the field's tag is "-", or
51// - the field is empty and its tag specifies the "omitempty" option
52//
53// The empty values are false, 0, any nil pointer or interface value, any array
54// slice, map, or string of length zero, and any time.Time that returns true
55// for IsZero().
56//
57// The URL parameter name defaults to the struct field name but can be
58// specified in the struct field's tag value. The "url" key in the struct
59// field's tag value is the key name, followed by an optional comma and
60// options. For example:
61//
62// // Field is ignored by this package.
63// Field int `url:"-"`
64//
65// // Field appears as URL parameter "myName".
66// Field int `url:"myName"`
67//
68// // Field appears as URL parameter "myName" and the field is omitted if
69// // its value is empty
70// Field int `url:"myName,omitempty"`
71//
72// // Field appears as URL parameter "Field" (the default), but the field
73// // is skipped if empty. Note the leading comma.
74// Field int `url:",omitempty"`
75//
76// For encoding individual field values, the following type-dependent rules
77// apply:
78//
79// Boolean values default to encoding as the strings "true" or "false".
80// Including the "int" option signals that the field should be encoded as the
81// strings "1" or "0".
82//
83// time.Time values default to encoding as RFC3339 timestamps. Including the
84// "unix" option signals that the field should be encoded as a Unix time (see
85// time.Unix())
86//
87// Slice and Array values default to encoding as multiple URL values of the
88// same name. Including the "comma" option signals that the field should be
89// encoded as a single comma-delimited value. Including the "space" option
90// similarly encodes the value as a single space-delimited string. Including
91// the "semicolon" option will encode the value as a semicolon-delimited string.
92// Including the "brackets" option signals that the multiple URL values should
93// have "[]" appended to the value name. "numbered" will append a number to
94// the end of each incidence of the value name, example:
95// name0=value0&name1=value1, etc.
96//
97// Anonymous struct fields are usually encoded as if their inner exported
98// fields were fields in the outer struct, subject to the standard Go
99// visibility rules. An anonymous struct field with a name given in its URL
100// tag is treated as having that name, rather than being anonymous.
101//
102// Non-nil pointer values are encoded as the value pointed to.
103//
104// Nested structs are encoded including parent fields in value names for
105// scoping. e.g:
106//
107// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO"
108//
109// All other values are encoded using their default string representation.
110//
111// Multiple fields that encode to the same URL parameter name will be included
112// as multiple URL values of the same name.
113func Values(v interface{}) (url.Values, error) {
114 values := make(url.Values)
115 val := reflect.ValueOf(v)
116 for val.Kind() == reflect.Ptr {
117 if val.IsNil() {
118 return values, nil
119 }
120 val = val.Elem()
121 }
122
123 if v == nil {
124 return values, nil
125 }
126
127 if val.Kind() != reflect.Struct {
128 return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind())
129 }
130
131 err := reflectValue(values, val, "")
132 return values, err
133}
134
135// reflectValue populates the values parameter from the struct fields in val.
136// Embedded structs are followed recursively (using the rules defined in the
137// Values function documentation) breadth-first.
138func reflectValue(values url.Values, val reflect.Value, scope string) error {
139 var embedded []reflect.Value
140
141 typ := val.Type()
142 for i := 0; i < typ.NumField(); i++ {
143 sf := typ.Field(i)
144 if sf.PkgPath != "" && !sf.Anonymous { // unexported
145 continue
146 }
147
148 sv := val.Field(i)
149 tag := sf.Tag.Get("url")
150 if tag == "-" {
151 continue
152 }
153 name, opts := parseTag(tag)
154 if name == "" {
155 if sf.Anonymous && sv.Kind() == reflect.Struct {
156 // save embedded struct for later processing
157 embedded = append(embedded, sv)
158 continue
159 }
160
161 name = sf.Name
162 }
163
164 if scope != "" {
165 name = scope + "[" + name + "]"
166 }
167
168 if opts.Contains("omitempty") && isEmptyValue(sv) {
169 continue
170 }
171
172 if sv.Type().Implements(encoderType) {
173 if !reflect.Indirect(sv).IsValid() {
174 sv = reflect.New(sv.Type().Elem())
175 }
176
177 m := sv.Interface().(Encoder)
178 if err := m.EncodeValues(name, &values); err != nil {
179 return err
180 }
181 continue
182 }
183
184 if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
185 var del byte
186 if opts.Contains("comma") {
187 del = ','
188 } else if opts.Contains("space") {
189 del = ' '
190 } else if opts.Contains("semicolon") {
191 del = ';'
192 } else if opts.Contains("brackets") {
193 name = name + "[]"
194 }
195
196 if del != 0 {
197 s := new(bytes.Buffer)
198 first := true
199 for i := 0; i < sv.Len(); i++ {
200 if first {
201 first = false
202 } else {
203 s.WriteByte(del)
204 }
205 s.WriteString(valueString(sv.Index(i), opts))
206 }
207 values.Add(name, s.String())
208 } else {
209 for i := 0; i < sv.Len(); i++ {
210 k := name
211 if opts.Contains("numbered") {
212 k = fmt.Sprintf("%s%d", name, i)
213 }
214 values.Add(k, valueString(sv.Index(i), opts))
215 }
216 }
217 continue
218 }
219
220 for sv.Kind() == reflect.Ptr {
221 if sv.IsNil() {
222 break
223 }
224 sv = sv.Elem()
225 }
226
227 if sv.Type() == timeType {
228 values.Add(name, valueString(sv, opts))
229 continue
230 }
231
232 if sv.Kind() == reflect.Struct {
233 reflectValue(values, sv, name)
234 continue
235 }
236
237 values.Add(name, valueString(sv, opts))
238 }
239
240 for _, f := range embedded {
241 if err := reflectValue(values, f, scope); err != nil {
242 return err
243 }
244 }
245
246 return nil
247}
248
249// valueString returns the string representation of a value.
250func valueString(v reflect.Value, opts tagOptions) string {
251 for v.Kind() == reflect.Ptr {
252 if v.IsNil() {
253 return ""
254 }
255 v = v.Elem()
256 }
257
258 if v.Kind() == reflect.Bool && opts.Contains("int") {
259 if v.Bool() {
260 return "1"
261 }
262 return "0"
263 }
264
265 if v.Type() == timeType {
266 t := v.Interface().(time.Time)
267 if opts.Contains("unix") {
268 return strconv.FormatInt(t.Unix(), 10)
269 }
270 return t.Format(time.RFC3339)
271 }
272
273 return fmt.Sprint(v.Interface())
274}
275
276// isEmptyValue checks if a value should be considered empty for the purposes
277// of omitting fields with the "omitempty" option.
278func isEmptyValue(v reflect.Value) bool {
279 switch v.Kind() {
280 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
281 return v.Len() == 0
282 case reflect.Bool:
283 return !v.Bool()
284 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
285 return v.Int() == 0
286 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
287 return v.Uint() == 0
288 case reflect.Float32, reflect.Float64:
289 return v.Float() == 0
290 case reflect.Interface, reflect.Ptr:
291 return v.IsNil()
292 }
293
294 if v.Type() == timeType {
295 return v.Interface().(time.Time).IsZero()
296 }
297
298 return false
299}
300
301// tagOptions is the string following a comma in a struct field's "url" tag, or
302// the empty string. It does not include the leading comma.
303type tagOptions []string
304
305// parseTag splits a struct field's url tag into its name and comma-separated
306// options.
307func parseTag(tag string) (string, tagOptions) {
308 s := strings.Split(tag, ",")
309 return s[0], s[1:]
310}
311
312// Contains checks whether the tagOptions contains the specified option.
313func (o tagOptions) Contains(option string) bool {
314 for _, s := range o {
315 if s == option {
316 return true
317 }
318 }
319 return false
320}