Vendor dependencies for GCS

This commit is contained in:
Alexander Neumann
2017-08-05 20:17:15 +02:00
parent ba75a3884c
commit 8ca6a9a240
1228 changed files with 1769186 additions and 1 deletions

444
vendor/cloud.google.com/go/internal/fields/fields.go generated vendored Normal file
View File

@@ -0,0 +1,444 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package fields provides a view of the fields of a struct that follows the Go
// rules, amended to consider tags and case insensitivity.
//
// Usage
//
// First define a function that interprets tags:
//
// func parseTag(st reflect.StructTag) (name string, keep bool, other interface{}, err error) { ... }
//
// The function's return values describe whether to ignore the field
// completely or provide an alternate name, as well as other data from the
// parse that is stored to avoid re-parsing.
//
// Then define a function to validate the type:
//
// func validate(t reflect.Type) error { ... }
//
// Then, if necessary, define a function to specify leaf types - types
// which should be considered one field and not be recursed into:
//
// func isLeafType(t reflect.Type) bool { ... }
//
// eg:
//
// func isLeafType(t reflect.Type) bool {
// return t == reflect.TypeOf(time.Time{})
// }
//
// Next, construct a Cache, passing your functions. As its name suggests, a
// Cache remembers validation and field information for a type, so subsequent
// calls with the same type are very fast.
//
// cache := fields.NewCache(parseTag, validate, isLeafType)
//
// To get the fields of a struct type as determined by the above rules, call
// the Fields method:
//
// fields, err := cache.Fields(reflect.TypeOf(MyStruct{}))
//
// The return value can be treated as a slice of Fields.
//
// Given a string, such as a key or column name obtained during unmarshalling,
// call Match on the list of fields to find a field whose name is the best
// match:
//
// field := fields.Match(name)
//
// Match looks for an exact match first, then falls back to a case-insensitive
// comparison.
package fields
import (
"bytes"
"reflect"
"sort"
"cloud.google.com/go/internal/atomiccache"
)
// A Field records information about a struct field.
type Field struct {
Name string // effective field name
NameFromTag bool // did Name come from a tag?
Type reflect.Type // field type
Index []int // index sequence, for reflect.Value.FieldByIndex
ParsedTag interface{} // third return value of the parseTag function
nameBytes []byte
equalFold func(s, t []byte) bool
}
type ParseTagFunc func(reflect.StructTag) (name string, keep bool, other interface{}, err error)
type ValidateFunc func(reflect.Type) error
type LeafTypesFunc func(reflect.Type) bool
// A Cache records information about the fields of struct types.
//
// A Cache is safe for use by multiple goroutines.
type Cache struct {
parseTag ParseTagFunc
validate ValidateFunc
leafTypes LeafTypesFunc
cache atomiccache.Cache // from reflect.Type to cacheValue
}
// NewCache constructs a Cache.
//
// Its first argument should be a function that accepts
// a struct tag and returns four values: an alternative name for the field
// extracted from the tag, a boolean saying whether to keep the field or ignore
// it, additional data that is stored with the field information to avoid
// having to parse the tag again, and an error.
//
// Its second argument should be a function that accepts a reflect.Type and
// returns an error if the struct type is invalid in any way. For example, it
// may check that all of the struct field tags are valid, or that all fields
// are of an appropriate type.
func NewCache(parseTag ParseTagFunc, validate ValidateFunc, leafTypes LeafTypesFunc) *Cache {
if parseTag == nil {
parseTag = func(reflect.StructTag) (string, bool, interface{}, error) {
return "", true, nil, nil
}
}
if validate == nil {
validate = func(reflect.Type) error {
return nil
}
}
if leafTypes == nil {
leafTypes = func(reflect.Type) bool {
return false
}
}
return &Cache{
parseTag: parseTag,
validate: validate,
leafTypes: leafTypes,
}
}
// A fieldScan represents an item on the fieldByNameFunc scan work list.
type fieldScan struct {
typ reflect.Type
index []int
}
// Fields returns all the exported fields of t, which must be a struct type. It
// follows the standard Go rules for embedded fields, modified by the presence
// of tags. The result is sorted lexicographically by index.
//
// These rules apply in the absence of tags:
// Anonymous struct fields are treated as if their inner exported fields were
// fields in the outer struct (embedding). The result includes all fields that
// aren't shadowed by fields at higher level of embedding. If more than one
// field with the same name exists at the same level of embedding, it is
// excluded. An anonymous field that is not of struct type is treated as having
// its type as its name.
//
// Tags modify these rules as follows:
// A field's tag is used as its name.
// An anonymous struct field with a name given in its tag is treated as
// a field having that name, rather than an embedded struct (the struct's
// fields will not be returned).
// If more than one field with the same name exists at the same level of embedding,
// but exactly one of them is tagged, then the tagged field is reported and the others
// are ignored.
func (c *Cache) Fields(t reflect.Type) (List, error) {
if t.Kind() != reflect.Struct {
panic("fields: Fields of non-struct type")
}
return c.cachedTypeFields(t)
}
// A List is a list of Fields.
type List []Field
// Match returns the field in the list whose name best matches the supplied
// name, nor nil if no field does. If there is a field with the exact name, it
// is returned. Otherwise the first field (sorted by index) whose name matches
// case-insensitively is returned.
func (l List) Match(name string) *Field {
return l.MatchBytes([]byte(name))
}
// MatchBytes is identical to Match, except that the argument is a byte slice.
func (l List) MatchBytes(name []byte) *Field {
var f *Field
for i := range l {
ff := &l[i]
if bytes.Equal(ff.nameBytes, name) {
return ff
}
if f == nil && ff.equalFold(ff.nameBytes, name) {
f = ff
}
}
return f
}
type cacheValue struct {
fields List
err error
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
// This code has been copied and modified from
// https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/encode.go.
func (c *Cache) cachedTypeFields(t reflect.Type) (List, error) {
cv := c.cache.Get(t, func() interface{} {
if err := c.validate(t); err != nil {
return cacheValue{nil, err}
}
f, err := c.typeFields(t)
return cacheValue{List(f), err}
}).(cacheValue)
return cv.fields, cv.err
}
func (c *Cache) typeFields(t reflect.Type) ([]Field, error) {
fields, err := c.listFields(t)
if err != nil {
return nil, err
}
sort.Sort(byName(fields))
// Delete all fields that are hidden by the Go rules for embedded fields.
// The fields are sorted in primary order of name, secondary order of field
// index length. So the first field with a given name is the dominant one.
var out []Field
for advance, i := 0, 0; i < len(fields); i += advance {
// One iteration per name.
// Find the sequence of fields with the name of this first field.
fi := fields[i]
name := fi.Name
for advance = 1; i+advance < len(fields); advance++ {
fj := fields[i+advance]
if fj.Name != name {
break
}
}
// Find the dominant field, if any, out of all fields that have the same name.
dominant, ok := dominantField(fields[i : i+advance])
if ok {
out = append(out, dominant)
}
}
sort.Sort(byIndex(out))
return out, nil
}
func (c *Cache) listFields(t reflect.Type) ([]Field, error) {
// This uses the same condition that the Go language does: there must be a unique instance
// of the match at a given depth level. If there are multiple instances of a match at the
// same depth, they annihilate each other and inhibit any possible match at a lower level.
// The algorithm is breadth first search, one depth level at a time.
// The current and next slices are work queues:
// current lists the fields to visit on this depth level,
// and next lists the fields on the next lower level.
current := []fieldScan{}
next := []fieldScan{{typ: t}}
// nextCount records the number of times an embedded type has been
// encountered and considered for queueing in the 'next' slice.
// We only queue the first one, but we increment the count on each.
// If a struct type T can be reached more than once at a given depth level,
// then it annihilates itself and need not be considered at all when we
// process that next depth level.
var nextCount map[reflect.Type]int
// visited records the structs that have been considered already.
// Embedded pointer fields can create cycles in the graph of
// reachable embedded types; visited avoids following those cycles.
// It also avoids duplicated effort: if we didn't find the field in an
// embedded type T at level 2, we won't find it in one at level 4 either.
visited := map[reflect.Type]bool{}
var fields []Field // Fields found.
for len(next) > 0 {
current, next = next, current[:0]
count := nextCount
nextCount = nil
// Process all the fields at this depth, now listed in 'current'.
// The loop queues embedded fields found in 'next', for processing during the next
// iteration. The multiplicity of the 'current' field counts is recorded
// in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'.
for _, scan := range current {
t := scan.typ
if visited[t] {
// We've looked through this type before, at a higher level.
// That higher level would shadow the lower level we're now at,
// so this one can't be useful to us. Ignore it.
continue
}
visited[t] = true
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
exported := (f.PkgPath == "")
// If a named field is unexported, ignore it. An anonymous
// unexported field is processed, because it may contain
// exported fields, which are visible.
if !exported && !f.Anonymous {
continue
}
// Examine the tag.
tagName, keep, other, err := c.parseTag(f.Tag)
if err != nil {
return nil, err
}
if !keep {
continue
}
if c.leafTypes(f.Type) {
fields = append(fields, newField(f, tagName, other, scan.index, i))
continue
}
var ntyp reflect.Type
if f.Anonymous {
// Anonymous field of type T or *T.
ntyp = f.Type
if ntyp.Kind() == reflect.Ptr {
ntyp = ntyp.Elem()
}
}
// Record fields with a tag name, non-anonymous fields, or
// anonymous non-struct fields.
if tagName != "" || ntyp == nil || ntyp.Kind() != reflect.Struct {
if !exported {
continue
}
fields = append(fields, newField(f, tagName, other, scan.index, i))
if count[t] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
fields = append(fields, fields[len(fields)-1])
}
continue
}
// Queue embedded struct fields for processing with next level,
// but only if the embedded types haven't already been queued.
if nextCount[ntyp] > 0 {
nextCount[ntyp] = 2 // exact multiple doesn't matter
continue
}
if nextCount == nil {
nextCount = map[reflect.Type]int{}
}
nextCount[ntyp] = 1
if count[t] > 1 {
nextCount[ntyp] = 2 // exact multiple doesn't matter
}
var index []int
index = append(index, scan.index...)
index = append(index, i)
next = append(next, fieldScan{ntyp, index})
}
}
}
return fields, nil
}
func newField(f reflect.StructField, tagName string, other interface{}, index []int, i int) Field {
name := tagName
if name == "" {
name = f.Name
}
sf := Field{
Name: name,
NameFromTag: tagName != "",
Type: f.Type,
ParsedTag: other,
nameBytes: []byte(name),
}
sf.equalFold = foldFunc(sf.nameBytes)
sf.Index = append(sf.Index, index...)
sf.Index = append(sf.Index, i)
return sf
}
// byName sorts fields using the following criteria, in order:
// 1. name
// 2. embedding depth
// 3. tag presence (preferring a tagged field)
// 4. index sequence.
type byName []Field
func (x byName) Len() int { return len(x) }
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byName) Less(i, j int) bool {
if x[i].Name != x[j].Name {
return x[i].Name < x[j].Name
}
if len(x[i].Index) != len(x[j].Index) {
return len(x[i].Index) < len(x[j].Index)
}
if x[i].NameFromTag != x[j].NameFromTag {
return x[i].NameFromTag
}
return byIndex(x).Less(i, j)
}
// byIndex sorts field by index sequence.
type byIndex []Field
func (x byIndex) Len() int { return len(x) }
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byIndex) Less(i, j int) bool {
xi := x[i].Index
xj := x[j].Index
ln := len(xi)
if l := len(xj); l < ln {
ln = l
}
for k := 0; k < ln; k++ {
if xi[k] != xj[k] {
return xi[k] < xj[k]
}
}
return len(xi) < len(xj)
}
// dominantField looks through the fields, all of which are known to have the
// same name, to find the single field that dominates the others using Go's
// embedding rules, modified by the presence of tags. If there are multiple
// top-level fields, the boolean will be false: This condition is an error in
// Go and we skip all the fields.
func dominantField(fs []Field) (Field, bool) {
// The fields are sorted in increasing index-length order, then by presence of tag.
// That means that the first field is the dominant one. We need only check
// for error cases: two fields at top level, either both tagged or neither tagged.
if len(fs) > 1 && len(fs[0].Index) == len(fs[1].Index) && fs[0].NameFromTag == fs[1].NameFromTag {
return Field{}, false
}
return fs[0], true
}

View File

@@ -0,0 +1,566 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fields
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"cloud.google.com/go/internal/testutil"
)
type embed1 struct {
Em1 int
Dup int // annihilates with embed2.Dup
Shadow int
embed3
}
type embed2 struct {
Dup int
embed3
embed4
}
type embed3 struct {
Em3 int // annihilated because embed3 is in both embed1 and embed2
embed5
}
type embed4 struct {
Em4 int
Dup int // annihilation of Dup in embed1, embed2 hides this Dup
*embed1 // ignored because it occurs at a higher level
}
type embed5 struct {
x int
}
type Anonymous int
type S1 struct {
Exported int
unexported int
Shadow int // shadows S1.Shadow
embed1
*embed2
Anonymous
}
type Time struct {
time.Time
}
var intType = reflect.TypeOf(int(0))
func field(name string, tval interface{}, index ...int) *Field {
return &Field{
Name: name,
Type: reflect.TypeOf(tval),
Index: index,
}
}
func tfield(name string, tval interface{}, index ...int) *Field {
return &Field{
Name: name,
Type: reflect.TypeOf(tval),
Index: index,
NameFromTag: true,
}
}
func TestFieldsNoTags(t *testing.T) {
c := NewCache(nil, nil, nil)
got, err := c.Fields(reflect.TypeOf(S1{}))
if err != nil {
t.Fatal(err)
}
want := []*Field{
field("Exported", int(0), 0),
field("Shadow", int(0), 2),
field("Em1", int(0), 3, 0),
field("Em4", int(0), 4, 2, 0),
field("Anonymous", Anonymous(0), 5),
}
if msg, ok := compareFields(got, want); !ok {
t.Error(msg)
}
}
func TestAgainstJSONEncodingNoTags(t *testing.T) {
// Demonstrates that this package produces the same set of fields as encoding/json.
s1 := S1{
Exported: 1,
unexported: 2,
Shadow: 3,
embed1: embed1{
Em1: 4,
Dup: 5,
Shadow: 6,
embed3: embed3{
Em3: 7,
embed5: embed5{x: 8},
},
},
embed2: &embed2{
Dup: 9,
embed3: embed3{
Em3: 10,
embed5: embed5{x: 11},
},
embed4: embed4{
Em4: 12,
Dup: 13,
embed1: &embed1{Em1: 14},
},
},
Anonymous: Anonymous(15),
}
var want S1
jsonRoundTrip(t, s1, &want)
var got S1
got.embed2 = &embed2{} // need this because reflection won't create it
fields, err := NewCache(nil, nil, nil).Fields(reflect.TypeOf(got))
if err != nil {
t.Fatal(err)
}
setFields(fields, &got, s1)
if !testutil.Equal(got, want,
cmp.AllowUnexported(S1{}, embed1{}, embed2{}, embed3{}, embed4{}, embed5{})) {
t.Errorf("got\n%+v\nwant\n%+v", got, want)
}
}
// Tests use of LeafTypes parameter to NewCache
func TestAgainstJSONEncodingEmbeddedTime(t *testing.T) {
timeLeafFn := func(t reflect.Type) bool {
return t == reflect.TypeOf(time.Time{})
}
// Demonstrates that this package can produce the same set of
// fields as encoding/json for a struct with an embedded time.Time.
now := time.Now().UTC()
myt := Time{
now,
}
var want Time
jsonRoundTrip(t, myt, &want)
var got Time
fields, err := NewCache(nil, nil, timeLeafFn).Fields(reflect.TypeOf(got))
if err != nil {
t.Fatal(err)
}
setFields(fields, &got, myt)
if !testutil.Equal(got, want) {
t.Errorf("got\n%+v\nwant\n%+v", got, want)
}
}
type S2 struct {
NoTag int
XXX int `json:"tag"` // tag name takes precedence
Anonymous `json:"anon"` // anonymous non-structs also get their name from the tag
unexported int `json:"tag"`
Embed `json:"em"` // embedded structs with tags become fields
Tag int
YYY int `json:"Tag"` // tag takes precedence over untagged field of the same name
Empty int `json:""` // empty tag is noop
tEmbed1
tEmbed2
}
type Embed struct {
Em int
}
type tEmbed1 struct {
Dup int
X int `json:"Dup2"`
}
type tEmbed2 struct {
Y int `json:"Dup"` // takes precedence over tEmbed1.Dup because it is tagged
Z int `json:"Dup2"` // same name as tEmbed1.X and both tagged, so ignored
}
func jsonTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) {
s := t.Get("json")
parts := strings.Split(s, ",")
if parts[0] == "-" {
return "", false, nil, nil
}
if len(parts) > 1 {
other = parts[1:]
}
return parts[0], true, other, nil
}
func validateFunc(t reflect.Type) (err error) {
if t.Kind() != reflect.Struct {
return errors.New("non-struct type used")
}
for i := 0; i < t.NumField(); i++ {
if t.Field(i).Type.Kind() == reflect.Slice {
return fmt.Errorf("slice field found at field %s on struct %s", t.Field(i).Name, t.Name())
}
}
return nil
}
func TestFieldsWithTags(t *testing.T) {
got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S2{}))
if err != nil {
t.Fatal(err)
}
want := []*Field{
field("NoTag", int(0), 0),
tfield("tag", int(0), 1),
tfield("anon", Anonymous(0), 2),
tfield("em", Embed{}, 4),
tfield("Tag", int(0), 6),
field("Empty", int(0), 7),
tfield("Dup", int(0), 8, 0),
}
if msg, ok := compareFields(got, want); !ok {
t.Error(msg)
}
}
func TestAgainstJSONEncodingWithTags(t *testing.T) {
// Demonstrates that this package produces the same set of fields as encoding/json.
s2 := S2{
NoTag: 1,
XXX: 2,
Anonymous: 3,
Embed: Embed{
Em: 4,
},
tEmbed1: tEmbed1{
Dup: 5,
X: 6,
},
tEmbed2: tEmbed2{
Y: 7,
Z: 8,
},
}
var want S2
jsonRoundTrip(t, s2, &want)
var got S2
fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(got))
if err != nil {
t.Fatal(err)
}
setFields(fields, &got, s2)
if !testutil.Equal(got, want, cmp.AllowUnexported(S2{})) {
t.Errorf("got\n%+v\nwant\n%+v", got, want)
}
}
func TestUnexportedAnonymousNonStruct(t *testing.T) {
// An unexported anonymous non-struct field should not be recorded.
// This is currently a bug in encoding/json.
// https://github.com/golang/go/issues/18009
type (
u int
v int
S struct {
u
v `json:"x"`
int
}
)
got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{}))
if err != nil {
t.Fatal(err)
}
if len(got) != 0 {
t.Errorf("got %d fields, want 0", len(got))
}
}
func TestUnexportedAnonymousStruct(t *testing.T) {
// An unexported anonymous struct with a tag is ignored.
// This is currently a bug in encoding/json.
// https://github.com/golang/go/issues/18009
type (
s1 struct{ X int }
S2 struct {
s1 `json:"Y"`
}
)
got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S2{}))
if err != nil {
t.Fatal(err)
}
if len(got) != 0 {
t.Errorf("got %d fields, want 0", len(got))
}
}
func TestDominantField(t *testing.T) {
// With fields sorted by index length and then by tag presence,
// the dominant field is always the first. Make sure all error
// cases are caught.
for _, test := range []struct {
fields []Field
wantOK bool
}{
// A single field is OK.
{[]Field{{Index: []int{0}}}, true},
{[]Field{{Index: []int{0}, NameFromTag: true}}, true},
// A single field at top level is OK.
{[]Field{{Index: []int{0}}, {Index: []int{1, 0}}}, true},
{[]Field{{Index: []int{0}}, {Index: []int{1, 0}, NameFromTag: true}}, true},
{[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1, 0}, NameFromTag: true}}, true},
// A single tagged field is OK.
{[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1}}}, true},
// Two untagged fields at the same level is an error.
{[]Field{{Index: []int{0}}, {Index: []int{1}}}, false},
// Two tagged fields at the same level is an error.
{[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1}, NameFromTag: true}}, false},
} {
_, gotOK := dominantField(test.fields)
if gotOK != test.wantOK {
t.Errorf("%v: got %t, want %t", test.fields, gotOK, test.wantOK)
}
}
}
func TestIgnore(t *testing.T) {
type S struct {
X int `json:"-"`
}
got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{}))
if err != nil {
t.Fatal(err)
}
if len(got) != 0 {
t.Errorf("got %d fields, want 0", len(got))
}
}
func TestParsedTag(t *testing.T) {
type S struct {
X int `json:"name,omitempty"`
}
got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{}))
if err != nil {
t.Fatal(err)
}
want := []*Field{
{Name: "name", NameFromTag: true, Type: intType,
Index: []int{0}, ParsedTag: []string{"omitempty"}},
}
if msg, ok := compareFields(got, want); !ok {
t.Error(msg)
}
}
func TestValidateFunc(t *testing.T) {
type MyInvalidStruct struct {
A string
B []int
}
_, err := NewCache(nil, validateFunc, nil).Fields(reflect.TypeOf(MyInvalidStruct{}))
if err == nil {
t.Fatal("expected error, got nil")
}
type MyValidStruct struct {
A string
B int
}
_, err = NewCache(nil, validateFunc, nil).Fields(reflect.TypeOf(MyValidStruct{}))
if err != nil {
t.Fatalf("expected nil, got error: %s\n", err)
}
}
func compareFields(got []Field, want []*Field) (msg string, ok bool) {
if len(got) != len(want) {
return fmt.Sprintf("got %d fields, want %d", len(got), len(want)), false
}
for i, g := range got {
w := *want[i]
if !fieldsEqual(&g, &w) {
return fmt.Sprintf("got %+v, want %+v", g, w), false
}
}
return "", true
}
// Need this because Field contains a function, which cannot be compared even
// by testutil.Equal.
func fieldsEqual(f1, f2 *Field) bool {
if f1 == nil || f2 == nil {
return f1 == f2
}
return f1.Name == f2.Name &&
f1.NameFromTag == f2.NameFromTag &&
f1.Type == f2.Type &&
testutil.Equal(f1.ParsedTag, f2.ParsedTag)
}
// Set the fields of dst from those of src.
// dst must be a pointer to a struct value.
// src must be a struct value.
func setFields(fields []Field, dst, src interface{}) {
vsrc := reflect.ValueOf(src)
vdst := reflect.ValueOf(dst).Elem()
for _, f := range fields {
fdst := vdst.FieldByIndex(f.Index)
fsrc := vsrc.FieldByIndex(f.Index)
fdst.Set(fsrc)
}
}
func jsonRoundTrip(t *testing.T, in, out interface{}) {
bytes, err := json.Marshal(in)
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(bytes, out); err != nil {
t.Fatal(err)
}
}
type S3 struct {
S4
Abc int
AbC int
Tag int
X int `json:"Tag"`
unexported int
}
type S4 struct {
ABc int
Y int `json:"Abc"` // ignored because of top-level Abc
}
func TestMatchingField(t *testing.T) {
fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S3{}))
if err != nil {
t.Fatal(err)
}
for _, test := range []struct {
name string
want *Field
}{
// Exact match wins.
{"Abc", field("Abc", int(0), 1)},
{"AbC", field("AbC", int(0), 2)},
{"ABc", field("ABc", int(0), 0, 0)},
// If there are multiple matches but no exact match or tag,
// the first field wins, lexicographically by index.
// Here, "ABc" is at a deeper embedding level, but since S4 appears
// first in S3, its index precedes the other fields of S3.
{"abc", field("ABc", int(0), 0, 0)},
// Tag name takes precedence over untagged field of the same name.
{"Tag", tfield("Tag", int(0), 4)},
// Unexported fields disappear.
{"unexported", nil},
// Untagged embedded structs disappear.
{"S4", nil},
} {
if got := fields.Match(test.name); !fieldsEqual(got, test.want) {
t.Errorf("match %q:\ngot %+v\nwant %+v", test.name, got, test.want)
}
}
}
func TestAgainstJSONMatchingField(t *testing.T) {
s3 := S3{
S4: S4{ABc: 1, Y: 2},
Abc: 3,
AbC: 4,
Tag: 5,
X: 6,
unexported: 7,
}
var want S3
jsonRoundTrip(t, s3, &want)
v := reflect.ValueOf(want)
fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S3{}))
if err != nil {
t.Fatal(err)
}
for _, test := range []struct {
name string
got int
}{
{"Abc", 3},
{"AbC", 4},
{"ABc", 1},
{"abc", 1},
{"Tag", 6},
} {
f := fields.Match(test.name)
if f == nil {
t.Fatalf("%s: no match", test.name)
}
w := v.FieldByIndex(f.Index).Interface()
if test.got != w {
t.Errorf("%s: got %d, want %d", test.name, test.got, w)
}
}
}
func TestTagErrors(t *testing.T) {
called := false
c := NewCache(func(t reflect.StructTag) (string, bool, interface{}, error) {
called = true
s := t.Get("f")
if s == "bad" {
return "", false, nil, errors.New("error")
}
return s, true, nil, nil
}, nil, nil)
type T struct {
X int `f:"ok"`
Y int `f:"bad"`
}
_, err := c.Fields(reflect.TypeOf(T{}))
if !called {
t.Fatal("tag parser not called")
}
if err == nil {
t.Error("want error, got nil")
}
// Second time, we should cache the error.
called = false
_, err = c.Fields(reflect.TypeOf(T{}))
if called {
t.Fatal("tag parser called on second time")
}
if err == nil {
t.Error("want error, got nil")
}
}

156
vendor/cloud.google.com/go/internal/fields/fold.go generated vendored Normal file
View File

@@ -0,0 +1,156 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fields
// This file was copied from https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/fold.go.
// Only the license and package were changed.
import (
"bytes"
"unicode/utf8"
)
const (
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
kelvin = '\u212a'
smallLongEss = '\u017f'
)
// foldFunc returns one of four different case folding equivalence
// functions, from most general (and slow) to fastest:
//
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
// 3) asciiEqualFold, no special, but includes non-letters (including _)
// 4) simpleLetterEqualFold, no specials, no non-letters.
//
// The letters S and K are special because they map to 3 runes, not just 2:
// * S maps to s and to U+017F 'ſ' Latin small letter long s
// * k maps to K and to U+212A '' Kelvin sign
// See https://play.golang.org/p/tTxjOc0OGo
//
// The returned function is specialized for matching against s and
// should only be given s. It's not curried for performance reasons.
func foldFunc(s []byte) func(s, t []byte) bool {
nonLetter := false
special := false // special letter
for _, b := range s {
if b >= utf8.RuneSelf {
return bytes.EqualFold
}
upper := b & caseMask
if upper < 'A' || upper > 'Z' {
nonLetter = true
} else if upper == 'K' || upper == 'S' {
// See above for why these letters are special.
special = true
}
}
if special {
return equalFoldRight
}
if nonLetter {
return asciiEqualFold
}
return simpleLetterEqualFold
}
// equalFoldRight is a specialization of bytes.EqualFold when s is
// known to be all ASCII (including punctuation), but contains an 's',
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
// See comments on foldFunc.
func equalFoldRight(s, t []byte) bool {
for _, sb := range s {
if len(t) == 0 {
return false
}
tb := t[0]
if tb < utf8.RuneSelf {
if sb != tb {
sbUpper := sb & caseMask
if 'A' <= sbUpper && sbUpper <= 'Z' {
if sbUpper != tb&caseMask {
return false
}
} else {
return false
}
}
t = t[1:]
continue
}
// sb is ASCII and t is not. t must be either kelvin
// sign or long s; sb must be s, S, k, or K.
tr, size := utf8.DecodeRune(t)
switch sb {
case 's', 'S':
if tr != smallLongEss {
return false
}
case 'k', 'K':
if tr != kelvin {
return false
}
default:
return false
}
t = t[size:]
}
if len(t) > 0 {
return false
}
return true
}
// asciiEqualFold is a specialization of bytes.EqualFold for use when
// s is all ASCII (but may contain non-letters) and contains no
// special-folding letters.
// See comments on foldFunc.
func asciiEqualFold(s, t []byte) bool {
if len(s) != len(t) {
return false
}
for i, sb := range s {
tb := t[i]
if sb == tb {
continue
}
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
if sb&caseMask != tb&caseMask {
return false
}
} else {
return false
}
}
return true
}
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
// use when s is all ASCII letters (no underscores, etc) and also
// doesn't contain 'k', 'K', 's', or 'S'.
// See comments on foldFunc.
func simpleLetterEqualFold(s, t []byte) bool {
if len(s) != len(t) {
return false
}
for i, b := range s {
if b&caseMask != t[i]&caseMask {
return false
}
}
return true
}

129
vendor/cloud.google.com/go/internal/fields/fold_test.go generated vendored Normal file
View File

@@ -0,0 +1,129 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fields
// This file was copied from https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/fold_test.go.
// Only the license and package were changed.
import (
"bytes"
"strings"
"testing"
"unicode/utf8"
)
var foldTests = []struct {
fn func(s, t []byte) bool
s, t string
want bool
}{
{equalFoldRight, "", "", true},
{equalFoldRight, "a", "a", true},
{equalFoldRight, "", "a", false},
{equalFoldRight, "a", "", false},
{equalFoldRight, "a", "A", true},
{equalFoldRight, "AB", "ab", true},
{equalFoldRight, "AB", "ac", false},
{equalFoldRight, "sbkKc", "ſbKc", true},
{equalFoldRight, "SbKkc", "ſbKc", true},
{equalFoldRight, "SbKkc", "ſbKK", false},
{equalFoldRight, "e", "é", false},
{equalFoldRight, "s", "S", true},
{simpleLetterEqualFold, "", "", true},
{simpleLetterEqualFold, "abc", "abc", true},
{simpleLetterEqualFold, "abc", "ABC", true},
{simpleLetterEqualFold, "abc", "ABCD", false},
{simpleLetterEqualFold, "abc", "xxx", false},
{asciiEqualFold, "a_B", "A_b", true},
{asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
}
func TestFold(t *testing.T) {
for i, tt := range foldTests {
if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
}
truth := strings.EqualFold(tt.s, tt.t)
if truth != tt.want {
t.Errorf("strings.EqualFold doesn't agree with case %d", i)
}
}
}
func TestFoldAgainstUnicode(t *testing.T) {
const bufSize = 5
buf1 := make([]byte, 0, bufSize)
buf2 := make([]byte, 0, bufSize)
var runes []rune
for i := 0x20; i <= 0x7f; i++ {
runes = append(runes, rune(i))
}
runes = append(runes, kelvin, smallLongEss)
funcs := []struct {
name string
fold func(s, t []byte) bool
letter bool // must be ASCII letter
simple bool // must be simple ASCII letter (not 'S' or 'K')
}{
{
name: "equalFoldRight",
fold: equalFoldRight,
},
{
name: "asciiEqualFold",
fold: asciiEqualFold,
simple: true,
},
{
name: "simpleLetterEqualFold",
fold: simpleLetterEqualFold,
simple: true,
letter: true,
},
}
for _, ff := range funcs {
for _, r := range runes {
if r >= utf8.RuneSelf {
continue
}
if ff.letter && !isASCIILetter(byte(r)) {
continue
}
if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
continue
}
for _, r2 := range runes {
buf1 := append(buf1[:0], 'x')
buf2 := append(buf2[:0], 'x')
buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
buf1 = append(buf1, 'x')
buf2 = append(buf2, 'x')
want := bytes.EqualFold(buf1, buf2)
if got := ff.fold(buf1, buf2); got != want {
t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
}
}
}
}
}
func isASCIILetter(b byte) bool {
return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
}