From 3dc868bef8e0923ec06544faaee1cfbe57d81e9d Mon Sep 17 00:00:00 2001 From: MTRNord Date: Thu, 14 Dec 2017 21:57:29 +0100 Subject: [PATCH] fix broken vendoring of structs 2/2 --- vendor/src/github.com/fatih/structs/LICENSE | 21 + vendor/src/github.com/fatih/structs/README.md | 163 ++ vendor/src/github.com/fatih/structs/field.go | 141 ++ .../github.com/fatih/structs/field_test.go | 397 +++++ .../src/github.com/fatih/structs/structs.go | 586 +++++++ .../fatih/structs/structs_example_test.go | 351 ++++ .../github.com/fatih/structs/structs_test.go | 1453 +++++++++++++++++ vendor/src/github.com/fatih/structs/tags.go | 32 + .../src/github.com/fatih/structs/tags_test.go | 46 + 9 files changed, 3190 insertions(+) create mode 100644 vendor/src/github.com/fatih/structs/LICENSE create mode 100644 vendor/src/github.com/fatih/structs/README.md create mode 100644 vendor/src/github.com/fatih/structs/field.go create mode 100644 vendor/src/github.com/fatih/structs/field_test.go create mode 100644 vendor/src/github.com/fatih/structs/structs.go create mode 100644 vendor/src/github.com/fatih/structs/structs_example_test.go create mode 100644 vendor/src/github.com/fatih/structs/structs_test.go create mode 100644 vendor/src/github.com/fatih/structs/tags.go create mode 100644 vendor/src/github.com/fatih/structs/tags_test.go diff --git a/vendor/src/github.com/fatih/structs/LICENSE b/vendor/src/github.com/fatih/structs/LICENSE new file mode 100644 index 0000000..34504e4 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/src/github.com/fatih/structs/README.md b/vendor/src/github.com/fatih/structs/README.md new file mode 100644 index 0000000..44e0100 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/README.md @@ -0,0 +1,163 @@ +# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs) + +Structs contains various utilities to work with Go (Golang) structs. It was +initially used by me to convert a struct into a `map[string]interface{}`. With +time I've added other utilities for structs. It's basically a high level +package based on primitives from the reflect package. Feel free to add new +functions or improve the existing code. + +## Install + +```bash +go get github.com/fatih/structs +``` + +## Usage and Examples + +Just like the standard lib `strings`, `bytes` and co packages, `structs` has +many global functions to manipulate or organize your struct data. Lets define +and declare a struct: + +```go +type Server struct { + Name string `json:"name,omitempty"` + ID int + Enabled bool + users []string // not exported + http.Server // embedded +} + +server := &Server{ + Name: "gopher", + ID: 123456, + Enabled: true, +} +``` + +```go +// Convert a struct to a map[string]interface{} +// => {"Name":"gopher", "ID":123456, "Enabled":true} +m := structs.Map(server) + +// Convert the values of a struct to a []interface{} +// => ["gopher", 123456, true] +v := structs.Values(server) + +// Convert the names of a struct to a []string +// (see "Names methods" for more info about fields) +n := structs.Names(server) + +// Convert the values of a struct to a []*Field +// (see "Field methods" for more info about fields) +f := structs.Fields(server) + +// Return the struct name => "Server" +n := structs.Name(server) + +// Check if any field of a struct is initialized or not. +h := structs.HasZero(server) + +// Check if all fields of a struct is initialized or not. +z := structs.IsZero(server) + +// Check if server is a struct or a pointer to struct +i := structs.IsStruct(server) +``` + +### Struct methods + +The structs functions can be also used as independent methods by creating a new +`*structs.Struct`. This is handy if you want to have more control over the +structs (such as retrieving a single Field). + +```go +// Create a new struct type: +s := structs.New(server) + +m := s.Map() // Get a map[string]interface{} +v := s.Values() // Get a []interface{} +f := s.Fields() // Get a []*Field +n := s.Names() // Get a []string +f := s.Field(name) // Get a *Field based on the given field name +f, ok := s.FieldOk(name) // Get a *Field based on the given field name +n := s.Name() // Get the struct name +h := s.HasZero() // Check if any field is initialized +z := s.IsZero() // Check if all fields are initialized +``` + +### Field methods + +We can easily examine a single Field for more detail. Below you can see how we +get and interact with various field methods: + + +```go +s := structs.New(server) + +// Get the Field struct for the "Name" field +name := s.Field("Name") + +// Get the underlying value, value => "gopher" +value := name.Value().(string) + +// Set the field's value +name.Set("another gopher") + +// Get the field's kind, kind => "string" +name.Kind() + +// Check if the field is exported or not +if name.IsExported() { + fmt.Println("Name field is exported") +} + +// Check if the value is a zero value, such as "" for string, 0 for int +if !name.IsZero() { + fmt.Println("Name is initialized") +} + +// Check if the field is an anonymous (embedded) field +if !name.IsEmbedded() { + fmt.Println("Name is not an embedded field") +} + +// Get the Field's tag value for tag name "json", tag value => "name,omitempty" +tagValue := name.Tag("json") +``` + +Nested structs are supported too: + +```go +addrField := s.Field("Server").Field("Addr") + +// Get the value for addr +a := addrField.Value().(string) + +// Or get all fields +httpServer := s.Field("Server").Fields() +``` + +We can also get a slice of Fields from the Struct type to iterate over all +fields. This is handy if you wish to examine all fields: + +```go +s := structs.New(server) + +for _, f := range s.Fields() { + fmt.Printf("field name: %+v\n", f.Name()) + + if f.IsExported() { + fmt.Printf("value : %+v\n", f.Value()) + fmt.Printf("is zero : %+v\n", f.IsZero()) + } +} +``` + +## Credits + + * [Fatih Arslan](https://github.com/fatih) + * [Cihangir Savas](https://github.com/cihangir) + +## License + +The MIT License (MIT) - see LICENSE.md for more details diff --git a/vendor/src/github.com/fatih/structs/field.go b/vendor/src/github.com/fatih/structs/field.go new file mode 100644 index 0000000..e697832 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/field.go @@ -0,0 +1,141 @@ +package structs + +import ( + "errors" + "fmt" + "reflect" +) + +var ( + errNotExported = errors.New("field is not exported") + errNotSettable = errors.New("field is not settable") +) + +// Field represents a single struct field that encapsulates high level +// functions around the field. +type Field struct { + value reflect.Value + field reflect.StructField + defaultTag string +} + +// Tag returns the value associated with key in the tag string. If there is no +// such key in the tag, Tag returns the empty string. +func (f *Field) Tag(key string) string { + return f.field.Tag.Get(key) +} + +// Value returns the underlying value of the field. It panics if the field +// is not exported. +func (f *Field) Value() interface{} { + return f.value.Interface() +} + +// IsEmbedded returns true if the given field is an anonymous field (embedded) +func (f *Field) IsEmbedded() bool { + return f.field.Anonymous +} + +// IsExported returns true if the given field is exported. +func (f *Field) IsExported() bool { + return f.field.PkgPath == "" +} + +// IsZero returns true if the given field is not initialized (has a zero value). +// It panics if the field is not exported. +func (f *Field) IsZero() bool { + zero := reflect.Zero(f.value.Type()).Interface() + current := f.Value() + + return reflect.DeepEqual(current, zero) +} + +// Name returns the name of the given field +func (f *Field) Name() string { + return f.field.Name +} + +// Kind returns the fields kind, such as "string", "map", "bool", etc .. +func (f *Field) Kind() reflect.Kind { + return f.value.Kind() +} + +// Set sets the field to given value v. It returns an error if the field is not +// settable (not addressable or not exported) or if the given value's type +// doesn't match the fields type. +func (f *Field) Set(val interface{}) error { + // we can't set unexported fields, so be sure this field is exported + if !f.IsExported() { + return errNotExported + } + + // do we get here? not sure... + if !f.value.CanSet() { + return errNotSettable + } + + given := reflect.ValueOf(val) + + if f.value.Kind() != given.Kind() { + return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind()) + } + + f.value.Set(given) + return nil +} + +// Zero sets the field to its zero value. It returns an error if the field is not +// settable (not addressable or not exported). +func (f *Field) Zero() error { + zero := reflect.Zero(f.value.Type()).Interface() + return f.Set(zero) +} + +// Fields returns a slice of Fields. This is particular handy to get the fields +// of a nested struct . A struct tag with the content of "-" ignores the +// checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field *http.Request `structs:"-"` +// +// It panics if field is not exported or if field's kind is not struct +func (f *Field) Fields() []*Field { + return getFields(f.value, f.defaultTag) +} + +// Field returns the field from a nested struct. It panics if the nested struct +// is not exported or if the field was not found. +func (f *Field) Field(name string) *Field { + field, ok := f.FieldOk(name) + if !ok { + panic("field not found") + } + + return field +} + +// FieldOk returns the field from a nested struct. The boolean returns whether +// the field was found (true) or not (false). +func (f *Field) FieldOk(name string) (*Field, bool) { + value := &f.value + // value must be settable so we need to make sure it holds the address of the + // variable and not a copy, so we can pass the pointer to strctVal instead of a + // copy (which is not assigned to any variable, hence not settable). + // see "https://blog.golang.org/laws-of-reflection#TOC_8." + if f.value.Kind() != reflect.Ptr { + a := f.value.Addr() + value = &a + } + v := strctVal(value.Interface()) + t := v.Type() + + field, ok := t.FieldByName(name) + if !ok { + return nil, false + } + + return &Field{ + field: field, + value: v.FieldByName(name), + }, true +} diff --git a/vendor/src/github.com/fatih/structs/field_test.go b/vendor/src/github.com/fatih/structs/field_test.go new file mode 100644 index 0000000..de9dc3b --- /dev/null +++ b/vendor/src/github.com/fatih/structs/field_test.go @@ -0,0 +1,397 @@ +package structs + +import ( + "reflect" + "testing" +) + +// A test struct that defines all cases +type Foo struct { + A string + B int `structs:"y"` + C bool `json:"c"` + d string // not exported + E *Baz + x string `xml:"x"` // not exported, with tag + Y []string + Z map[string]interface{} + *Bar // embedded +} + +type Baz struct { + A string + B int +} + +type Bar struct { + E string + F int + g []string +} + +func newStruct() *Struct { + b := &Bar{ + E: "example", + F: 2, + g: []string{"zeynep", "fatih"}, + } + + // B and x is not initialized for testing + f := &Foo{ + A: "gopher", + C: true, + d: "small", + E: nil, + Y: []string{"example"}, + Z: nil, + } + f.Bar = b + + return New(f) +} + +func TestField_Set(t *testing.T) { + s := newStruct() + + f := s.Field("A") + err := f.Set("fatih") + if err != nil { + t.Error(err) + } + + if f.Value().(string) != "fatih" { + t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih") + } + + f = s.Field("Y") + err = f.Set([]string{"override", "with", "this"}) + if err != nil { + t.Error(err) + } + + sliceLen := len(f.Value().([]string)) + if sliceLen != 3 { + t.Errorf("Setted values slice length is wrong: %d, want: %d", sliceLen, 3) + } + + f = s.Field("C") + err = f.Set(false) + if err != nil { + t.Error(err) + } + + if f.Value().(bool) { + t.Errorf("Setted value is wrong: %t want: %t", f.Value().(bool), false) + } + + // let's pass a different type + f = s.Field("A") + err = f.Set(123) // Field A is of type string, but we are going to pass an integer + if err == nil { + t.Error("Setting a field's value with a different type than the field's type should return an error") + } + + // old value should be still there :) + if f.Value().(string) != "fatih" { + t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih") + } + + // let's access an unexported field, which should give an error + f = s.Field("d") + err = f.Set("large") + if err != errNotExported { + t.Error(err) + } + + // let's set a pointer to struct + b := &Bar{ + E: "gopher", + F: 2, + } + + f = s.Field("Bar") + err = f.Set(b) + if err != nil { + t.Error(err) + } + + baz := &Baz{ + A: "helloWorld", + B: 42, + } + + f = s.Field("E") + err = f.Set(baz) + if err != nil { + t.Error(err) + } + + ba := s.Field("E").Value().(*Baz) + + if ba.A != "helloWorld" { + t.Errorf("could not set baz. Got: %s Want: helloWorld", ba.A) + } +} + +func TestField_NotSettable(t *testing.T) { + a := map[int]Baz{ + 4: Baz{ + A: "value", + }, + } + + s := New(a[4]) + + if err := s.Field("A").Set("newValue"); err != errNotSettable { + t.Errorf("Trying to set non-settable field should error with %q. Got %q instead.", errNotSettable, err) + } +} + +func TestField_Zero(t *testing.T) { + s := newStruct() + + f := s.Field("A") + err := f.Zero() + if err != nil { + t.Error(err) + } + + if f.Value().(string) != "" { + t.Errorf("Zeroed value is wrong: %s want: %s", f.Value().(string), "") + } + + f = s.Field("Y") + err = f.Zero() + if err != nil { + t.Error(err) + } + + sliceLen := len(f.Value().([]string)) + if sliceLen != 0 { + t.Errorf("Zeroed values slice length is wrong: %d, want: %d", sliceLen, 0) + } + + f = s.Field("C") + err = f.Zero() + if err != nil { + t.Error(err) + } + + if f.Value().(bool) { + t.Errorf("Zeroed value is wrong: %t want: %t", f.Value().(bool), false) + } + + // let's access an unexported field, which should give an error + f = s.Field("d") + err = f.Zero() + if err != errNotExported { + t.Error(err) + } + + f = s.Field("Bar") + err = f.Zero() + if err != nil { + t.Error(err) + } + + f = s.Field("E") + err = f.Zero() + if err != nil { + t.Error(err) + } + + v := s.Field("E").value + if !v.IsNil() { + t.Errorf("could not set baz. Got: %s Want: ", v.Interface()) + } +} + +func TestField(t *testing.T) { + s := newStruct() + + defer func() { + err := recover() + if err == nil { + t.Error("Retrieveing a non existing field from the struct should panic") + } + }() + + _ = s.Field("no-field") +} + +func TestField_Kind(t *testing.T) { + s := newStruct() + + f := s.Field("A") + if f.Kind() != reflect.String { + t.Errorf("Field A has wrong kind: %s want: %s", f.Kind(), reflect.String) + } + + f = s.Field("B") + if f.Kind() != reflect.Int { + t.Errorf("Field B has wrong kind: %s want: %s", f.Kind(), reflect.Int) + } + + // unexported + f = s.Field("d") + if f.Kind() != reflect.String { + t.Errorf("Field d has wrong kind: %s want: %s", f.Kind(), reflect.String) + } +} + +func TestField_Tag(t *testing.T) { + s := newStruct() + + v := s.Field("B").Tag("json") + if v != "" { + t.Errorf("Field's tag value of a non existing tag should return empty, got: %s", v) + } + + v = s.Field("C").Tag("json") + if v != "c" { + t.Errorf("Field's tag value of the existing field C should return 'c', got: %s", v) + } + + v = s.Field("d").Tag("json") + if v != "" { + t.Errorf("Field's tag value of a non exported field should return empty, got: %s", v) + } + + v = s.Field("x").Tag("xml") + if v != "x" { + t.Errorf("Field's tag value of a non exported field with a tag should return 'x', got: %s", v) + } + + v = s.Field("A").Tag("json") + if v != "" { + t.Errorf("Field's tag value of a existing field without a tag should return empty, got: %s", v) + } +} + +func TestField_Value(t *testing.T) { + s := newStruct() + + v := s.Field("A").Value() + val, ok := v.(string) + if !ok { + t.Errorf("Field's value of a A should be string") + } + + if val != "gopher" { + t.Errorf("Field's value of a existing tag should return 'gopher', got: %s", val) + } + + defer func() { + err := recover() + if err == nil { + t.Error("Value of a non exported field from the field should panic") + } + }() + + // should panic + _ = s.Field("d").Value() +} + +func TestField_IsEmbedded(t *testing.T) { + s := newStruct() + + if !s.Field("Bar").IsEmbedded() { + t.Errorf("Fields 'Bar' field is an embedded field") + } + + if s.Field("d").IsEmbedded() { + t.Errorf("Fields 'd' field is not an embedded field") + } +} + +func TestField_IsExported(t *testing.T) { + s := newStruct() + + if !s.Field("Bar").IsExported() { + t.Errorf("Fields 'Bar' field is an exported field") + } + + if !s.Field("A").IsExported() { + t.Errorf("Fields 'A' field is an exported field") + } + + if s.Field("d").IsExported() { + t.Errorf("Fields 'd' field is not an exported field") + } +} + +func TestField_IsZero(t *testing.T) { + s := newStruct() + + if s.Field("A").IsZero() { + t.Errorf("Fields 'A' field is an initialized field") + } + + if !s.Field("B").IsZero() { + t.Errorf("Fields 'B' field is not an initialized field") + } +} + +func TestField_Name(t *testing.T) { + s := newStruct() + + if s.Field("A").Name() != "A" { + t.Errorf("Fields 'A' field should have the name 'A'") + } +} + +func TestField_Field(t *testing.T) { + s := newStruct() + + e := s.Field("Bar").Field("E") + + val, ok := e.Value().(string) + if !ok { + t.Error("The value of the field 'e' inside 'Bar' struct should be string") + } + + if val != "example" { + t.Errorf("The value of 'e' should be 'example, got: %s", val) + } + + defer func() { + err := recover() + if err == nil { + t.Error("Field of a non existing nested struct should panic") + } + }() + + _ = s.Field("Bar").Field("e") +} + +func TestField_Fields(t *testing.T) { + s := newStruct() + fields := s.Field("Bar").Fields() + + if len(fields) != 3 { + t.Errorf("We expect 3 fields in embedded struct, was: %d", len(fields)) + } +} + +func TestField_FieldOk(t *testing.T) { + s := newStruct() + + b, ok := s.FieldOk("Bar") + if !ok { + t.Error("The field 'Bar' should exists.") + } + + e, ok := b.FieldOk("E") + if !ok { + t.Error("The field 'E' should exists.") + } + + val, ok := e.Value().(string) + if !ok { + t.Error("The value of the field 'e' inside 'Bar' struct should be string") + } + + if val != "example" { + t.Errorf("The value of 'e' should be 'example, got: %s", val) + } +} diff --git a/vendor/src/github.com/fatih/structs/structs.go b/vendor/src/github.com/fatih/structs/structs.go new file mode 100644 index 0000000..be3816a --- /dev/null +++ b/vendor/src/github.com/fatih/structs/structs.go @@ -0,0 +1,586 @@ +// Package structs contains various utilities functions to work with structs. +package structs + +import ( + "fmt" + + "reflect" +) + +var ( + // DefaultTagName is the default tag name for struct fields which provides + // a more granular to tweak certain structs. Lookup the necessary functions + // for more info. + DefaultTagName = "structs" // struct's field default tag name +) + +// Struct encapsulates a struct type to provide several high level functions +// around the struct. +type Struct struct { + raw interface{} + value reflect.Value + TagName string +} + +// New returns a new *Struct with the struct s. It panics if the s's kind is +// not struct. +func New(s interface{}) *Struct { + return &Struct{ + raw: s, + value: strctVal(s), + TagName: DefaultTagName, + } +} + +// Map converts the given struct to a map[string]interface{}, where the keys +// of the map are the field names and the values of the map the associated +// values of the fields. The default key string is the struct field name but +// can be changed in the struct field's tag value. The "structs" key in the +// struct's field tag value is the key name. Example: +// +// // Field appears in map as key "myName". +// Name string `structs:"myName"` +// +// A tag value with the content of "-" ignores that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A tag value with the content of "string" uses the stringer to get the value. Example: +// +// // The value will be output of Animal's String() func. +// // Map will panic if Animal does not implement String(). +// Field *Animal `structs:"field,string"` +// +// A tag value with the option of "flatten" used in a struct field is to flatten its fields +// in the output map. Example: +// +// // The FieldStruct's fields will be flattened into the output map. +// FieldStruct time.Time `structs:",flatten"` +// +// A tag value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// A tag value with the option of "omitempty" ignores that particular field if +// the field value is empty. Example: +// +// // Field appears in map as key "myName", but the field is +// // skipped if empty. +// Field string `structs:"myName,omitempty"` +// +// // Field appears in map as key "Field" (the default), but +// // the field is skipped if empty. +// Field string `structs:",omitempty"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. +func (s *Struct) Map() map[string]interface{} { + out := make(map[string]interface{}) + s.FillMap(out) + return out +} + +// FillMap is the same as Map. Instead of returning the output, it fills the +// given map. +func (s *Struct) FillMap(out map[string]interface{}) { + if out == nil { + return + } + + fields := s.structFields() + + for _, field := range fields { + name := field.Name + val := s.value.FieldByName(name) + isSubStruct := false + var finalVal interface{} + + tagName, tagOpts := parseTag(field.Tag.Get(s.TagName)) + if tagName != "" { + name = tagName + } + + // if the value is a zero value and the field is marked as omitempty do + // not include + if tagOpts.Has("omitempty") { + zero := reflect.Zero(val.Type()).Interface() + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + continue + } + } + + if !tagOpts.Has("omitnested") { + finalVal = s.nested(val) + + v := reflect.ValueOf(val.Interface()) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Map, reflect.Struct: + isSubStruct = true + } + } else { + finalVal = val.Interface() + } + + if tagOpts.Has("string") { + s, ok := val.Interface().(fmt.Stringer) + if ok { + out[name] = s.String() + } + continue + } + + if isSubStruct && (tagOpts.Has("flatten")) { + for k := range finalVal.(map[string]interface{}) { + out[k] = finalVal.(map[string]interface{})[k] + } + } else { + out[name] = finalVal + } + } +} + +// Values converts the given s struct's field values to a []interface{}. A +// struct tag with the content of "-" ignores the that particular field. +// Example: +// +// // Field is ignored by this package. +// Field int `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Fields is not processed further by this package. +// Field time.Time `structs:",omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// A tag value with the option of "omitempty" ignores that particular field and +// is not added to the values if the field value is empty. Example: +// +// // Field is skipped if empty +// Field string `structs:",omitempty"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. +func (s *Struct) Values() []interface{} { + fields := s.structFields() + + var t []interface{} + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + // if the value is a zero value and the field is marked as omitempty do + // not include + if tagOpts.Has("omitempty") { + zero := reflect.Zero(val.Type()).Interface() + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + continue + } + } + + if tagOpts.Has("string") { + s, ok := val.Interface().(fmt.Stringer) + if ok { + t = append(t, s.String()) + } + continue + } + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + // look out for embedded structs, and convert them to a + // []interface{} to be added to the final values slice + for _, embeddedVal := range Values(val.Interface()) { + t = append(t, embeddedVal) + } + } else { + t = append(t, val.Interface()) + } + } + + return t +} + +// Fields returns a slice of Fields. A struct tag with the content of "-" +// ignores the checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// It panics if s's kind is not struct. +func (s *Struct) Fields() []*Field { + return getFields(s.value, s.TagName) +} + +// Names returns a slice of field names. A struct tag with the content of "-" +// ignores the checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// It panics if s's kind is not struct. +func (s *Struct) Names() []string { + fields := getFields(s.value, s.TagName) + + names := make([]string, len(fields)) + + for i, field := range fields { + names[i] = field.Name() + } + + return names +} + +func getFields(v reflect.Value, tagName string) []*Field { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + t := v.Type() + + var fields []*Field + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + + if tag := field.Tag.Get(tagName); tag == "-" { + continue + } + + f := &Field{ + field: field, + value: v.FieldByName(field.Name), + } + + fields = append(fields, f) + + } + + return fields +} + +// Field returns a new Field struct that provides several high level functions +// around a single struct field entity. It panics if the field is not found. +func (s *Struct) Field(name string) *Field { + f, ok := s.FieldOk(name) + if !ok { + panic("field not found") + } + + return f +} + +// FieldOk returns a new Field struct that provides several high level functions +// around a single struct field entity. The boolean returns true if the field +// was found. +func (s *Struct) FieldOk(name string) (*Field, bool) { + t := s.value.Type() + + field, ok := t.FieldByName(name) + if !ok { + return nil, false + } + + return &Field{ + field: field, + value: s.value.FieldByName(name), + defaultTag: s.TagName, + }, true +} + +// IsZero returns true if all fields in a struct is a zero value (not +// initialized) A struct tag with the content of "-" ignores the checking of +// that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. It panics if s's kind is not struct. +func (s *Struct) IsZero() bool { + fields := s.structFields() + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + ok := IsZero(val.Interface()) + if !ok { + return false + } + + continue + } + + // zero value of the given field, such as "" for string, 0 for int + zero := reflect.Zero(val.Type()).Interface() + + // current value of the given field + current := val.Interface() + + if !reflect.DeepEqual(current, zero) { + return false + } + } + + return true +} + +// HasZero returns true if a field in a struct is not initialized (zero value). +// A struct tag with the content of "-" ignores the checking of that particular +// field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. It panics if s's kind is not struct. +func (s *Struct) HasZero() bool { + fields := s.structFields() + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + ok := HasZero(val.Interface()) + if ok { + return true + } + + continue + } + + // zero value of the given field, such as "" for string, 0 for int + zero := reflect.Zero(val.Type()).Interface() + + // current value of the given field + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + return true + } + } + + return false +} + +// Name returns the structs's type name within its package. For more info refer +// to Name() function. +func (s *Struct) Name() string { + return s.value.Type().Name() +} + +// structFields returns the exported struct fields for a given s struct. This +// is a convenient helper method to avoid duplicate code in some of the +// functions. +func (s *Struct) structFields() []reflect.StructField { + t := s.value.Type() + + var f []reflect.StructField + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + // we can't access the value of unexported fields + if field.PkgPath != "" { + continue + } + + // don't check if it's omitted + if tag := field.Tag.Get(s.TagName); tag == "-" { + continue + } + + f = append(f, field) + } + + return f +} + +func strctVal(s interface{}) reflect.Value { + v := reflect.ValueOf(s) + + // if pointer get the underlying element≤ + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + panic("not struct") + } + + return v +} + +// Map converts the given struct to a map[string]interface{}. For more info +// refer to Struct types Map() method. It panics if s's kind is not struct. +func Map(s interface{}) map[string]interface{} { + return New(s).Map() +} + +// FillMap is the same as Map. Instead of returning the output, it fills the +// given map. +func FillMap(s interface{}, out map[string]interface{}) { + New(s).FillMap(out) +} + +// Values converts the given struct to a []interface{}. For more info refer to +// Struct types Values() method. It panics if s's kind is not struct. +func Values(s interface{}) []interface{} { + return New(s).Values() +} + +// Fields returns a slice of *Field. For more info refer to Struct types +// Fields() method. It panics if s's kind is not struct. +func Fields(s interface{}) []*Field { + return New(s).Fields() +} + +// Names returns a slice of field names. For more info refer to Struct types +// Names() method. It panics if s's kind is not struct. +func Names(s interface{}) []string { + return New(s).Names() +} + +// IsZero returns true if all fields is equal to a zero value. For more info +// refer to Struct types IsZero() method. It panics if s's kind is not struct. +func IsZero(s interface{}) bool { + return New(s).IsZero() +} + +// HasZero returns true if any field is equal to a zero value. For more info +// refer to Struct types HasZero() method. It panics if s's kind is not struct. +func HasZero(s interface{}) bool { + return New(s).HasZero() +} + +// IsStruct returns true if the given variable is a struct or a pointer to +// struct. +func IsStruct(s interface{}) bool { + v := reflect.ValueOf(s) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + // uninitialized zero value of a struct + if v.Kind() == reflect.Invalid { + return false + } + + return v.Kind() == reflect.Struct +} + +// Name returns the structs's type name within its package. It returns an +// empty string for unnamed types. It panics if s's kind is not struct. +func Name(s interface{}) string { + return New(s).Name() +} + +// nested retrieves recursively all types for the given value and returns the +// nested value. +func (s *Struct) nested(val reflect.Value) interface{} { + var finalVal interface{} + + v := reflect.ValueOf(val.Interface()) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Struct: + n := New(val.Interface()) + n.TagName = s.TagName + m := n.Map() + + // do not add the converted value if there are no exported fields, ie: + // time.Time + if len(m) == 0 { + finalVal = val.Interface() + } else { + finalVal = m + } + case reflect.Map: + // get the element type of the map + mapElem := val.Type() + switch val.Type().Kind() { + case reflect.Ptr, reflect.Array, reflect.Map, + reflect.Slice, reflect.Chan: + mapElem = val.Type().Elem() + if mapElem.Kind() == reflect.Ptr { + mapElem = mapElem.Elem() + } + } + + // only iterate over struct types, ie: map[string]StructType, + // map[string][]StructType, + if mapElem.Kind() == reflect.Struct || + (mapElem.Kind() == reflect.Slice && + mapElem.Elem().Kind() == reflect.Struct) { + m := make(map[string]interface{}, val.Len()) + for _, k := range val.MapKeys() { + m[k.String()] = s.nested(val.MapIndex(k)) + } + finalVal = m + break + } + + // TODO(arslan): should this be optional? + finalVal = val.Interface() + case reflect.Slice, reflect.Array: + if val.Type().Kind() == reflect.Interface { + finalVal = val.Interface() + break + } + + // TODO(arslan): should this be optional? + // do not iterate of non struct types, just pass the value. Ie: []int, + // []string, co... We only iterate further if it's a struct. + // i.e []foo or []*foo + if val.Type().Elem().Kind() != reflect.Struct && + !(val.Type().Elem().Kind() == reflect.Ptr && + val.Type().Elem().Elem().Kind() == reflect.Struct) { + finalVal = val.Interface() + break + } + + slices := make([]interface{}, val.Len(), val.Len()) + for x := 0; x < val.Len(); x++ { + slices[x] = s.nested(val.Index(x)) + } + finalVal = slices + default: + finalVal = val.Interface() + } + + return finalVal +} diff --git a/vendor/src/github.com/fatih/structs/structs_example_test.go b/vendor/src/github.com/fatih/structs/structs_example_test.go new file mode 100644 index 0000000..329c130 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/structs_example_test.go @@ -0,0 +1,351 @@ +package structs + +import ( + "fmt" + "time" +) + +func ExampleNew() { + type Server struct { + Name string + ID int32 + Enabled bool + } + + server := &Server{ + Name: "Arslan", + ID: 123456, + Enabled: true, + } + + s := New(server) + + fmt.Printf("Name : %v\n", s.Name()) + fmt.Printf("Values : %v\n", s.Values()) + fmt.Printf("Value of ID : %v\n", s.Field("ID").Value()) + // Output: + // Name : Server + // Values : [Arslan 123456 true] + // Value of ID : 123456 + +} + +func ExampleMap() { + type Server struct { + Name string + ID int32 + Enabled bool + } + + s := &Server{ + Name: "Arslan", + ID: 123456, + Enabled: true, + } + + m := Map(s) + + fmt.Printf("%#v\n", m["Name"]) + fmt.Printf("%#v\n", m["ID"]) + fmt.Printf("%#v\n", m["Enabled"]) + // Output: + // "Arslan" + // 123456 + // true + +} + +func ExampleMap_tags() { + // Custom tags can change the map keys instead of using the fields name + type Server struct { + Name string `structs:"server_name"` + ID int32 `structs:"server_id"` + Enabled bool `structs:"enabled"` + } + + s := &Server{ + Name: "Zeynep", + ID: 789012, + } + + m := Map(s) + + // access them by the custom tags defined above + fmt.Printf("%#v\n", m["server_name"]) + fmt.Printf("%#v\n", m["server_id"]) + fmt.Printf("%#v\n", m["enabled"]) + // Output: + // "Zeynep" + // 789012 + // false + +} + +func ExampleMap_omitNested() { + // By default field with struct types are processed too. We can stop + // processing them via "omitnested" tag option. + type Server struct { + Name string `structs:"server_name"` + ID int32 `structs:"server_id"` + Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{} + } + + const shortForm = "2006-Jan-02" + t, _ := time.Parse("2006-Jan-02", "2013-Feb-03") + + s := &Server{ + Name: "Zeynep", + ID: 789012, + Time: t, + } + + m := Map(s) + + // access them by the custom tags defined above + fmt.Printf("%v\n", m["server_name"]) + fmt.Printf("%v\n", m["server_id"]) + fmt.Printf("%v\n", m["time"].(time.Time)) + // Output: + // Zeynep + // 789012 + // 2013-02-03 00:00:00 +0000 UTC +} + +func ExampleMap_omitEmpty() { + // By default field with struct types of zero values are processed too. We + // can stop processing them via "omitempty" tag option. + type Server struct { + Name string `structs:",omitempty"` + ID int32 `structs:"server_id,omitempty"` + Location string + } + + // Only add location + s := &Server{ + Location: "Tokyo", + } + + m := Map(s) + + // map contains only the Location field + fmt.Printf("%v\n", m) + // Output: + // map[Location:Tokyo] +} + +func ExampleValues() { + type Server struct { + Name string + ID int32 + Enabled bool + } + + s := &Server{ + Name: "Fatih", + ID: 135790, + Enabled: false, + } + + m := Values(s) + + fmt.Printf("Values: %+v\n", m) + // Output: + // Values: [Fatih 135790 false] +} + +func ExampleValues_omitEmpty() { + // By default field with struct types of zero values are processed too. We + // can stop processing them via "omitempty" tag option. + type Server struct { + Name string `structs:",omitempty"` + ID int32 `structs:"server_id,omitempty"` + Location string + } + + // Only add location + s := &Server{ + Location: "Ankara", + } + + m := Values(s) + + // values contains only the Location field + fmt.Printf("Values: %+v\n", m) + // Output: + // Values: [Ankara] +} + +func ExampleValues_tags() { + type Location struct { + City string + Country string + } + + type Server struct { + Name string + ID int32 + Enabled bool + Location Location `structs:"-"` // values from location are not included anymore + } + + s := &Server{ + Name: "Fatih", + ID: 135790, + Enabled: false, + Location: Location{City: "Ankara", Country: "Turkey"}, + } + + // Let get all values from the struct s. Note that we don't include values + // from the Location field + m := Values(s) + + fmt.Printf("Values: %+v\n", m) + // Output: + // Values: [Fatih 135790 false] +} + +func ExampleFields() { + type Access struct { + Name string + LastAccessed time.Time + Number int + } + + s := &Access{ + Name: "Fatih", + LastAccessed: time.Now(), + Number: 1234567, + } + + fields := Fields(s) + + for i, field := range fields { + fmt.Printf("[%d] %+v\n", i, field.Name()) + } + + // Output: + // [0] Name + // [1] LastAccessed + // [2] Number +} + +func ExampleFields_nested() { + type Person struct { + Name string + Number int + } + + type Access struct { + Person Person + HasPermission bool + LastAccessed time.Time + } + + s := &Access{ + Person: Person{Name: "fatih", Number: 1234567}, + LastAccessed: time.Now(), + HasPermission: true, + } + + // Let's get all fields from the struct s. + fields := Fields(s) + + for _, field := range fields { + if field.Name() == "Person" { + fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value()) + } + } + + // Output: + // Access.Person.Name: fatih +} + +func ExampleField() { + type Person struct { + Name string + Number int + } + + type Access struct { + Person Person + HasPermission bool + LastAccessed time.Time + } + + access := &Access{ + Person: Person{Name: "fatih", Number: 1234567}, + LastAccessed: time.Now(), + HasPermission: true, + } + + // Create a new Struct type + s := New(access) + + // Get the Field type for "Person" field + p := s.Field("Person") + + // Get the underlying "Name field" and print the value of it + name := p.Field("Name") + + fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value()) + + // Output: + // Value of Person.Access.Name: fatih + +} + +func ExampleIsZero() { + type Server struct { + Name string + ID int32 + Enabled bool + } + + // Nothing is initalized + a := &Server{} + isZeroA := IsZero(a) + + // Name and Enabled is initialized, but not ID + b := &Server{ + Name: "Golang", + Enabled: true, + } + isZeroB := IsZero(b) + + fmt.Printf("%#v\n", isZeroA) + fmt.Printf("%#v\n", isZeroB) + // Output: + // true + // false +} + +func ExampleHasZero() { + // Let's define an Access struct. Note that the "Enabled" field is not + // going to be checked because we added the "structs" tag to the field. + type Access struct { + Name string + LastAccessed time.Time + Number int + Enabled bool `structs:"-"` + } + + // Name and Number is not initialized. + a := &Access{ + LastAccessed: time.Now(), + } + hasZeroA := HasZero(a) + + // Name and Number is initialized. + b := &Access{ + Name: "Fatih", + LastAccessed: time.Now(), + Number: 12345, + } + hasZeroB := HasZero(b) + + fmt.Printf("%#v\n", hasZeroA) + fmt.Printf("%#v\n", hasZeroB) + // Output: + // true + // false +} diff --git a/vendor/src/github.com/fatih/structs/structs_test.go b/vendor/src/github.com/fatih/structs/structs_test.go new file mode 100644 index 0000000..96a5284 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/structs_test.go @@ -0,0 +1,1453 @@ +package structs + +import ( + "fmt" + "reflect" + "testing" + "time" +) + +func TestMapNonStruct(t *testing.T) { + foo := []string{"foo"} + + defer func() { + err := recover() + if err == nil { + t.Error("Passing a non struct into Map should panic") + } + }() + + // this should panic. We are going to recover and and test it + _ = Map(foo) +} + +func TestStructIndexes(t *testing.T) { + type C struct { + something int + Props map[string]interface{} + } + + defer func() { + err := recover() + if err != nil { + fmt.Printf("err %+v\n", err) + t.Error("Using mixed indexes should not panic") + } + }() + + // They should not panic + _ = Map(&C{}) + _ = Fields(&C{}) + _ = Values(&C{}) + _ = IsZero(&C{}) + _ = HasZero(&C{}) +} + +func TestMap(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + a := Map(T) + + if typ := reflect.TypeOf(a).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + // we have three fields + if len(a) != 3 { + t.Errorf("Map should return a map of len 3, got: %d", len(a)) + } + + inMap := func(val interface{}) bool { + for _, v := range a { + if reflect.DeepEqual(v, val) { + return true + } + } + + return false + } + + for _, val := range []interface{}{"a-value", 2, true} { + if !inMap(val) { + t.Errorf("Map should have the value %v", val) + } + } + +} + +func TestMap_Tag(t *testing.T) { + var T = struct { + A string `structs:"x"` + B int `structs:"y"` + C bool `structs:"z"` + }{ + A: "a-value", + B: 2, + C: true, + } + + a := Map(T) + + inMap := func(key interface{}) bool { + for k := range a { + if reflect.DeepEqual(k, key) { + return true + } + } + return false + } + + for _, key := range []string{"x", "y", "z"} { + if !inMap(key) { + t.Errorf("Map should have the key %v", key) + } + } + +} + +func TestMap_CustomTag(t *testing.T) { + var T = struct { + A string `json:"x"` + B int `json:"y"` + C bool `json:"z"` + D struct { + E string `json:"jkl"` + } `json:"nested"` + }{ + A: "a-value", + B: 2, + C: true, + } + T.D.E = "e-value" + + s := New(T) + s.TagName = "json" + + a := s.Map() + + inMap := func(key interface{}) bool { + for k := range a { + if reflect.DeepEqual(k, key) { + return true + } + } + return false + } + + for _, key := range []string{"x", "y", "z"} { + if !inMap(key) { + t.Errorf("Map should have the key %v", key) + } + } + + nested, ok := a["nested"].(map[string]interface{}) + if !ok { + t.Fatalf("Map should contain the D field that is tagged as 'nested'") + } + + e, ok := nested["jkl"].(string) + if !ok { + t.Fatalf("Map should contain the D.E field that is tagged as 'jkl'") + } + + if e != "e-value" { + t.Errorf("D.E field should be equal to 'e-value', got: '%v'", e) + } + +} + +func TestMap_MultipleCustomTag(t *testing.T) { + var A = struct { + X string `aa:"ax"` + }{"a_value"} + + aStruct := New(A) + aStruct.TagName = "aa" + + var B = struct { + X string `bb:"bx"` + }{"b_value"} + + bStruct := New(B) + bStruct.TagName = "bb" + + a, b := aStruct.Map(), bStruct.Map() + if !reflect.DeepEqual(a, map[string]interface{}{"ax": "a_value"}) { + t.Error("Map should have field ax with value a_value") + } + + if !reflect.DeepEqual(b, map[string]interface{}{"bx": "b_value"}) { + t.Error("Map should have field bx with value b_value") + } +} + +func TestMap_OmitEmpty(t *testing.T) { + type A struct { + Name string + Value string `structs:",omitempty"` + Time time.Time `structs:",omitempty"` + } + a := A{} + + m := Map(a) + + _, ok := m["Value"].(map[string]interface{}) + if ok { + t.Error("Map should not contain the Value field that is tagged as omitempty") + } + + _, ok = m["Time"].(map[string]interface{}) + if ok { + t.Error("Map should not contain the Time field that is tagged as omitempty") + } +} + +func TestMap_OmitNested(t *testing.T) { + type A struct { + Name string + Value string + Time time.Time `structs:",omitnested"` + } + a := A{Time: time.Now()} + + type B struct { + Desc string + A A + } + b := &B{A: a} + + m := Map(b) + + in, ok := m["A"].(map[string]interface{}) + if !ok { + t.Error("Map nested structs is not available in the map") + } + + // should not happen + if _, ok := in["Time"].(map[string]interface{}); ok { + t.Error("Map nested struct should omit recursiving parsing of Time") + } + + if _, ok := in["Time"].(time.Time); !ok { + t.Error("Map nested struct should stop parsing of Time at is current value") + } +} + +func TestMap_Nested(t *testing.T) { + type A struct { + Name string + } + a := &A{Name: "example"} + + type B struct { + A *A + } + b := &B{A: a} + + m := Map(b) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["A"].(map[string]interface{}) + if !ok { + t.Error("Map nested structs is not available in the map") + } + + if name := in["Name"].(string); name != "example" { + t.Errorf("Map nested struct's name field should give example, got: %s", name) + } +} + +func TestMap_NestedMapWithStructValues(t *testing.T) { + type A struct { + Name string + } + + type B struct { + A map[string]*A + } + + a := &A{Name: "example"} + + b := &B{ + A: map[string]*A{ + "example_key": a, + }, + } + + m := Map(b) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["A"].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["A"]) + } + + example := in["example_key"].(map[string]interface{}) + if name := example["Name"].(string); name != "example" { + t.Errorf("Map nested struct's name field should give example, got: %s", name) + } +} + +func TestMap_NestedMapWithStringValues(t *testing.T) { + type B struct { + Foo map[string]string + } + + type A struct { + B *B + } + + b := &B{ + Foo: map[string]string{ + "example_key": "example", + }, + } + + a := &A{B: b} + + m := Map(a) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["B"].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["B"]) + } + + foo := in["Foo"].(map[string]string) + if name := foo["example_key"]; name != "example" { + t.Errorf("Map nested struct's name field should give example, got: %s", name) + } +} +func TestMap_NestedMapWithInterfaceValues(t *testing.T) { + type B struct { + Foo map[string]interface{} + } + + type A struct { + B *B + } + + b := &B{ + Foo: map[string]interface{}{ + "example_key": "example", + }, + } + + a := &A{B: b} + + m := Map(a) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["B"].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["B"]) + } + + foo := in["Foo"].(map[string]interface{}) + if name := foo["example_key"]; name != "example" { + t.Errorf("Map nested struct's name field should give example, got: %s", name) + } +} + +func TestMap_NestedMapWithSliceIntValues(t *testing.T) { + type B struct { + Foo map[string][]int + } + + type A struct { + B *B + } + + b := &B{ + Foo: map[string][]int{ + "example_key": []int{80}, + }, + } + + a := &A{B: b} + + m := Map(a) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["B"].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["B"]) + } + + foo := in["Foo"].(map[string][]int) + if name := foo["example_key"]; name[0] != 80 { + t.Errorf("Map nested struct's name field should give example, got: %v", name) + } +} + +func TestMap_NestedMapWithSliceStructValues(t *testing.T) { + type address struct { + Country string `structs:"country"` + } + + type B struct { + Foo map[string][]address + } + + type A struct { + B *B + } + + b := &B{ + Foo: map[string][]address{ + "example_key": []address{ + {Country: "Turkey"}, + }, + }, + } + + a := &A{B: b} + m := Map(a) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["B"].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["B"]) + } + + foo := in["Foo"].(map[string]interface{}) + + addresses := foo["example_key"].([]interface{}) + + addr, ok := addresses[0].(map[string]interface{}) + if !ok { + t.Errorf("Nested type of map should be of type map[string]interface{}, have %T", m["B"]) + } + + if _, exists := addr["country"]; !exists { + t.Errorf("Expecting country, but found Country") + } +} + +func TestMap_NestedSliceWithStructValues(t *testing.T) { + type address struct { + Country string `structs:"customCountryName"` + } + + type person struct { + Name string `structs:"name"` + Addresses []address `structs:"addresses"` + } + + p := person{ + Name: "test", + Addresses: []address{ + address{Country: "England"}, + address{Country: "Italy"}, + }, + } + mp := Map(p) + + mpAddresses := mp["addresses"].([]interface{}) + if _, exists := mpAddresses[0].(map[string]interface{})["Country"]; exists { + t.Errorf("Expecting customCountryName, but found Country") + } + + if _, exists := mpAddresses[0].(map[string]interface{})["customCountryName"]; !exists { + t.Errorf("customCountryName key not found") + } +} + +func TestMap_NestedSliceWithPointerOfStructValues(t *testing.T) { + type address struct { + Country string `structs:"customCountryName"` + } + + type person struct { + Name string `structs:"name"` + Addresses []*address `structs:"addresses"` + } + + p := person{ + Name: "test", + Addresses: []*address{ + &address{Country: "England"}, + &address{Country: "Italy"}, + }, + } + mp := Map(p) + + mpAddresses := mp["addresses"].([]interface{}) + if _, exists := mpAddresses[0].(map[string]interface{})["Country"]; exists { + t.Errorf("Expecting customCountryName, but found Country") + } + + if _, exists := mpAddresses[0].(map[string]interface{})["customCountryName"]; !exists { + t.Errorf("customCountryName key not found") + } +} + +func TestMap_NestedSliceWithIntValues(t *testing.T) { + type person struct { + Name string `structs:"name"` + Ports []int `structs:"ports"` + } + + p := person{ + Name: "test", + Ports: []int{80}, + } + m := Map(p) + + ports, ok := m["ports"].([]int) + if !ok { + t.Errorf("Nested type of map should be of type []int, have %T", m["ports"]) + } + + if ports[0] != 80 { + t.Errorf("Map nested struct's ports field should give 80, got: %v", ports) + } +} + +func TestMap_Anonymous(t *testing.T) { + type A struct { + Name string + } + a := &A{Name: "example"} + + type B struct { + *A + } + b := &B{} + b.A = a + + m := Map(b) + + if typ := reflect.TypeOf(m).Kind(); typ != reflect.Map { + t.Errorf("Map should return a map type, got: %v", typ) + } + + in, ok := m["A"].(map[string]interface{}) + if !ok { + t.Error("Embedded structs is not available in the map") + } + + if name := in["Name"].(string); name != "example" { + t.Errorf("Embedded A struct's Name field should give example, got: %s", name) + } +} + +func TestMap_Flatnested(t *testing.T) { + type A struct { + Name string + } + a := A{Name: "example"} + + type B struct { + A `structs:",flatten"` + C int + } + b := &B{C: 123} + b.A = a + + m := Map(b) + + _, ok := m["A"].(map[string]interface{}) + if ok { + t.Error("Embedded A struct with tag flatten has to be flat in the map") + } + + expectedMap := map[string]interface{}{"Name": "example", "C": 123} + if !reflect.DeepEqual(m, expectedMap) { + t.Errorf("The exprected map %+v does't correspond to %+v", expectedMap, m) + } + +} + +func TestMap_FlatnestedOverwrite(t *testing.T) { + type A struct { + Name string + } + a := A{Name: "example"} + + type B struct { + A `structs:",flatten"` + Name string + C int + } + b := &B{C: 123, Name: "bName"} + b.A = a + + m := Map(b) + + _, ok := m["A"].(map[string]interface{}) + if ok { + t.Error("Embedded A struct with tag flatten has to be flat in the map") + } + + expectedMap := map[string]interface{}{"Name": "bName", "C": 123} + if !reflect.DeepEqual(m, expectedMap) { + t.Errorf("The exprected map %+v does't correspond to %+v", expectedMap, m) + } +} + +func TestMap_TimeField(t *testing.T) { + type A struct { + CreatedAt time.Time + } + + a := &A{CreatedAt: time.Now().UTC()} + m := Map(a) + + _, ok := m["CreatedAt"].(time.Time) + if !ok { + t.Error("Time field must be final") + } +} + +func TestFillMap(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + a := make(map[string]interface{}, 0) + FillMap(T, a) + + // we have three fields + if len(a) != 3 { + t.Errorf("FillMap should fill a map of len 3, got: %d", len(a)) + } + + inMap := func(val interface{}) bool { + for _, v := range a { + if reflect.DeepEqual(v, val) { + return true + } + } + + return false + } + + for _, val := range []interface{}{"a-value", 2, true} { + if !inMap(val) { + t.Errorf("FillMap should have the value %v", val) + } + } +} + +func TestFillMap_Nil(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + defer func() { + err := recover() + if err != nil { + t.Error("FillMap should not panic if a nil map is passed") + } + }() + + // nil should no + FillMap(T, nil) +} +func TestStruct(t *testing.T) { + var T = struct{}{} + + if !IsStruct(T) { + t.Errorf("T should be a struct, got: %T", T) + } + + if !IsStruct(&T) { + t.Errorf("T should be a struct, got: %T", T) + } + +} + +func TestValues(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + s := Values(T) + + if typ := reflect.TypeOf(s).Kind(); typ != reflect.Slice { + t.Errorf("Values should return a slice type, got: %v", typ) + } + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v, val) { + return true + } + } + return false + } + + for _, val := range []interface{}{"a-value", 2, true} { + if !inSlice(val) { + t.Errorf("Values should have the value %v", val) + } + } +} + +func TestValues_OmitEmpty(t *testing.T) { + type A struct { + Name string + Value int `structs:",omitempty"` + } + + a := A{Name: "example"} + s := Values(a) + + if len(s) != 1 { + t.Errorf("Values of omitted empty fields should be not counted") + } + + if s[0].(string) != "example" { + t.Errorf("Values of omitted empty fields should left the value example") + } +} + +func TestValues_OmitNested(t *testing.T) { + type A struct { + Name string + Value int + } + + a := A{ + Name: "example", + Value: 123, + } + + type B struct { + A A `structs:",omitnested"` + C int + } + b := &B{A: a, C: 123} + + s := Values(b) + + if len(s) != 2 { + t.Errorf("Values of omitted nested struct should be not counted") + } + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v, val) { + return true + } + } + return false + } + + for _, val := range []interface{}{123, a} { + if !inSlice(val) { + t.Errorf("Values should have the value %v", val) + } + } +} + +func TestValues_Nested(t *testing.T) { + type A struct { + Name string + } + a := A{Name: "example"} + + type B struct { + A A + C int + } + b := &B{A: a, C: 123} + + s := Values(b) + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v, val) { + return true + } + } + return false + } + + for _, val := range []interface{}{"example", 123} { + if !inSlice(val) { + t.Errorf("Values should have the value %v", val) + } + } +} + +func TestValues_Anonymous(t *testing.T) { + type A struct { + Name string + } + a := A{Name: "example"} + + type B struct { + A + C int + } + b := &B{C: 123} + b.A = a + + s := Values(b) + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v, val) { + return true + } + } + return false + } + + for _, val := range []interface{}{"example", 123} { + if !inSlice(val) { + t.Errorf("Values should have the value %v", val) + } + } +} + +func TestNames(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + s := Names(T) + + if len(s) != 3 { + t.Errorf("Names should return a slice of len 3, got: %d", len(s)) + } + + inSlice := func(val string) bool { + for _, v := range s { + if reflect.DeepEqual(v, val) { + return true + } + } + return false + } + + for _, val := range []string{"A", "B", "C"} { + if !inSlice(val) { + t.Errorf("Names should have the value %v", val) + } + } +} + +func TestFields(t *testing.T) { + var T = struct { + A string + B int + C bool + }{ + A: "a-value", + B: 2, + C: true, + } + + s := Fields(T) + + if len(s) != 3 { + t.Errorf("Fields should return a slice of len 3, got: %d", len(s)) + } + + inSlice := func(val string) bool { + for _, v := range s { + if reflect.DeepEqual(v.Name(), val) { + return true + } + } + return false + } + + for _, val := range []string{"A", "B", "C"} { + if !inSlice(val) { + t.Errorf("Fields should have the value %v", val) + } + } +} + +func TestFields_OmitNested(t *testing.T) { + type A struct { + Name string + Enabled bool + } + a := A{Name: "example"} + + type B struct { + A A + C int + Value string `structs:"-"` + Number int + } + b := &B{A: a, C: 123} + + s := Fields(b) + + if len(s) != 3 { + t.Errorf("Fields should omit nested struct. Expecting 2 got: %d", len(s)) + } + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v.Name(), val) { + return true + } + } + return false + } + + for _, val := range []interface{}{"A", "C"} { + if !inSlice(val) { + t.Errorf("Fields should have the value %v", val) + } + } +} + +func TestFields_Anonymous(t *testing.T) { + type A struct { + Name string + } + a := A{Name: "example"} + + type B struct { + A + C int + } + b := &B{C: 123} + b.A = a + + s := Fields(b) + + inSlice := func(val interface{}) bool { + for _, v := range s { + if reflect.DeepEqual(v.Name(), val) { + return true + } + } + return false + } + + for _, val := range []interface{}{"A", "C"} { + if !inSlice(val) { + t.Errorf("Fields should have the value %v", val) + } + } +} + +func TestIsZero(t *testing.T) { + var T = struct { + A string + B int + C bool `structs:"-"` + D []string + }{} + + ok := IsZero(T) + if !ok { + t.Error("IsZero should return true because none of the fields are initialized.") + } + + var X = struct { + A string + F *bool + }{ + A: "a-value", + } + + ok = IsZero(X) + if ok { + t.Error("IsZero should return false because A is initialized") + } + + var Y = struct { + A string + B int + }{ + A: "a-value", + B: 123, + } + + ok = IsZero(Y) + if ok { + t.Error("IsZero should return false because A and B is initialized") + } +} + +func TestIsZero_OmitNested(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A A `structs:",omitnested"` + C int + } + b := &B{A: a, C: 123} + + ok := IsZero(b) + if ok { + t.Error("IsZero should return false because A, B and C are initialized") + } + + aZero := A{} + bZero := &B{A: aZero} + + ok = IsZero(bZero) + if !ok { + t.Error("IsZero should return true because neither A nor B is initialized") + } + +} + +func TestIsZero_Nested(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A A + C int + } + b := &B{A: a, C: 123} + + ok := IsZero(b) + if ok { + t.Error("IsZero should return false because A, B and C are initialized") + } + + aZero := A{} + bZero := &B{A: aZero} + + ok = IsZero(bZero) + if !ok { + t.Error("IsZero should return true because neither A nor B is initialized") + } + +} + +func TestIsZero_Anonymous(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A + C int + } + b := &B{C: 123} + b.A = a + + ok := IsZero(b) + if ok { + t.Error("IsZero should return false because A, B and C are initialized") + } + + aZero := A{} + bZero := &B{} + bZero.A = aZero + + ok = IsZero(bZero) + if !ok { + t.Error("IsZero should return true because neither A nor B is initialized") + } +} + +func TestHasZero(t *testing.T) { + var T = struct { + A string + B int + C bool `structs:"-"` + D []string + }{ + A: "a-value", + B: 2, + } + + ok := HasZero(T) + if !ok { + t.Error("HasZero should return true because A and B are initialized.") + } + + var X = struct { + A string + F *bool + }{ + A: "a-value", + } + + ok = HasZero(X) + if !ok { + t.Error("HasZero should return true because A is initialized") + } + + var Y = struct { + A string + B int + }{ + A: "a-value", + B: 123, + } + + ok = HasZero(Y) + if ok { + t.Error("HasZero should return false because A and B is initialized") + } +} + +func TestHasZero_OmitNested(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A A `structs:",omitnested"` + C int + } + b := &B{A: a, C: 123} + + // Because the Field A inside B is omitted HasZero should return false + // because it will stop iterating deeper andnot going to lookup for D + ok := HasZero(b) + if ok { + t.Error("HasZero should return false because A and C are initialized") + } +} + +func TestHasZero_Nested(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A A + C int + } + b := &B{A: a, C: 123} + + ok := HasZero(b) + if !ok { + t.Error("HasZero should return true because D is not initialized") + } +} + +func TestHasZero_Anonymous(t *testing.T) { + type A struct { + Name string + D string + } + a := A{Name: "example"} + + type B struct { + A + C int + } + b := &B{C: 123} + b.A = a + + ok := HasZero(b) + if !ok { + t.Error("HasZero should return false because D is not initialized") + } +} + +func TestName(t *testing.T) { + type Foo struct { + A string + B bool + } + f := &Foo{} + + n := Name(f) + if n != "Foo" { + t.Errorf("Name should return Foo, got: %s", n) + } + + unnamed := struct{ Name string }{Name: "Cihangir"} + m := Name(unnamed) + if m != "" { + t.Errorf("Name should return empty string for unnamed struct, got: %s", n) + } + + defer func() { + err := recover() + if err == nil { + t.Error("Name should panic if a non struct is passed") + } + }() + + Name([]string{}) +} + +func TestNestedNilPointer(t *testing.T) { + type Collar struct { + Engraving string + } + + type Dog struct { + Name string + Collar *Collar + } + + type Person struct { + Name string + Dog *Dog + } + + person := &Person{ + Name: "John", + } + + personWithDog := &Person{ + Name: "Ron", + Dog: &Dog{ + Name: "Rover", + }, + } + + personWithDogWithCollar := &Person{ + Name: "Kon", + Dog: &Dog{ + Name: "Ruffles", + Collar: &Collar{ + Engraving: "If lost, call Kon", + }, + }, + } + + defer func() { + err := recover() + if err != nil { + fmt.Printf("err %+v\n", err) + t.Error("Internal nil pointer should not panic") + } + }() + + _ = Map(person) // Panics + _ = Map(personWithDog) // Panics + _ = Map(personWithDogWithCollar) // Doesn't panic +} + +func TestSetValueOnNestedField(t *testing.T) { + type Base struct { + ID int + } + + type User struct { + Base + Name string + } + + u := User{} + s := New(&u) + f := s.Field("Base").Field("ID") + err := f.Set(10) + if err != nil { + t.Errorf("Error %v", err) + } + if f.Value().(int) != 10 { + t.Errorf("Value should be equal to 10, got %v", f.Value()) + } +} + +type Person struct { + Name string + Age int +} + +func (p *Person) String() string { + return fmt.Sprintf("%s(%d)", p.Name, p.Age) +} + +func TestTagWithStringOption(t *testing.T) { + + type Address struct { + Country string `json:"country"` + Person *Person `json:"person,string"` + } + + person := &Person{ + Name: "John", + Age: 23, + } + + address := &Address{ + Country: "EU", + Person: person, + } + + defer func() { + err := recover() + if err != nil { + fmt.Printf("err %+v\n", err) + t.Error("Internal nil pointer should not panic") + } + }() + + s := New(address) + + s.TagName = "json" + m := s.Map() + + if m["person"] != person.String() { + t.Errorf("Value for field person should be %s, got: %s", person.String(), m["person"]) + } + + vs := s.Values() + if vs[1] != person.String() { + t.Errorf("Value for 2nd field (person) should be %T, got: %T", person.String(), vs[1]) + } +} + +type Animal struct { + Name string + Age int +} + +type Dog struct { + Animal *Animal `json:"animal,string"` +} + +func TestNonStringerTagWithStringOption(t *testing.T) { + a := &Animal{ + Name: "Fluff", + Age: 4, + } + + d := &Dog{ + Animal: a, + } + + defer func() { + err := recover() + if err != nil { + fmt.Printf("err %+v\n", err) + t.Error("Internal nil pointer should not panic") + } + }() + + s := New(d) + + s.TagName = "json" + m := s.Map() + + if _, exists := m["animal"]; exists { + t.Errorf("Value for field Animal should not exist") + } +} + +func TestMap_InterfaceValue(t *testing.T) { + type TestStruct struct { + A interface{} + } + + expected := []byte("test value") + + a := TestStruct{A: expected} + s := Map(a) + if !reflect.DeepEqual(s["A"], expected) { + t.Errorf("Value does not match expected: %q != %q", s["A"], expected) + } +} + +func TestPointer2Pointer(t *testing.T) { + defer func() { + err := recover() + if err != nil { + fmt.Printf("err %+v\n", err) + t.Error("Internal nil pointer should not panic") + } + }() + a := &Animal{ + Name: "Fluff", + Age: 4, + } + _ = Map(&a) + + b := &a + _ = Map(&b) + + c := &b + _ = Map(&c) +} + +func TestMap_InterfaceTypeWithMapValue(t *testing.T) { + type A struct { + Name string `structs:"name"` + Ip string `structs:"ip"` + Query string `structs:"query"` + Payload interface{} `structs:"payload"` + } + + a := A{ + Name: "test", + Ip: "127.0.0.1", + Query: "", + Payload: map[string]string{"test_param": "test_param"}, + } + + defer func() { + err := recover() + if err != nil { + t.Error("Converting Map with an interface{} type with map value should not panic") + } + }() + + _ = Map(a) +} diff --git a/vendor/src/github.com/fatih/structs/tags.go b/vendor/src/github.com/fatih/structs/tags.go new file mode 100644 index 0000000..136a31e --- /dev/null +++ b/vendor/src/github.com/fatih/structs/tags.go @@ -0,0 +1,32 @@ +package structs + +import "strings" + +// tagOptions contains a slice of tag options +type tagOptions []string + +// Has returns true if the given option is available in tagOptions +func (t tagOptions) Has(opt string) bool { + for _, tagOpt := range t { + if tagOpt == opt { + return true + } + } + + return false +} + +// parseTag splits a struct field's tag into its name and a list of options +// which comes after a name. A tag is in the form of: "name,option1,option2". +// The name can be neglectected. +func parseTag(tag string) (string, tagOptions) { + // tag is one of followings: + // "" + // "name" + // "name,opt" + // "name,opt,opt2" + // ",opt" + + res := strings.Split(tag, ",") + return res[0], res[1:] +} diff --git a/vendor/src/github.com/fatih/structs/tags_test.go b/vendor/src/github.com/fatih/structs/tags_test.go new file mode 100644 index 0000000..5d12724 --- /dev/null +++ b/vendor/src/github.com/fatih/structs/tags_test.go @@ -0,0 +1,46 @@ +package structs + +import "testing" + +func TestParseTag_Name(t *testing.T) { + tags := []struct { + tag string + has bool + }{ + {"", false}, + {"name", true}, + {"name,opt", true}, + {"name , opt, opt2", false}, // has a single whitespace + {", opt, opt2", false}, + } + + for _, tag := range tags { + name, _ := parseTag(tag.tag) + + if (name != "name") && tag.has { + t.Errorf("Parse tag should return name: %#v", tag) + } + } +} + +func TestParseTag_Opts(t *testing.T) { + tags := []struct { + opts string + has bool + }{ + {"name", false}, + {"name,opt", true}, + {"name , opt, opt2", false}, // has a single whitespace + {",opt, opt2", true}, + {", opt3, opt4", false}, + } + + // search for "opt" + for _, tag := range tags { + _, opts := parseTag(tag.opts) + + if opts.Has("opt") != tag.has { + t.Errorf("Tag opts should have opt: %#v", tag) + } + } +}