Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022-2024 The Decred developers
// Copyright (c) 2022-2025 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -66,8 +66,11 @@ func (c *Client) FeeAddress(ctx context.Context, req types.FeeAddressRequest,
func (c *Client) PayFee(ctx context.Context, req types.PayFeeRequest,
commitmentAddr stdaddr.Address) (*types.PayFeeResponse, error) {

// TSpendPolicy and TreasuryPolicy are optional but must be an empty map
// rather than nil.
// VoteChoices, TSpendPolicy and TreasuryPolicy are optional but must be an
// empty map rather than nil.
if req.VoteChoices == nil {
req.VoteChoices = map[string]string{}
}
if req.TSpendPolicy == nil {
req.TSpendPolicy = map[string]string{}
}
Expand Down Expand Up @@ -119,8 +122,11 @@ func (c *Client) TicketStatus(ctx context.Context, req types.TicketStatusRequest
func (c *Client) SetVoteChoices(ctx context.Context, req types.SetVoteChoicesRequest,
commitmentAddr stdaddr.Address) (*types.SetVoteChoicesResponse, error) {

// TSpendPolicy and TreasuryPolicy are optional but must be an empty map
// rather than nil.
// VoteChoices, TSpendPolicy and TreasuryPolicy are optional but must be an
// empty map rather than nil.
if req.VoteChoices == nil {
req.VoteChoices = map[string]string{}
}
if req.TSpendPolicy == nil {
req.TSpendPolicy = map[string]string{}
}
Expand Down
114 changes: 114 additions & 0 deletions internal/webapi/binding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package webapi

import (
"testing"

"github.com/decred/vspd/types/v3"
"github.com/gin-gonic/gin/binding"
)

// TestGinJSONBinding does not test code in this package. It is a
// characterization test to determine exactly how Gin handles JSON binding tags.
func TestGinJSONBinding(t *testing.T) {
tests := map[string]struct {
req []byte
expectedErr string
}{

"Filled arrays bind without error": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": {"k": "v"},
"tspendpolicy": {"k": "v"},
"treasurypolicy": {"k": "v"}
}`),
expectedErr: "",
},

"Array filled beyond max does not bind": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": {"k": "v"},
"tspendpolicy": {"k": "v"},
"treasurypolicy": {"k1": "v","k2": "v","k3": "v","k4": "v"}
}`),
expectedErr: "Key: 'SetVoteChoicesRequest.TreasuryPolicy' Error:Field validation for 'TreasuryPolicy' failed on the 'max' tag",
},

"Empty arrays bind without error": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": {},
"tspendpolicy": {},
"treasurypolicy": {}
}`),
expectedErr: "",
},

"Missing array with 'required' tag does not bind": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"tspendpolicy": {},
"treasurypolicy": {}
}`),
expectedErr: "Key: 'SetVoteChoicesRequest.VoteChoices' Error:Field validation for 'VoteChoices' failed on the 'required' tag",
},

"Missing array with 'max' tag binds without error": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": {},
"treasurypolicy": {}
}`),
expectedErr: "",
},

"Null array with 'required' tag does not bind": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": null,
"tspendpolicy": {},
"treasurypolicy": {}
}`),
expectedErr: "Key: 'SetVoteChoicesRequest.VoteChoices' Error:Field validation for 'VoteChoices' failed on the 'required' tag",
},

"Null array with 'max' tag binds without error": {
req: []byte(`{
"timestamp": 12345,
"tickethash": "hash",
"votechoices": {},
"tspendpolicy": null,
"treasurypolicy": {}
}`),
expectedErr: "",
},
}

for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
err := binding.JSON.BindBody(test.req, &types.SetVoteChoicesRequest{})
if test.expectedErr == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
} else {
if err == nil {
t.Fatalf("expected error but got none")
}
if err.Error() != test.expectedErr {
t.Fatalf("incorrect error, got %q expected %q",
err.Error(), test.expectedErr)
}
}

})
}

}
Loading