forked from TrueCloudLab/neoneo-go
smartcontract: add marshaller for Parameter
1) Add marshaller and tests for smartcontract.Parameter 2) Add unmarshaller and tests for missing types of smartcontract.Parameter: - MapType - BoolType
This commit is contained in:
parent
648e0bb242
commit
535f391550
2 changed files with 256 additions and 13 deletions
|
@ -46,6 +46,75 @@ type rawParameter struct {
|
|||
Value json.RawMessage `json:"value"`
|
||||
}
|
||||
|
||||
type keyValuePair struct {
|
||||
Key rawParameter `json:"key"`
|
||||
Value rawParameter `json:"value"`
|
||||
}
|
||||
|
||||
type rawKeyValuePair struct {
|
||||
Key json.RawMessage `json:"key"`
|
||||
Value json.RawMessage `json:"value"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements Marshaler interface.
|
||||
func (p *Parameter) MarshalJSON() ([]byte, error) {
|
||||
var (
|
||||
resultRawValue json.RawMessage
|
||||
resultErr error
|
||||
)
|
||||
switch p.Type {
|
||||
case BoolType, IntegerType, StringType, Hash256Type, Hash160Type:
|
||||
resultRawValue, resultErr = json.Marshal(p.Value)
|
||||
case PublicKeyType, ByteArrayType, SignatureType:
|
||||
resultRawValue, resultErr = json.Marshal(hex.EncodeToString(p.Value.([]byte)))
|
||||
case ArrayType:
|
||||
var value = make([]rawParameter, 0)
|
||||
for _, parameter := range p.Value.([]Parameter) {
|
||||
rawValue, err := json.Marshal(parameter.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value = append(value, rawParameter{
|
||||
Type: parameter.Type,
|
||||
Value: rawValue,
|
||||
})
|
||||
}
|
||||
resultRawValue, resultErr = json.Marshal(value)
|
||||
case MapType:
|
||||
var value []keyValuePair
|
||||
for key, val := range p.Value.(map[Parameter]Parameter) {
|
||||
rawKey, err := json.Marshal(key.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawValue, err := json.Marshal(val.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value = append(value, keyValuePair{
|
||||
Key: rawParameter{
|
||||
Type: key.Type,
|
||||
Value: rawKey,
|
||||
},
|
||||
Value: rawParameter{
|
||||
Type: val.Type,
|
||||
Value: rawValue,
|
||||
},
|
||||
})
|
||||
}
|
||||
resultRawValue, resultErr = json.Marshal(value)
|
||||
default:
|
||||
resultErr = errors.Errorf("Marshaller for type %s not implemented", p.Type)
|
||||
}
|
||||
if resultErr != nil {
|
||||
return nil, resultErr
|
||||
}
|
||||
return json.Marshal(rawParameter{
|
||||
Type: p.Type,
|
||||
Value: resultRawValue,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements Unmarshaler interface.
|
||||
func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
||||
var (
|
||||
|
@ -53,14 +122,18 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
|||
i int64
|
||||
s string
|
||||
b []byte
|
||||
boolean bool
|
||||
)
|
||||
|
||||
if err = json.Unmarshal(data, &r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch p.Type = r.Type; r.Type {
|
||||
case ByteArrayType:
|
||||
case BoolType:
|
||||
if err = json.Unmarshal(r.Value, &boolean); err != nil {
|
||||
return
|
||||
}
|
||||
p.Value = boolean
|
||||
case ByteArrayType, PublicKeyType:
|
||||
if err = json.Unmarshal(r.Value, &s); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -93,6 +166,23 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
|||
return
|
||||
}
|
||||
p.Value = rs
|
||||
case MapType:
|
||||
var rawMap []rawKeyValuePair
|
||||
if err = json.Unmarshal(r.Value, &rawMap); err != nil {
|
||||
return
|
||||
}
|
||||
rs := make(map[Parameter]Parameter)
|
||||
for _, p := range rawMap {
|
||||
var key, value Parameter
|
||||
if err = json.Unmarshal(p.Key, &key); err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(p.Value, &value); err != nil {
|
||||
return
|
||||
}
|
||||
rs[key] = value
|
||||
}
|
||||
p.Value = rs
|
||||
case Hash160Type:
|
||||
var h util.Uint160
|
||||
if err = json.Unmarshal(r.Value, &h); err != nil {
|
||||
|
@ -106,7 +196,7 @@ func (p *Parameter) UnmarshalJSON(data []byte) (err error) {
|
|||
}
|
||||
p.Value = h
|
||||
default:
|
||||
return errors.New("not implemented")
|
||||
return errors.Errorf("Unmarshaller for type %s not implemented", p.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package smartcontract
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -9,10 +10,129 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testCases = []struct {
|
||||
var marshalJSONTestCases = []struct {
|
||||
input Parameter
|
||||
result string
|
||||
}{
|
||||
{
|
||||
input: Parameter{Type: IntegerType, Value: int64(12345)},
|
||||
result: `{"type":"Integer","value":12345}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{Type: StringType, Value: "Some string"},
|
||||
result: `{"type":"String","value":"Some string"}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{Type: BoolType, Value: true},
|
||||
result: `{"type":"Boolean","value":true}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{Type: ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
|
||||
result: `{"type":"ByteArray","value":"010203"}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: PublicKeyType,
|
||||
Value: []byte{0x03, 0xb3, 0xbf, 0x15, 0x02, 0xfb, 0xdc, 0x05, 0x44, 0x9b, 0x50, 0x6a, 0xaf, 0x04, 0x57, 0x97, 0x24, 0x02, 0x4b, 0x06, 0x54, 0x2e, 0x49, 0x26, 0x2b, 0xfa, 0xa3, 0xf7, 0x0e, 0x20, 0x00, 0x40, 0xa9},
|
||||
},
|
||||
result: `{"type":"PublicKey","value":"03b3bf1502fbdc05449b506aaf04579724024b06542e49262bfaa3f70e200040a9"}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: ArrayType,
|
||||
Value: []Parameter{
|
||||
{Type: StringType, Value: "str 1"},
|
||||
{Type: IntegerType, Value: int64(2)},
|
||||
},
|
||||
},
|
||||
result: `{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: MapType,
|
||||
Value: map[Parameter]Parameter{
|
||||
{Type: StringType, Value: "key1"}: {Type: IntegerType, Value: 1},
|
||||
{Type: StringType, Value: "key2"}: {Type: StringType, Value: "two"},
|
||||
},
|
||||
},
|
||||
result: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Integer","value":1}},{"key":{"type":"String","value":"key2"},"value":{"type":"String","value":"two"}}]}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: MapType,
|
||||
Value: map[Parameter]Parameter{
|
||||
{Type: StringType, Value: "key1"}: {Type: ArrayType, Value: []Parameter{
|
||||
{Type: StringType, Value: "str 1"},
|
||||
{Type: IntegerType, Value: int64(2)},
|
||||
}},
|
||||
},
|
||||
},
|
||||
result: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}}]}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: Hash160Type,
|
||||
Value: util.Uint160{
|
||||
0x0b, 0xcd, 0x29, 0x78, 0x63, 0x4d, 0x96, 0x1c, 0x24, 0xf5,
|
||||
0xae, 0xa0, 0x80, 0x22, 0x97, 0xff, 0x12, 0x87, 0x24, 0xd6,
|
||||
},
|
||||
},
|
||||
result: `{"type":"Hash160","value":"0x0bcd2978634d961c24f5aea0802297ff128724d6"}`,
|
||||
},
|
||||
{
|
||||
input: Parameter{
|
||||
Type: Hash256Type,
|
||||
Value: util.Uint256{
|
||||
0x2d, 0xf3, 0x45, 0xf2, 0x45, 0xc5, 0x98, 0x9e,
|
||||
0x69, 0x95, 0x45, 0x06, 0xa5, 0x9e, 0x40, 0x12,
|
||||
0xc1, 0x68, 0x54, 0x48, 0x08, 0xfc, 0xcc, 0x5b,
|
||||
0x15, 0x18, 0xab, 0xa0, 0x8f, 0x30, 0x37, 0xf0,
|
||||
},
|
||||
},
|
||||
result: `{"type":"Hash256","value":"0xf037308fa0ab18155bccfc08485468c112409ea5064595699e98c545f245f32d"}`,
|
||||
},
|
||||
}
|
||||
|
||||
var marshalJSONErrorCases = []Parameter{
|
||||
{
|
||||
Type: UnknownType,
|
||||
Value: nil,
|
||||
},
|
||||
{
|
||||
Type: InteropInterfaceType,
|
||||
Value: nil,
|
||||
},
|
||||
{
|
||||
Type: IntegerType,
|
||||
Value: math.Inf(1),
|
||||
},
|
||||
}
|
||||
|
||||
func TestParam_MarshalJSON(t *testing.T) {
|
||||
for _, tc := range marshalJSONTestCases {
|
||||
res, err := json.Marshal(&tc.input)
|
||||
assert.NoError(t, err)
|
||||
var actual, expected Parameter
|
||||
assert.NoError(t, json.Unmarshal(res, &actual))
|
||||
assert.NoError(t, json.Unmarshal([]byte(tc.result), &expected))
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
for _, input := range marshalJSONErrorCases {
|
||||
_, err := json.Marshal(&input)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
var unmarshalJSONTestCases = []struct {
|
||||
input string
|
||||
result Parameter
|
||||
}{
|
||||
{
|
||||
input: `{"type":"Bool","value":true}`,
|
||||
result: Parameter{Type: BoolType, Value: true},
|
||||
},
|
||||
{
|
||||
input: `{"type":"Integer","value":12345}`,
|
||||
result: Parameter{Type: IntegerType, Value: int64(12345)},
|
||||
|
@ -63,9 +183,38 @@ var testCases = []struct {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Integer","value":1}},{"key":{"type":"String","value":"key2"},"value":{"type":"String","value":"two"}}]}`,
|
||||
result: Parameter{
|
||||
Type: MapType,
|
||||
Value: map[Parameter]Parameter{
|
||||
{Type: StringType, Value: "key1"}: {Type: IntegerType, Value: int64(1)},
|
||||
{Type: StringType, Value: "key2"}: {Type: StringType, Value: "two"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `{"type":"Map","value":[{"key":{"type":"String","value":"key1"},"value":{"type":"Array","value":[{"type":"String","value":"str 1"},{"type":"Integer","value":2}]}}]}`,
|
||||
result: Parameter{
|
||||
Type: MapType,
|
||||
Value: map[Parameter]Parameter{
|
||||
{Type: StringType, Value: "key1"}: {Type: ArrayType, Value: []Parameter{
|
||||
{Type: StringType, Value: "str 1"},
|
||||
{Type: IntegerType, Value: int64(2)},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
result: Parameter{
|
||||
Type: PublicKeyType,
|
||||
Value: []byte{0x03, 0xb3, 0xbf, 0x15, 0x02, 0xfb, 0xdc, 0x05, 0x44, 0x9b, 0x50, 0x6a, 0xaf, 0x04, 0x57, 0x97, 0x24, 0x02, 0x4b, 0x06, 0x54, 0x2e, 0x49, 0x26, 0x2b, 0xfa, 0xa3, 0xf7, 0x0e, 0x20, 0x00, 0x40, 0xa9},
|
||||
},
|
||||
input: `{"type":"PublicKey","value":"03b3bf1502fbdc05449b506aaf04579724024b06542e49262bfaa3f70e200040a9"}`,
|
||||
},
|
||||
}
|
||||
|
||||
var errorCases = []string{
|
||||
var unmarshalJSONErrorCases = []string{
|
||||
`{"type": "ByteArray","value":`, // incorrect JSON
|
||||
`{"type": "ByteArray","value":1}`, // incorrect Value
|
||||
`{"type": "ByteArray","value":"12zz"}`, // incorrect ByteArray value
|
||||
|
@ -78,19 +227,23 @@ var errorCases = []string{
|
|||
`{"type": "Hash256","value": "0bcd"}`, // incorrect Uint256 value
|
||||
`{"type": "Stringg","value": ""}`, // incorrect type
|
||||
`{"type": {},"value": ""}`, // incorrect value
|
||||
`{"type": "Boolean","value": qwerty}`, // incorrect Bool value
|
||||
`{"type": "Boolean","value": ""}`, // incorrect Bool value
|
||||
`{"type": "Map","value": ["key": {}]}`, // incorrect Map value
|
||||
`{"type": "Map","value": ["key": {"type":"String", "value":"qwer"}, "value": {"type":"Boolean"}]}`, // incorrect Map Value value
|
||||
`{"type": "Map","value": ["key": {"type":"String"}, "value": {"type":"Boolean", "value":true}]}`, // incorrect Map Key value
|
||||
|
||||
`{"type": "InteropInterface","value": ""}`, // ununmarshable type
|
||||
`{"type": "Map","value": ""}`, //unmarshable type
|
||||
}
|
||||
|
||||
func TestParam_UnmarshalJSON(t *testing.T) {
|
||||
var s Parameter
|
||||
for _, tc := range testCases {
|
||||
for _, tc := range unmarshalJSONTestCases {
|
||||
assert.NoError(t, json.Unmarshal([]byte(tc.input), &s))
|
||||
assert.Equal(t, s, tc.result)
|
||||
}
|
||||
|
||||
for _, input := range errorCases {
|
||||
for _, input := range unmarshalJSONErrorCases {
|
||||
assert.Error(t, json.Unmarshal([]byte(input), &s))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue