struct: increase coverage back to %100
This commit is contained in:
parent
3bd57b6a66
commit
f614213600
15
field.go
15
field.go
@ -48,16 +48,27 @@ func (f *Field) Name() string {
|
|||||||
// Field returns the field from a nested struct. It panics if the nested struct
|
// Field returns the field from a nested struct. It panics if the nested struct
|
||||||
// is not exported or if the field was not found.
|
// is not exported or if the field was not found.
|
||||||
func (f *Field) Field(name string) *Field {
|
func (f *Field) Field(name string) *Field {
|
||||||
|
field, ok := f.FieldOk(name)
|
||||||
|
if !ok {
|
||||||
|
panic("field not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) FieldOk(name string) (*Field, bool) {
|
||||||
v := strctVal(f.value.Interface())
|
v := strctVal(f.value.Interface())
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
|
|
||||||
field, ok := t.FieldByName(name)
|
field, ok := t.FieldByName(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("field not found")
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Field{
|
return &Field{
|
||||||
field: field,
|
field: field,
|
||||||
value: v.FieldByName(name),
|
value: v.FieldByName(name),
|
||||||
}
|
}, true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,3 +173,26 @@ func TestField_Field(t *testing.T) {
|
|||||||
|
|
||||||
_ = s.Field("Bar").Field("e")
|
_ = s.Field("Bar").Field("e")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
84
structs.go
84
structs.go
@ -1,84 +0,0 @@
|
|||||||
package structure
|
|
||||||
|
|
||||||
// Struct encapsulates a struct type to provide several high level functions
|
|
||||||
// around the structure.
|
|
||||||
type Struct struct {
|
|
||||||
raw interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new *Struct with the struct s.
|
|
||||||
func New(s interface{}) *Struct {
|
|
||||||
return &Struct{
|
|
||||||
raw: s,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map converts the given struct to a map[string]interface{}. For more info
|
|
||||||
// refer to Map() function.
|
|
||||||
func (s *Struct) Map() map[string]interface{} {
|
|
||||||
return Map(s.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values converts the given struct to a []interface{}. For more info refer to
|
|
||||||
// Values() function.
|
|
||||||
func (s *Struct) Values() []interface{} {
|
|
||||||
return Values(s.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fields returns a slice of field names For more info refer to Fields()
|
|
||||||
// function.
|
|
||||||
func (s *Struct) Fields() []string {
|
|
||||||
return Fields(s.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field returns a new Field struct that provides several high level functions
|
|
||||||
// around a single struct field entitiy. 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field returns a new Field struct that provides several high level functions
|
|
||||||
// around a single struct field entitiy. The boolean returns true if the field
|
|
||||||
// was found.
|
|
||||||
func (s *Struct) FieldOk(name string) (*Field, bool) {
|
|
||||||
v := strctVal(s.raw)
|
|
||||||
t := v.Type()
|
|
||||||
|
|
||||||
field, ok := t.FieldByName(name)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Field{
|
|
||||||
field: field,
|
|
||||||
value: v.FieldByName(name),
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsZero returns true if all fields is equal to a zero value. For more info
|
|
||||||
// refer to IsZero() function.
|
|
||||||
func (s *Struct) IsZero() bool {
|
|
||||||
return IsZero(s.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasZero returns true if any field is equal to a zero value. For more info
|
|
||||||
// refer to HasZero() function.
|
|
||||||
func (s *Struct) HasZero() bool {
|
|
||||||
return HasZero(s.raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the structs's type name within its package. For more info refer
|
|
||||||
// to Name() function.
|
|
||||||
func (s *Struct) Name() string {
|
|
||||||
return Name(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsStruct returns true if its a struct or a pointer to struct.
|
|
||||||
func (s *Struct) IsStruct() bool {
|
|
||||||
return IsStruct(s.raw)
|
|
||||||
}
|
|
||||||
192
structure.go
192
structure.go
@ -10,7 +10,23 @@ var (
|
|||||||
DefaultTagName = "structure" // struct's field default tag name
|
DefaultTagName = "structure" // struct's field default tag name
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map converts the given s struct to a map[string]interface{}, where the keys
|
// Struct encapsulates a struct type to provide several high level functions
|
||||||
|
// around the structure.
|
||||||
|
type Struct struct {
|
||||||
|
raw interface{}
|
||||||
|
value reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// 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
|
// 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 "structure" key in the
|
// can be changed in the struct field's tag value. The "structure" key in the
|
||||||
@ -32,15 +48,15 @@ var (
|
|||||||
// Field *http.Request `structure:",omitnested"`
|
// Field *http.Request `structure:",omitnested"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// 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.
|
// fields will be neglected.
|
||||||
func Map(s interface{}) map[string]interface{} {
|
func (s *Struct) Map() map[string]interface{} {
|
||||||
out := make(map[string]interface{})
|
out := make(map[string]interface{})
|
||||||
|
|
||||||
v, fields := strctInfo(s)
|
fields := s.structFields()
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
name := field.Name
|
name := field.Name
|
||||||
val := v.FieldByName(name)
|
val := s.value.FieldByName(name)
|
||||||
|
|
||||||
var finalVal interface{}
|
var finalVal interface{}
|
||||||
|
|
||||||
@ -79,14 +95,14 @@ func Map(s interface{}) map[string]interface{} {
|
|||||||
// Field *http.Request `structure:",omitnested"`
|
// Field *http.Request `structure:",omitnested"`
|
||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// 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.
|
// fields will be neglected.
|
||||||
func Values(s interface{}) []interface{} {
|
func (s *Struct) Values() []interface{} {
|
||||||
v, fields := strctInfo(s)
|
fields := s.structFields()
|
||||||
|
|
||||||
var t []interface{}
|
var t []interface{}
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
val := v.FieldByName(field.Name)
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
||||||
|
|
||||||
@ -102,7 +118,6 @@ func Values(s interface{}) []interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields returns a slice of field names. A struct tag with the content of "-"
|
// Fields returns a slice of field names. A struct tag with the content of "-"
|
||||||
@ -120,13 +135,13 @@ func Values(s interface{}) []interface{} {
|
|||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// 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.
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
func Fields(s interface{}) []string {
|
func (s *Struct) Fields() []string {
|
||||||
v, fields := strctInfo(s)
|
fields := s.structFields()
|
||||||
|
|
||||||
var keys []string
|
var keys []string
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
val := v.FieldByName(field.Name)
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
||||||
|
|
||||||
@ -144,6 +159,34 @@ func Fields(s interface{}) []string {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field returns a new Field struct that provides several high level functions
|
||||||
|
// around a single struct field entitiy. 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns a new Field struct that provides several high level functions
|
||||||
|
// around a single struct field entitiy. 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),
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
// IsZero returns true if all fields in a struct is a zero value (not
|
// 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
|
// initialized) A struct tag with the content of "-" ignores the checking of
|
||||||
// that particular field. Example:
|
// that particular field. Example:
|
||||||
@ -160,11 +203,11 @@ func Fields(s interface{}) []string {
|
|||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// 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.
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
func IsZero(s interface{}) bool {
|
func (s *Struct) IsZero() bool {
|
||||||
v, fields := strctInfo(s)
|
fields := s.structFields()
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
val := v.FieldByName(field.Name)
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
||||||
|
|
||||||
@ -207,11 +250,11 @@ func IsZero(s interface{}) bool {
|
|||||||
//
|
//
|
||||||
// Note that only exported fields of a struct can be accessed, non exported
|
// 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.
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
func HasZero(s interface{}) bool {
|
func (s *Struct) HasZero() bool {
|
||||||
v, fields := strctInfo(s)
|
fields := s.structFields()
|
||||||
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
val := v.FieldByName(field.Name)
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
|
||||||
|
|
||||||
@ -238,61 +281,17 @@ func HasZero(s interface{}) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStruct returns true if the given variable is a struct or a pointer to
|
// Name returns the structs's type name within its package. For more info refer
|
||||||
// struct.
|
// to Name() function.
|
||||||
func IsStruct(s interface{}) bool {
|
func (s *Struct) Name() string {
|
||||||
t := reflect.TypeOf(s)
|
return s.value.Type().Name()
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.Kind() == reflect.Struct
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the structs's type name within its package. It returns an
|
// structFields returns the exported struct fields for a given s struct. This
|
||||||
// empty string for unnamed types. It panics if s's kind is not struct.
|
// is a convenient helper method to avoid duplicate code in some of the
|
||||||
func Name(s interface{}) string {
|
// functions.
|
||||||
t := reflect.TypeOf(s)
|
func (s *Struct) structFields() []reflect.StructField {
|
||||||
|
t := s.value.Type()
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
panic("not struct")
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has returns true if the given field name exists for the struct s. It panic's
|
|
||||||
// if s's kind is not struct.
|
|
||||||
func Has(s interface{}, fieldName string) bool {
|
|
||||||
v, fields := strctInfo(s)
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
val := v.FieldByName(field.Name)
|
|
||||||
|
|
||||||
if IsStruct(val.Interface()) {
|
|
||||||
if ok := Has(val.Interface(), fieldName); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if field.Name == fieldName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// strctInfo returns the struct value and 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 strctInfo(s interface{}) (reflect.Value, []reflect.StructField) {
|
|
||||||
v := strctVal(s)
|
|
||||||
t := v.Type()
|
|
||||||
|
|
||||||
var f []reflect.StructField
|
var f []reflect.StructField
|
||||||
|
|
||||||
@ -311,7 +310,7 @@ func strctInfo(s interface{}) (reflect.Value, []reflect.StructField) {
|
|||||||
f = append(f, field)
|
f = append(f, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func strctVal(s interface{}) reflect.Value {
|
func strctVal(s interface{}) reflect.Value {
|
||||||
@ -328,3 +327,50 @@ func strctVal(s interface{}) reflect.Value {
|
|||||||
|
|
||||||
return v
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 names. For more info refer to Struct types
|
||||||
|
// Fields() method. It panics if s's kind is not struct.
|
||||||
|
func Fields(s interface{}) []string {
|
||||||
|
return New(s).Fields()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
t := reflect.TypeOf(s)
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.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()
|
||||||
|
}
|
||||||
|
|||||||
@ -237,23 +237,3 @@ func ExampleHasZero() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleHas() {
|
|
||||||
type Access struct {
|
|
||||||
Name string
|
|
||||||
LastAccessed time.Time
|
|
||||||
Number int
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Access{
|
|
||||||
Name: "Fatih",
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
Number: 1234567,
|
|
||||||
}
|
|
||||||
|
|
||||||
found := Has(s, "LastAccessed")
|
|
||||||
|
|
||||||
fmt.Printf("Has: %+v\n", found)
|
|
||||||
// Output:
|
|
||||||
// Has: true
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package structure
|
package structure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -29,6 +30,7 @@ func TestStructIndexes(t *testing.T) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
err := recover()
|
err := recover()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("err %+v\n", err)
|
||||||
t.Error("Using mixed indexes should not panic")
|
t.Error("Using mixed indexes should not panic")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -735,33 +737,6 @@ func TestHasZero_Anonymous(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHas(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
|
|
||||||
|
|
||||||
if !Has(b, "Name") {
|
|
||||||
t.Error("Has should return true for Name, but it's false")
|
|
||||||
}
|
|
||||||
|
|
||||||
if Has(b, "NotAvailable") {
|
|
||||||
t.Error("Has should return false for NotAvailable, but it's true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !Has(b, "C") {
|
|
||||||
t.Error("Has should return true for C, but it's false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestName(t *testing.T) {
|
func TestName(t *testing.T) {
|
||||||
type Foo struct {
|
type Foo struct {
|
||||||
A string
|
A string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user