Skip to content

Commit

Permalink
[FIX] Additional tests/fixes for KVListDeserializerFromReflect
Browse files Browse the repository at this point in the history
Apparently, previous versions failed to realize that a []string was
an instance of []any, which made things complicated.
  • Loading branch information
Nicolas Ménétrier authored and Yoric committed Dec 3, 2024
1 parent ce6906c commit 8b61b15
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
33 changes: 32 additions & 1 deletion deserialize/deserialize_reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ func TestNestedStructReflectKVDeserializer(t *testing.T) {
assert.Equal(t, *deserialized, sample)
}

// Not mandatory, but could be nice to have.
func TestAnonymStructReflectKVDeserializer(t *testing.T) {
type EmbeddedStruct struct {
BBB string
Expand Down Expand Up @@ -175,3 +174,35 @@ func TestAnonymStructReflectKVDeserializer(t *testing.T) {
assert.NilError(t, err)
assert.Equal(t, *deserialized, sample)
}

// A bug we encountered in previous versions: KVDeserializerFromReflect
// did not manage to see through an alias `[]TestType` = `[]string`.
func TestReflectKVDeserializerUnderlyingPrimitiveSlices(t *testing.T) {
type StringAlias string
type Int8Alias uint8
type BoolAlias bool
type TestStruct struct {
Strings []StringAlias
Int8s []Int8Alias
Bools []BoolAlias
}
sample := TestStruct{
Strings: []StringAlias{"abc"},
Int8s: []Int8Alias{1, 2, 3},
Bools: []BoolAlias{true, true, false},
}

deserializer, err := deserialize.MakeKVDeserializerFromReflect(deserialize.QueryOptions(""), reflect.TypeOf(sample))
assert.NilError(t, err)

kvList := map[string][]string{}
kvList["Strings"] = []string{"abc"}
kvList["Int8s"] = []string{"1", "2", "3"}
kvList["Bools"] = []string{"true", "true", "false"}

deserialized := new(TestStruct)
reflectDeserialized := reflect.ValueOf(deserialized).Elem()
err = deserializer.DeserializeKVListTo(kvList, &reflectDeserialized)
assert.NilError(t, err)
assert.DeepEqual(t, *deserialized, sample)
}
22 changes: 22 additions & 0 deletions deserialize/deserialize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1558,3 +1558,25 @@ func TestKVDeserializerFlattened(t *testing.T) {

assert.DeepEqual(t, *found, expected)
}

// KVListDeserializer works with arrays with non-primitive types with a primitive Kind.
func TestKVDeserializeUnderlyingPrimitiveSlices(t *testing.T) {
type TestType string
type TestStruct struct {
TestField []TestType
}

deserializer, err := deserialize.MakeKVListDeserializer[TestStruct](deserialize.QueryOptions(""))
assert.NilError(t, err)

sample := TestStruct{
TestField: []TestType{"abc"},
}

kvlist := make(map[string][]string)
kvlist["TestField"] = []string{"abc"}

deserialized, err := deserializer.DeserializeKVList(kvlist)
assert.NilError(t, err)
assert.DeepEqual(t, *deserialized, sample)
}
18 changes: 13 additions & 5 deletions deserialize/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,22 @@ func (v Value) AsDict() (shared.Dict, bool) {
}
}
func (v Value) AsSlice() ([]shared.Value, bool) {
if wrapped, ok := v.wrapped.([]any); ok {
result := make([]shared.Value, len(wrapped))
for i, value := range wrapped {
result[i] = Value{wrapped: value}
// We can't simply cast to `[]any`, as this doesn't work for e.g. `[]string`.
reflected := reflect.ValueOf(v.wrapped)
switch reflected.Type().Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
length := reflected.Len()
result := make([]shared.Value, length)
for i := 0; i < length; i++ {
value := reflected.Index(i)
result[i] = Value{wrapped: value.Interface()}
}
return result, true
default:
return nil, false
}
return nil, false
}
func (v Value) Interface() any {
return v.wrapped
Expand Down

0 comments on commit 8b61b15

Please sign in to comment.