Skip to content

Commit

Permalink
- Completing map assignment from struct and from map ✨
Browse files Browse the repository at this point in the history
- Refactoring some functions ♻️
- Adding and updating test cases ✅
- Adding GetType function ✨
  • Loading branch information
fairyhunter13 committed Jun 14, 2021
1 parent 7275596 commit 3027d1d
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 51 deletions.
56 changes: 41 additions & 15 deletions assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,17 @@ import (
"time"

"github.com/fairyhunter13/task/v2"
"github.com/mitchellh/mapstructure"
)

func checkAssigner(assigner reflect.Value) (err error) {
err = getErrIsValid(assigner)
if err != nil {
return
}
if !assigner.CanSet() {
err = ErrAssignerCantSet
}
return
}

func assignReflect(assigner reflect.Value, val reflect.Value, opt *Option) (err error) {
var oriAssigner reflect.Value
if assigner.CanSet() {
oriAssigner = assigner
} else {
oriAssigner = GetChildElem(assigner)
}

err = checkAssigner(oriAssigner)
if err != nil {
return
Expand Down Expand Up @@ -128,12 +119,20 @@ func tryAssign(assigner reflect.Value, val reflect.Value, opt *Option) (err erro
assigner.SetString(result)
case reflect.Map:
switch valKind {
case reflect.Map, reflect.Struct, reflect.Array, reflect.Slice:
// TODO: Add map decoding
case reflect.Map:
if GetType(assigner) == GetType(val) {
err = assignDefault(assigner, val)
if err == nil {
return
}
}
fallthrough
case reflect.Struct, reflect.Array, reflect.Slice:
err = assignMap(assigner, val, opt)
default:
err = assignDefault(assigner, val)
}
case reflect.Chan, reflect.Func, reflect.Struct, reflect.Interface:
case reflect.Struct:
switch assigner.Type() {
case TypeTime:
var timeRes time.Time
Expand All @@ -142,15 +141,42 @@ func tryAssign(assigner reflect.Value, val reflect.Value, opt *Option) (err erro
return
}
assigner.Set(reflect.ValueOf(timeRes))
return
default:
err = assignDefault(assigner, val)
if !IsKindMap(valKind) && !IsKindStruct(valKind) {
break
}

err = assignMap(assigner, val, opt)
if err == nil {
return
}
}
fallthrough
case reflect.Chan, reflect.Func, reflect.Interface:
err = assignDefault(assigner, val)
default:
err = getErrUnimplementedAssign(assigner, val)
}
return
}

func assignMap(assigner reflect.Value, val reflect.Value, opt *Option) (err error) {
err = getErrCanAddrInterface(assigner)
if err != nil {
return
}

opt.DecoderConfig.Result = assigner.Addr().Interface()
decoder, err := mapstructure.NewDecoder(opt.DecoderConfig)
if err != nil {
return
}

err = decoder.Decode(val.Interface())
return
}

func assignDefault(assigner reflect.Value, val reflect.Value) (err error) {
err = getErrUnassignable(assigner, val)
if err != nil {
Expand Down
98 changes: 97 additions & 1 deletion assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestAssignReflect(t *testing.T) {
wantAssigner: nil,
},
{
name: "nil assigner",
name: "nil ptr assigner",
args: args{
assigner: func() reflect.Value {
var hello *int
Expand Down Expand Up @@ -640,6 +640,102 @@ func TestAssignReflect(t *testing.T) {
wantAssigner: nil,
wantErr: true,
},
{
name: "assign map from struct",
args: args{
assigner: func() reflect.Value {
hello := make(map[string]interface{})
return reflect.ValueOf(&hello)
},
val: func() reflect.Value {
type test struct {
Hello string
Hi int
}
return reflect.ValueOf(test{"hello", 5})
},
},
wantAssigner: func() reflect.Value {
return reflect.ValueOf(map[string]interface{}{
"Hello": "hello",
"Hi": 5,
})
},
wantErr: false,
},
{
name: "assign map from map with different type",
args: args{
assigner: func() reflect.Value {
hello := make(map[string]interface{})
return reflect.ValueOf(&hello)
},
val: func() reflect.Value {
return reflect.ValueOf(map[string]int{"hello": 5, "hi": 10})
},
},
wantAssigner: func() reflect.Value {
return reflect.ValueOf(map[string]interface{}{
"hello": 5,
"hi": 10,
})
},
wantErr: false,
},
{
name: "assign map from int - error",
args: args{
assigner: func() reflect.Value {
hello := make(map[string]interface{})
return reflect.ValueOf(&hello)
},
val: func() reflect.Value {
return reflect.ValueOf(5)
},
},
wantAssigner: nil,
wantErr: true,
},
{
name: "assign struct from map",
args: args{
assigner: func() reflect.Value {
type test struct {
Hello string
Hi int
}
return reflect.ValueOf(&test{})
},
val: func() reflect.Value {
return reflect.ValueOf(map[string]interface{}{"hello": "hola!", "hi": 10})
},
},
wantAssigner: func() reflect.Value {
type test struct {
Hello string
Hi int
}
return reflect.ValueOf(test{"hola!", 10})
},
wantErr: false,
},
{
name: "assign struct from int - error",
args: args{
assigner: func() reflect.Value {
type test struct {
Hello string
Hi int
}
return reflect.ValueOf(&test{})
},
val: func() reflect.Value {
return reflect.ValueOf(5)
},
},
wantAssigner: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func IsValueZero(v reflect.Value) bool {

// IsStructZero checks if the struct is zero.
func IsStructZero(v reflect.Value) bool {
if !v.IsValid() || v.NumField() == 0 {
if !v.IsValid() || !IsKindStruct(GetKind(v)) || v.NumField() == 0 {
return true
}

Expand All @@ -134,7 +134,7 @@ func IsStructZero(v reflect.Value) bool {

// IsArrayZero checks if the array is empty.
func IsArrayZero(v reflect.Value) bool {
if !v.IsValid() || v.Len() == 0 {
if !v.IsValid() || !IsKindList(GetKind(v)) || v.Len() == 0 {
return true
}

Expand Down
54 changes: 53 additions & 1 deletion empty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"testing"
"time"

"github.com/fairyhunter13/decimal"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -219,3 +219,55 @@ func TestIsPtrValueZero(t *testing.T) {
})
}
}

func TestIsStructZero(t *testing.T) {
type args struct {
v reflect.Value
}
tests := []struct {
name string
args args
want bool
}{
{
name: "kind is not struct",
args: args{
v: reflect.ValueOf(5),
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsStructZero(tt.args.v); got != tt.want {
t.Errorf("IsStructZero() = %v, want %v", got, tt.want)
}
})
}
}

func TestIsArrayZero(t *testing.T) {
type args struct {
v reflect.Value
}
tests := []struct {
name string
args args
want bool
}{
{
name: "kind is not array or slice",
args: args{
v: reflect.ValueOf(5),
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsArrayZero(tt.args.v); got != tt.want {
t.Errorf("IsArrayZero() = %v, want %v", got, tt.want)
}
})
}
}
54 changes: 46 additions & 8 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ func getErrOverflow(val reflect.Value) (err error) {
}

func getErrUnassignable(assigner reflect.Value, val reflect.Value) (err error) {
assignerType := assigner.Type()
valType := val.Type()
assignerType := GetType(assigner)
valType := GetType(val)
if !valType.AssignableTo(assignerType) {
err = fmt.Errorf(
"error unassignable for kind: %s with val of reflect.Value, kind: %s type: %s val: %s",
GetKind(assigner),
GetKind(val),
val.Type(),
GetType(val),
val,
)
}
Expand All @@ -43,9 +43,9 @@ func getErrOverflowedLength(assigner reflect.Value, val reflect.Value, isSlice b
if assigner.Len() < val.Len() {
err = fmt.Errorf(
"error length of assigner is smaller than the length of val, assigner type:%s length:%d, val type:%s length:%d",
assigner.Type(),
GetType(assigner),
assigner.Len(),
val.Type(),
GetType(val),
val.Len(),
)
}
Expand All @@ -57,7 +57,7 @@ func getErrCanInterface(val reflect.Value) (err error) {
err = fmt.Errorf(
"can't get the interface from the val of reflect.Value, kind: %s type: %s val: %s",
GetKind(val),
val.Type(),
GetType(val),
val,
)
}
Expand All @@ -78,7 +78,7 @@ func getErrUnimplementedExtract(val reflect.Value) (err error) {
err = fmt.Errorf(
"error unimplemented extraction for val of reflect.Value,kind: %s type: %s val: %s",
GetKind(val),
val.Type(),
GetType(val),
val,
)
return
Expand All @@ -89,8 +89,46 @@ func getErrUnimplementedAssign(assigner reflect.Value, val reflect.Value) (err e
"error unimplemented assignment for kind: %s with val of reflect.Value, kind: %s type: %s val: %s",
GetKind(assigner),
GetKind(val),
val.Type(),
GetType(val),
val,
)
return
}

func getErrCanAddrInterface(assigner reflect.Value) (err error) {
if !assigner.CanAddr() {
err = fmt.Errorf(
"error can't get pointer address from assigner, kind: %s type: %s val: %s",
GetKind(assigner),
GetType(assigner),
assigner,
)
return
}
err = getErrCanInterface(assigner.Addr())
return
}

func checkAssigner(assigner reflect.Value) (err error) {
err = getErrIsValid(assigner)
if err != nil {
return
}

if !assigner.CanSet() {
err = ErrAssignerCantSet
}
return
}

func checkExtractValid(val reflect.Value, opt *Option) (err error) {
if !opt.hasCheckExtractValid {
defer opt.toggleOnCheckExtractValid()
err = getErrIsValid(val)
if err != nil {
return
}
err = getErrCanInterface(val)
}
return
}
Loading

0 comments on commit 3027d1d

Please sign in to comment.