diff --git a/field.go b/field.go index 952eeb8..1a21071 100644 --- a/field.go +++ b/field.go @@ -30,3 +30,17 @@ func (f *Field) IsEmbedded() bool { func (f *Field) IsExported() bool { return f.field.PkgPath == "" } + +// IsZero returns true if the given field is not initalized (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 +} diff --git a/field_test.go b/field_test.go index 8c24760..3f93f68 100644 --- a/field_test.go +++ b/field_test.go @@ -8,6 +8,7 @@ type Foo struct { B int `structure:"y"` C bool `json:"c"` d string // not exported + x string `xml:"x"` // not exported, with tag *Bar // embedded } @@ -24,9 +25,9 @@ func newStruct() *Struct { g: []string{"zeynep", "fatih"}, } + // B and x is not initialized for testing f := &Foo{ A: "gopher", - B: 1, C: true, d: "small", } @@ -47,3 +48,56 @@ func TestField(t *testing.T) { _ = s.Field("no-field") } + +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() +} diff --git a/structs.go b/structs.go index 87c1465..bc7249f 100644 --- a/structs.go +++ b/structs.go @@ -32,8 +32,7 @@ func (s *Struct) Fields() []string { } // 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 or -// is unexported. +// 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 { @@ -44,8 +43,8 @@ func (s *Struct) Field(name string) *Field { } // Field returns a new Field struct that provides several high level functions -// around a single struct field entitiy and a boolean indicating if the field -// was found. It panics if the or is unexported. +// 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() @@ -55,10 +54,6 @@ func (s *Struct) FieldOk(name string) (*Field, bool) { return nil, false } - if field.PkgPath != "" { - panic("unexported field access is not allowed") - } - return &Field{ field: field, value: v.FieldByName(name),