Skip to content

Commit

Permalink
Merge pull request #69 from alexejk/skip-unknown-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
alexejk authored Aug 8, 2022
2 parents c221db9 + b14b0a4 commit ecb01a6
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 8 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
make build-in-docker
- name: Code coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./build/coverage.txt
files: ./build/coverage.txt
yml: ./codecov.yaml

- name: SonarCloud Scan
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Improvements:

* Ability to remap struct member names to via `xmlrpc` tags (#47)
* Ability to skip unknown fields by `SkipUnknownFields(bool)` `Option` (#48)

Library is now built against Go 1.19

Expand Down
10 changes: 10 additions & 0 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ func NewCodec(endpoint *url.URL, httpClient *http.Client) *Codec {
}
}

// SetEncoder allows setting a new Encoder on the codec
func (c *Codec) SetEncoder(encoder Encoder) {
c.encoder = encoder
}

// SetDecoder allows setting a new Decoder on the codec
func (c *Codec) SetDecoder(decoder Decoder) {
c.decoder = decoder
}

func (c *Codec) WriteRequest(req *rpc.Request, args interface{}) error {
bodyBuffer := new(bytes.Buffer)
err := c.encoder.Encode(bodyBuffer, req.ServiceMethod, args)
Expand Down
8 changes: 8 additions & 0 deletions codecov.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
coverage:
status:
project:
default:
target: 80%
threshold: 5%
patch:
default:
target: 70%
precision: 2
round: down
range: "70...100"
7 changes: 6 additions & 1 deletion decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ type Decoder interface {
}

// StdDecoder is the default implementation of the Decoder interface.
type StdDecoder struct{}
type StdDecoder struct {
skipUnknownFields bool
}

func (d *StdDecoder) DecodeRaw(body []byte, v interface{}) error {
response, err := NewResponse(body)
Expand Down Expand Up @@ -139,6 +141,9 @@ func (d *StdDecoder) decodeValue(value *ResponseValue, field reflect.Value) erro
f := findFieldByNameOrTag(field, fName)

if !f.IsValid() {
if d.skipUnknownFields {
continue
}
return fmt.Errorf("cannot find field '%s' on struct", fName)
}

Expand Down
45 changes: 40 additions & 5 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (

func TestStdDecoder_DecodeRaw(t *testing.T) {
tests := []struct {
name string
testFile string
v interface{}
expect interface{}
err error
name string
testFile string
skipUnknown bool
v interface{}
expect interface{}
err error
}{
{
name: "simple response",
Expand Down Expand Up @@ -107,6 +108,39 @@ func TestStdDecoder_DecodeRaw(t *testing.T) {
},
},
},
{
name: "struct response - skip unknown",
testFile: "response_struct.xml",
skipUnknown: true,
v: &struct {
Struct struct {
Foo string
Baz int
WoBleBobble bool
WoBleBobble2 int
}
}{},
expect: &struct {
Struct struct {
Foo string
Baz int
WoBleBobble bool
WoBleBobble2 int
}
}{
Struct: struct {
Foo string
Baz int
WoBleBobble bool
WoBleBobble2 int
}{
Foo: "bar",
Baz: 2,
WoBleBobble: true,
WoBleBobble2: 34,
},
},
},
{
name: "struct response - bad param",
testFile: "response_struct.xml",
Expand All @@ -121,6 +155,7 @@ func TestStdDecoder_DecodeRaw(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dec := &StdDecoder{}
dec.skipUnknownFields = tt.skipUnknown
err := dec.DecodeRaw(loadTestFile(t, tt.testFile), tt.v)

if tt.err == nil {
Expand Down
10 changes: 10 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,13 @@ func UserAgent(userAgent string) Option {
client.codec.userAgent = userAgent
}
}

// SkipUnknownFields option allows setting decoder setting to skip unknown fields.
// This is only effective if using standard client, which in turn uses StdDecoder.
func SkipUnknownFields(skip bool) Option {
return func(client *Client) {
if v, ok := client.codec.decoder.(*StdDecoder); ok {
v.skipUnknownFields = skip
}
}
}
55 changes: 55 additions & 0 deletions options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,58 @@ func TestClient_Option_HttpClient(t *testing.T) {
})
}
}

func TestClient_Option_SkipUnknownFields(t *testing.T) {
tests := []struct {
name string
opts []Option
expect bool
}{
{
name: "default setting",
expect: false,
},
{
name: "new setting - false",
opts: []Option{
SkipUnknownFields(false),
},
expect: false,
},
{
name: "new setting - false",
opts: []Option{
SkipUnknownFields(true),
},
expect: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
serverCalled := false
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
serverCalled = true
_, _ = fmt.Fprintln(w, string(loadTestFile(t, "response_bugzilla_version.xml")))
}))
defer ts.Close()

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

v := &struct {
Bugzilla struct {
}
}{}

err = c.Call("test.Method", nil, v)
if tt.expect {
require.NoError(t, err)
} else {
require.Error(t, err)
}

require.True(t, serverCalled, "server must be called")
})
}
}

0 comments on commit ecb01a6

Please sign in to comment.