fix error when convert empty lua table
Signed-off-by: yingjinhui <yingjinhui@didiglobal.com>
This commit is contained in:
parent
aeac17b77d
commit
5cc6d813ab
|
@ -16,6 +16,60 @@ func ConvertLuaResultInto(luaResult lua.LValue, obj interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("obj is not pointer")
|
return fmt.Errorf("obj is not pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For example, `GetReplicas` returns requirement with empty:
|
||||||
|
// {
|
||||||
|
// nodeClaim: {},
|
||||||
|
// resourceRequest: {
|
||||||
|
// cpu: "100m"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Luajson encodes it to
|
||||||
|
// {"nodeClaim": [], "resourceRequest": {"cpu": "100m"}}
|
||||||
|
//
|
||||||
|
// While go json fails to unmarshal `[]` to ReplicaRequirements.NodeClaim object.
|
||||||
|
// ReplicaRequirements object.
|
||||||
|
//
|
||||||
|
// Here we handle it as follows:
|
||||||
|
// 1. Walk the object (lua table), delete the key with empty value (`nodeClaim` in this example):
|
||||||
|
// {
|
||||||
|
// resourceRequest: {
|
||||||
|
// cpu: "100m"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// 2. Encode the object with luajson to be:
|
||||||
|
// {"resourceRequest": {"cpu": "100m"}}
|
||||||
|
// 4. Finally, unmarshal the new json to object, get
|
||||||
|
// {
|
||||||
|
// resourceRequest: {
|
||||||
|
// cpu: "100m"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
isEmptyDic := func(v *lua.LTable) bool {
|
||||||
|
count := 0
|
||||||
|
v.ForEach(func(lua.LValue, lua.LValue) {
|
||||||
|
count++
|
||||||
|
})
|
||||||
|
return count == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var walkValue func(v lua.LValue)
|
||||||
|
walkValue = func(v lua.LValue) {
|
||||||
|
if t, ok := v.(*lua.LTable); ok {
|
||||||
|
t.ForEach(func(key lua.LValue, value lua.LValue) {
|
||||||
|
if tt, ok := value.(*lua.LTable); ok {
|
||||||
|
if isEmptyDic(tt) {
|
||||||
|
// set nil to delete key
|
||||||
|
t.RawSetH(key, lua.LNil)
|
||||||
|
} else {
|
||||||
|
walkValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walkValue(luaResult)
|
||||||
|
|
||||||
jsonBytes, err := luajson.Encode(luaResult)
|
jsonBytes, err := luajson.Encode(luaResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("json Encode obj eroor %v", err)
|
return fmt.Errorf("json Encode obj eroor %v", err)
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package luavm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertLuaResultInto(t *testing.T) {
|
||||||
|
type barStruct struct {
|
||||||
|
Bar string
|
||||||
|
}
|
||||||
|
type fooStruct struct {
|
||||||
|
Bar barStruct
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
luaResult lua.LValue
|
||||||
|
obj interface{}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
want interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "not a pointer",
|
||||||
|
args: args{
|
||||||
|
luaResult: &lua.LTable{},
|
||||||
|
obj: struct{}{},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
want: struct{}{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty table into struct",
|
||||||
|
args: args{
|
||||||
|
luaResult: &lua.LTable{},
|
||||||
|
obj: &fooStruct{},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
want: &fooStruct{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty table into slice",
|
||||||
|
args: args{
|
||||||
|
luaResult: &lua.LTable{},
|
||||||
|
obj: &[]string{},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
want: &[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-empty table into slice",
|
||||||
|
args: args{
|
||||||
|
luaResult: func() lua.LValue {
|
||||||
|
v := &lua.LTable{}
|
||||||
|
v.Append(lua.LString("foo"))
|
||||||
|
v.Append(lua.LString("bar"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
obj: &[]string{},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
want: &[]string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "table with empty table into slice",
|
||||||
|
args: args{
|
||||||
|
luaResult: func() lua.LValue {
|
||||||
|
v := &lua.LTable{}
|
||||||
|
v.RawSetString("Bar", &lua.LTable{})
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
obj: &fooStruct{},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
want: &fooStruct{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "struct is not empty, and convert successfully",
|
||||||
|
args: args{
|
||||||
|
luaResult: func() lua.LValue {
|
||||||
|
bar := &lua.LTable{}
|
||||||
|
bar.RawSetString("Bar", lua.LString("bar"))
|
||||||
|
|
||||||
|
v := &lua.LTable{}
|
||||||
|
v.RawSetString("Bar", bar)
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
obj: &fooStruct{},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
want: &fooStruct{
|
||||||
|
Bar: barStruct{Bar: "bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := ConvertLuaResultInto(tt.args.luaResult, tt.args.obj); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ConvertLuaResultInto() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
if got := tt.args.obj; !reflect.DeepEqual(tt.want, got) {
|
||||||
|
t.Errorf("ConvertLuaResultInto() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue