Fix assignment to nil map.

Ensure that Tickets loaded from the database are returned with empty maps instead of nil maps.

To be back-ported to 1.1.0 release.
This commit is contained in:
Jamie Holdstock 2022-03-22 13:46:43 +00:00 committed by GitHub
parent 9fa1012f3d
commit aac96f8c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 19 deletions

28
database/helpers.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright (c) 2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"encoding/json"
)
func bytesToStringMap(bytes []byte) (map[string]string, error) {
if bytes == nil {
return make(map[string]string), nil
}
var stringMap map[string]string
err := json.Unmarshal(bytes, &stringMap)
if err != nil {
return nil, err
}
// stringMap can still be nil here, eg. if bytes == "null".
if stringMap == nil {
stringMap = make(map[string]string)
}
return stringMap, nil
}

78
database/helpers_test.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright (c) 2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"reflect"
"testing"
)
func TestBytesToStringMap(t *testing.T) {
t.Parallel()
var tests = []struct {
name string
input []byte
expect map[string]string
expectErr bool
}{
{
name: "Empty map on nil bytes",
input: nil,
expect: map[string]string{},
expectErr: false,
},
{
name: "Empty map on empty json map",
input: []byte("{}"),
expect: map[string]string{},
expectErr: false,
},
{
name: "Empty map on null",
input: []byte("null"),
expect: map[string]string{},
expectErr: false,
},
{
name: "Correct values with valid json",
input: []byte("{\"key\":\"value\"}"),
expect: map[string]string{"key": "value"},
expectErr: false,
},
{
name: "Error on no bytes",
input: []byte(""),
expect: nil,
expectErr: true,
},
{
name: "Error on invalid json",
input: []byte("invalid json"),
expect: nil,
expectErr: true,
},
{
name: "Error on non-map json",
input: []byte("[\"not a map\"]"),
expect: nil,
expectErr: true,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
result, err := bytesToStringMap(test.input)
if !reflect.DeepEqual(test.expect, result) {
t.Fatalf("expected %v, got %v", test.expect, result)
}
if test.expectErr != (err != nil) {
t.Fatalf("expected err=%t, got %v", test.expectErr, err)
}
})
}
}

View File

@ -223,29 +223,19 @@ func getTicketFromBkt(bkt *bolt.Bucket) (Ticket, error) {
ticket.Confirmed = bytesToBool(bkt.Get(confirmedK))
var err error
voteChoicesB := bkt.Get(voteChoicesK)
if voteChoicesB != nil {
err = json.Unmarshal(voteChoicesB, &ticket.VoteChoices)
if err != nil {
return ticket, fmt.Errorf("unmarshal VoteChoices err: %w", err)
}
ticket.VoteChoices, err = bytesToStringMap(bkt.Get(voteChoicesK))
if err != nil {
return ticket, fmt.Errorf("unmarshal VoteChoices err: %w", err)
}
tSpendPolicyB := bkt.Get(tSpendPolicyK)
if tSpendPolicyB != nil {
err = json.Unmarshal(tSpendPolicyB, &ticket.TSpendPolicy)
if err != nil {
return ticket, fmt.Errorf("unmarshal TSpendPolicy err: %w", err)
}
ticket.TSpendPolicy, err = bytesToStringMap(bkt.Get(tSpendPolicyK))
if err != nil {
return ticket, fmt.Errorf("unmarshal TSpendPolicy err: %w", err)
}
treasuryPolicyB := bkt.Get(treasuryPolicyK)
if treasuryPolicyB != nil {
err = json.Unmarshal(treasuryPolicyB, &ticket.TreasuryPolicy)
if err != nil {
return ticket, fmt.Errorf("unmarshal TreasuryPolicy err: %w", err)
}
ticket.TreasuryPolicy, err = bytesToStringMap(bkt.Get(treasuryPolicyK))
if err != nil {
return ticket, fmt.Errorf("unmarshal TreasuryPolicy err: %w", err)
}
return ticket, nil