mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-13 09:12:28 +08:00
Merge branch 'main' into v2
This commit is contained in:
0
docs/structutil/field.md
Normal file
0
docs/structutil/field.md
Normal file
0
docs/structutil/struct.md
Normal file
0
docs/structutil/struct.md
Normal file
14
pointer/pointer.go
Normal file
14
pointer/pointer.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// ExtractPointer returns the underlying value by the given interface type
|
||||||
|
func ExtractPointer(value any) any {
|
||||||
|
t := reflect.TypeOf(value)
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
|
if t.Kind() != reflect.Pointer {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ExtractPointer(v.Elem().Interface())
|
||||||
|
}
|
||||||
18
pointer/pointer_test.go
Normal file
18
pointer/pointer_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractPointer(t *testing.T) {
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestExtractPointer")
|
||||||
|
|
||||||
|
a := 1
|
||||||
|
b := &a
|
||||||
|
c := &b
|
||||||
|
d := &c
|
||||||
|
|
||||||
|
assert.Equal(1, ExtractPointer(d))
|
||||||
|
}
|
||||||
7
structutil/error.go
Normal file
7
structutil/error.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package structutil
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func ErrInvalidStruct(v any) error {
|
||||||
|
return fmt.Errorf("invalid struct %v", v)
|
||||||
|
}
|
||||||
@@ -1,20 +1,25 @@
|
|||||||
package structutil
|
package structutil
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/pointer"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
type Field struct {
|
type Field struct {
|
||||||
value reflect.Value
|
Struct
|
||||||
field reflect.StructField
|
field reflect.StructField
|
||||||
tag *Tag
|
tag *Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func newField(v reflect.Value, f reflect.StructField, tagName string) *Field {
|
func newField(v reflect.Value, f reflect.StructField, tagName string) *Field {
|
||||||
tag := f.Tag.Get(tagName)
|
tag := f.Tag.Get(tagName)
|
||||||
return &Field{
|
field := &Field{
|
||||||
value: v,
|
|
||||||
field: f,
|
field: f,
|
||||||
tag: newTag(tag),
|
tag: newTag(tag),
|
||||||
}
|
}
|
||||||
|
field.rvalue = v
|
||||||
|
field.TagName = tagName
|
||||||
|
return field
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag returns the value that the key in the tag string.
|
// Tag returns the value that the key in the tag string.
|
||||||
@@ -24,22 +29,22 @@ func (f *Field) Tag() *Tag {
|
|||||||
|
|
||||||
// Value returns the underlying value of the field.
|
// Value returns the underlying value of the field.
|
||||||
func (f *Field) Value() any {
|
func (f *Field) Value() any {
|
||||||
return f.value.Interface()
|
return f.rvalue.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmbedded returns true if the given field is an embedded field.
|
// IsEmbedded returns true if the given field is an embedded field.
|
||||||
func (f *Field) IsEmbedded() bool {
|
func (f *Field) IsEmbedded() bool {
|
||||||
return f.field.Anonymous
|
return len(f.field.Index) > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsExported returns true if the given field is exported.
|
// IsExported returns true if the given field is exported.
|
||||||
func (f *Field) IsExported() bool {
|
func (f *Field) IsExported() bool {
|
||||||
return f.field.PkgPath == ""
|
return f.field.IsExported()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsZero returns true if the given field is zero value.
|
// IsZero returns true if the given field is zero value.
|
||||||
func (f *Field) IsZero() bool {
|
func (f *Field) IsZero() bool {
|
||||||
z := reflect.Zero(f.value.Type()).Interface()
|
z := reflect.Zero(f.rvalue.Type()).Interface()
|
||||||
v := f.Value()
|
v := f.Value()
|
||||||
return reflect.DeepEqual(z, v)
|
return reflect.DeepEqual(z, v)
|
||||||
}
|
}
|
||||||
@@ -51,5 +56,52 @@ func (f *Field) Name() string {
|
|||||||
|
|
||||||
// Kind returns the field's kind
|
// Kind returns the field's kind
|
||||||
func (f *Field) Kind() reflect.Kind {
|
func (f *Field) Kind() reflect.Kind {
|
||||||
return f.value.Kind()
|
return f.rvalue.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) IsSlice() bool {
|
||||||
|
k := f.rvalue.Kind()
|
||||||
|
return k == reflect.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) MapValue(value any) any {
|
||||||
|
val := pointer.ExtractPointer(value)
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
var ret any
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
s := New(val)
|
||||||
|
s.TagName = f.TagName
|
||||||
|
m, _ := s.ToMap()
|
||||||
|
ret = m
|
||||||
|
case reflect.Map:
|
||||||
|
mapEl := v.Type().Elem()
|
||||||
|
switch mapEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
// iterate the map
|
||||||
|
m := make(map[string]any, v.Len())
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
m[key.String()] = f.MapValue(v.MapIndex(key).Interface())
|
||||||
|
}
|
||||||
|
ret = m
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
sEl := v.Type().Elem()
|
||||||
|
switch sEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
slices := make([]any, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
slices[i] = f.MapValue(v.Index(i).Interface())
|
||||||
|
}
|
||||||
|
ret = slices
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|||||||
272
structutil/field_test.go
Normal file
272
structutil/field_test.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package structutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestField_Tag(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Tag")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
assert.Equal("name", tag.Name)
|
||||||
|
assert.Equal(true, tag.HasOption("omitempty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Value(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Value")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
assert.Equal("111", n.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsEmbedded(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsEmbedded())
|
||||||
|
assert.Equal(false, a.IsEmbedded())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsExported(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
assert.Equal(true, n.IsExported())
|
||||||
|
assert.Equal(false, a.IsExported())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsZero(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsZero")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsZero())
|
||||||
|
assert.Equal(false, a.IsZero())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Name(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Name")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal("Name", n.Name())
|
||||||
|
assert.Equal("Age", a.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Kind(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Kind")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal(reflect.String, n.Kind())
|
||||||
|
assert.Equal(reflect.Int, a.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsSlice(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsSlice")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
assert.Equal(true, a.IsSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_MapValue(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_MapValue")
|
||||||
|
|
||||||
|
t.Run("nested struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c1,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child any `json:"child"`
|
||||||
|
}
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &c1
|
||||||
|
c3 := &c2
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c3,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []int `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []int{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal([]int{1, 2, 3}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array in struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr array in struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *[]*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: &[]*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested map in struct", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child map[string]any `json:"child"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.MapValue(f.Value())
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}}, val)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package structutil
|
package structutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/pointer"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,11 +18,9 @@ type Struct struct {
|
|||||||
|
|
||||||
// New returns a new *Struct
|
// New returns a new *Struct
|
||||||
func New(value any) *Struct {
|
func New(value any) *Struct {
|
||||||
|
value = pointer.ExtractPointer(value)
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
t := reflect.TypeOf(value)
|
t := reflect.TypeOf(value)
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
return &Struct{
|
return &Struct{
|
||||||
raw: value,
|
raw: value,
|
||||||
rtype: t,
|
rtype: t,
|
||||||
@@ -49,8 +48,11 @@ func New(value any) *Struct {
|
|||||||
//
|
//
|
||||||
// Only the exported fields of a struct can be converted.
|
// Only the exported fields of a struct can be converted.
|
||||||
func (s *Struct) ToMap() (map[string]any, error) {
|
func (s *Struct) ToMap() (map[string]any, error) {
|
||||||
result := make(map[string]any)
|
if !s.IsStruct() {
|
||||||
|
return nil, ErrInvalidStruct(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]any)
|
||||||
fields := s.Fields()
|
fields := s.Fields()
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
|
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
|
||||||
@@ -59,8 +61,7 @@ func (s *Struct) ToMap() (map[string]any, error) {
|
|||||||
if f.IsZero() && f.tag.HasOption("omitempty") {
|
if f.IsZero() && f.tag.HasOption("omitempty") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO: sub struct
|
result[f.tag.Name] = f.MapValue(f.Value())
|
||||||
result[f.tag.Name] = f.Value()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -68,19 +69,35 @@ func (s *Struct) ToMap() (map[string]any, error) {
|
|||||||
|
|
||||||
// Fields returns all the struct fields within a slice
|
// Fields returns all the struct fields within a slice
|
||||||
func (s *Struct) Fields() []*Field {
|
func (s *Struct) Fields() []*Field {
|
||||||
|
|
||||||
var fields []*Field
|
var fields []*Field
|
||||||
fieldNum := s.rvalue.NumField()
|
fieldNum := s.rvalue.NumField()
|
||||||
for i := 0; i < fieldNum; i++ {
|
for i := 0; i < fieldNum; i++ {
|
||||||
v := s.rvalue.Field(i)
|
v := s.rvalue.Field(i)
|
||||||
sf := s.rtype.Field(i)
|
sf := s.rtype.Field(i)
|
||||||
field := newField(v, sf, DefaultTagName)
|
field := newField(v, sf, s.TagName)
|
||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field returns a Field if the given field name was found
|
||||||
|
func (s *Struct) Field(name string) (*Field, bool) {
|
||||||
|
f, ok := s.rtype.FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return newField(s.rvalue.FieldByName(name), f, s.TagName), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStruct returns true if the given rvalue is a struct
|
||||||
|
func (s *Struct) IsStruct() bool {
|
||||||
|
k := s.rvalue.Kind()
|
||||||
|
if k == reflect.Invalid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return k == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
// ToMap convert struct to map, only convert exported struct field
|
// ToMap convert struct to map, only convert exported struct field
|
||||||
// map key is specified same as struct field tag `json` value.
|
// map key is specified same as struct field tag `json` value.
|
||||||
func ToMap(v any) (map[string]any, error) {
|
func ToMap(v any) (map[string]any, error) {
|
||||||
|
|||||||
@@ -2,11 +2,18 @@ package structutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToMap(t *testing.T) {
|
func TestStruct_ToMap(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestStructToMap")
|
assert := internal.NewAssert(t, "TestStruct_ToMap")
|
||||||
|
|
||||||
|
t.Run("no struct", func(t *testing.T) {
|
||||||
|
m, _ := ToMap(1)
|
||||||
|
var expected map[string]any
|
||||||
|
assert.Equal(expected, m)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("StructToMap", func(_ *testing.T) {
|
t.Run("StructToMap", func(_ *testing.T) {
|
||||||
type People struct {
|
type People struct {
|
||||||
@@ -55,3 +62,69 @@ func TestToMap(t *testing.T) {
|
|||||||
assert.Equal(expect2, p2m)
|
assert.Equal(expect2, p2m)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStruct_Fields(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Fields")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int `json:"b"`
|
||||||
|
C []string `json:"c"`
|
||||||
|
D map[string]any `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
A: "1",
|
||||||
|
B: 11,
|
||||||
|
C: []string{"11", "22"},
|
||||||
|
D: map[string]any{"d1": 1, "d2": 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
assert.Equal(4, len(fields))
|
||||||
|
assert.Equal(reflect.String, fields[0].Kind())
|
||||||
|
assert.Equal(reflect.Int, fields[1].Kind())
|
||||||
|
assert.Equal(reflect.Slice, fields[2].Kind())
|
||||||
|
assert.Equal(reflect.Map, fields[3].Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStruct_Field(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Field")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int `json:"b"`
|
||||||
|
C []string `json:"c"`
|
||||||
|
D map[string]any `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
A: "1",
|
||||||
|
B: 11,
|
||||||
|
C: []string{"11", "22"},
|
||||||
|
D: map[string]any{"d1": 1, "d2": 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
a, ok := s.Field("A")
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(reflect.String, a.Kind())
|
||||||
|
assert.Equal("1", a.Value())
|
||||||
|
assert.Equal("a", a.tag.Name)
|
||||||
|
assert.Equal(false, a.tag.HasOption("omitempty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStruct_IsStruct(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Field")
|
||||||
|
|
||||||
|
type Test1 struct{}
|
||||||
|
t1 := &Test1{}
|
||||||
|
t2 := 1
|
||||||
|
|
||||||
|
s1 := New(t1)
|
||||||
|
s2 := New(t2)
|
||||||
|
|
||||||
|
assert.Equal(true, s1.IsStruct())
|
||||||
|
assert.Equal(false, s2.IsStruct())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user