Skip to content

Commit

Permalink
Merge pull request #87 from alexejk/nested_mixed_arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
alexejk committed May 16, 2024
2 parents c1e7cf1 + 78203c0 commit efdc407
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 6 deletions.
9 changes: 6 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ linters-settings:
- $gostd
- github.com/stretchr/testify
gci:
local-prefixes: github.com/golangci/golangci-lint
sections:
- standard # Standard section: captures all standard packages.
- default
- prefix(alexejk.io/go-xmlrpc)
goconst:
min-len: 2
min-occurrences: 2
Expand All @@ -29,7 +32,7 @@ linters-settings:
- wrapperFunc
goimports:
local-prefixes: alexejk.io/go-xmlrpc
gomnd:
mnd:
settings:
mnd:
# don't include the "operation" and "assign"
Expand Down Expand Up @@ -63,7 +66,7 @@ linters:
- gocritic
- gofmt
- goimports
- gomnd
- mnd
- goprintffuncname
- gosec
- gosimple
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.5.3

Bugfixes:
* Decoding an `<array>` of mixed types that contains another set of nested `<array>` (with equally mixed types) (#86).
Outer slice would need to be defined as `[]any` and it's up to the user to cast the inner values (including nested slices) to the desired/expected type.


## 0.5.2

Bugfixes:
Expand Down
82 changes: 82 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,88 @@ func TestClient_Call(t *testing.T) {
require.Equal(t, 12345, resp.Index)
}

func TestClient_Github_86(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
m := &struct {
Name string `xml:"methodName"`
Params []*ResponseParam `xml:"params>param"`
}{}
body, err := io.ReadAll(r.Body)
require.NoError(t, err, "test server: read body")

err = xml.Unmarshal(body, m)
require.NoError(t, err, "test server: unmarshal body")

require.Equal(t, "di", m.Name)
require.Equal(t, 3, len(m.Params))

expected := []string{"abc", "def", "hij"}
for i, p := range m.Params {
require.Equal(t, expected[i], *p.Value.String)
}

respBody := `<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>OK</string></value>
</param>
<param>
<value><int>200</int></value>
</param>
<param>
<value>
<array>
<data>
<value><i4>200</i4></value>
<value><array><data><value>Some String</value></data></array></value>
<value>Server: Sip Express Media Server (5.1.0 (x86_64/Linux)) calls: 0 active/0 total/0 connect/0 min</value>
</data>
</array>
</value>
</param>
</params>
</methodResponse>`
_, _ = fmt.Fprintln(w, respBody)
}))
defer ts.Close()

c, err := NewClient(ts.URL)
require.NoError(t, err)
require.NotNil(t, c)

type DiRequest struct {
First string
Second string
Third string
}

type DiResponse struct {
Status string
Code int
Data []any
}

req := &DiRequest{
First: "abc",
Second: "def",
Third: "hij",
}
resp := &DiResponse{}

err = c.Call("di", req, resp)
require.NoError(t, err)
require.Equal(t, "OK", resp.Status)
require.Equal(t, 200, resp.Code)

// Data array decoding validation
require.NotEmpty(t, resp.Data)
require.Len(t, resp.Data, 3)
require.Equal(t, 200, resp.Data[0].(int))
require.Equal(t, []any{"Some String"}, resp.Data[1].([]any))
require.Equal(t, "Server: Sip Express Media Server (5.1.0 (x86_64/Linux)) calls: 0 active/0 total/0 connect/0 min", resp.Data[2].(string))
}

func TestClient_Fault(t *testing.T) {
ts := mockupServer(t, "response_fault.xml")
defer ts.Close()
Expand Down
13 changes: 12 additions & 1 deletion decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,18 @@ func (d *StdDecoder) decodeValue(value *ResponseValue, field reflect.Value) erro

// Array decoding
case value.Array != nil:
if field.Kind() != reflect.Slice {
fieldKind := field.Kind()

// When dealing with nested arrays of []any type, initial kind for the nested array will be reflect.Interface
if fieldKind == reflect.Interface {
// Create a new []interface{} and assign it to field
fieldType := reflect.SliceOf(reflect.TypeOf((*interface{})(nil)).Elem())
fieldKind = reflect.Slice

field.Set(reflect.MakeSlice(fieldType, 0, 0))
}

if fieldKind != reflect.Slice {
return fmt.Errorf(errFormatInvalidFieldType, reflect.Slice.String(), field.Kind().String())
}

Expand Down
23 changes: 22 additions & 1 deletion decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func TestStdDecoder_DecodeRaw(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}
}{},
expect: &struct {
Expand All @@ -86,6 +87,7 @@ func TestStdDecoder_DecodeRaw(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}
}{
Struct: struct {
Expand All @@ -94,12 +96,14 @@ func TestStdDecoder_DecodeRaw(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}{
Foo: "bar",
Baz: 2,
WoBleBobble: true,
WoBleBobble2: 34,
Field2: 3,
Array: []any{200, "Some String", []any{"Nested String", 10, true}},
},
},
},
Expand Down Expand Up @@ -274,6 +278,7 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}
}{},
expect: &struct {
Expand All @@ -283,6 +288,7 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}
}{
Struct: struct {
Expand All @@ -291,12 +297,14 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 int
Field2 int `xmlrpc:"2"`
Array []any
}{
Foo: "bar",
Baz: 2,
WoBleBobble: true,
WoBleBobble2: 34,
Field2: 3,
Array: []any{200, "Some String", []any{"Nested String", 10, true}},
},
},
},
Expand All @@ -310,6 +318,7 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 *int
Field2 *int `xmlrpc:"2"`
Array []any
}
}{},
expect: &struct {
Expand All @@ -319,6 +328,7 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 *int
Field2 *int `xmlrpc:"2"`
Array []any
}
}{
Struct: &struct {
Expand All @@ -327,12 +337,14 @@ func TestStdDecoder_DecodeRaw_StructFields(t *testing.T) {
WoBleBobble bool
WoBleBobble2 *int
Field2 *int `xmlrpc:"2"`
Array []any
}{
Foo: sPtr("bar"),
Baz: 2,
WoBleBobble: true,
WoBleBobble2: iPtr(34),
Field2: iPtr(3),
Array: []any{200, "Some String", []any{"Nested String", 10, true}},
},
},
},
Expand Down Expand Up @@ -407,6 +419,13 @@ func TestStdDecoder_DecodeRaw_Arrays(t *testing.T) {
Array: []any{0, "4099", "O3D217AC", "<c><b>123</b></c>"},
},
},
// Related to issue #86: https://github.com/alexejk/go-xmlrpc/issues/86
"Basic mixed array - with nested mixed array (Github #86)": {
testFile: "response_array_mixed_with_array.xml",
expect: &TestStruct{
Array: []any{10, "s11", true, []any{"Some String", []any{"Nested String", 10, true}}},
},
},
}

for name, tt := range tests {
Expand Down Expand Up @@ -456,6 +475,7 @@ func TestStdDecoder_DecodeRaw_Struct_Map(t *testing.T) {
"woBleBobble": true,
"WoBleBobble2": 34,
"2": 3,
"array": []any{200, "Some String", []any{"Nested String", 10, true}},
},
},
},
Expand Down Expand Up @@ -622,7 +642,8 @@ func Test_structMemberToFieldName(t *testing.T) {
}
}

func Test_github(t *testing.T) {
// Issue: https://github.com/alexejk/go-xmlrpc/issues/84
func Test_github_84(t *testing.T) {
dec := &StdDecoder{}
decodeTarget := struct {
Array []any
Expand Down
2 changes: 1 addition & 1 deletion hack/linter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ GREEN="\033[32m"
YELLOW="\033[33m"
NORMAL="\033[39m"

LINTER_VERSION=1.56.1
LINTER_VERSION=1.58.1

LINTER_BINDIR=$(go env GOPATH)/bin
LINTER_NAME=golangci-lint
Expand Down
36 changes: 36 additions & 0 deletions testdata/response_array_mixed_with_array.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<!--
Issue #86: https://github.com/alexejk/go-xmlrpc/issues/86
Nested array in the mixed array decoding issue
-->
<methodResponse>
<params>
<param>
<value>
<array>
<data>
<value><int>10</int></value>
<value><string>s11</string></value>
<value><boolean>1</boolean></value>
<value>
<array>
<data>
<value>Some String</value>
<value>
<array>
<data>
<value>Nested String</value>
<value><int>10</int></value>
<value><boolean>1</boolean></value>
</data>
</array>
</value>
</data>
</array>
</value>
</data>
</array>
</value>
</param>
</params>
</methodResponse>
20 changes: 20 additions & 0 deletions testdata/response_struct.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@
<name>2</name>
<value><int>3</int></value>
</member>
<member>
<name>array</name>
<value>
<array>
<data>
<value><int>200</int></value>
<value><string>Some String</string></value>
<value>
<array>
<data>
<value><string>Nested String</string></value>
<value><int>10</int></value>
<value><boolean>1</boolean></value>
</data>
</array>
</value>
</data>
</array>
</value>
</member>
</struct>
</value>
</param>
Expand Down

0 comments on commit efdc407

Please sign in to comment.