Currently, unreleased changes in PR #636 and #645 cause the input data to be checked twice when UnmarshalCBOR() is called internally by Unmarshal() for: - ByteString - RawTag - SimpleValue UnmarshalCBOR() checks input data because it can be called by user apps providing bad data. However, the codec already checks input data before internally calling UnmarshalCBOR() so the 2nd check is redundant. This commit avoids redundant check on the input data by having Unmarshal() call the private unmarshalCBOR() if implemented by ByteString, RawTag, SimpleValue, etc.: - Internally, the codec calls the private unmarshalCBOR() to avoid the redundant check on input data. - Externally, UnmarshalCBOR() is available as a wrapper that checks input data before calling the private unmarshalCBOR(). UnmarshalCBOR() for ByteString, RawTag, and SimpleValue are marked as deprecated and Unmarshal() should be used instead.
299 lines
7.6 KiB
Go
299 lines
7.6 KiB
Go
// Copyright (c) Faye Amacker. All rights reserved.
|
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
|
|
package cbor
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestUnmarshalSimpleValue(t *testing.T) {
|
|
t.Run("0..23", func(t *testing.T) {
|
|
for i := 0; i <= 23; i++ {
|
|
data := []byte{byte(cborTypePrimitives) | byte(i)}
|
|
want := SimpleValue(i)
|
|
|
|
switch i {
|
|
case 20: // false
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, false)
|
|
case 21: // true
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, true)
|
|
case 22: // null
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, nil)
|
|
case 23: // undefined
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, nil)
|
|
default:
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, want)
|
|
}
|
|
|
|
testUnmarshalSimpleValue(t, data, want)
|
|
}
|
|
})
|
|
|
|
t.Run("24..31", func(t *testing.T) {
|
|
for i := 24; i <= 31; i++ {
|
|
data := []byte{byte(cborTypePrimitives) | byte(24), byte(i)}
|
|
|
|
testUnmarshalInvalidSimpleValueToEmptyInterface(t, data)
|
|
testUnmarshalInvalidSimpleValue(t, data)
|
|
}
|
|
})
|
|
|
|
t.Run("32..255", func(t *testing.T) {
|
|
for i := 32; i <= 255; i++ {
|
|
data := []byte{byte(cborTypePrimitives) | byte(24), byte(i)}
|
|
want := SimpleValue(i)
|
|
testUnmarshalSimpleValueToEmptyInterface(t, data, want)
|
|
testUnmarshalSimpleValue(t, data, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUnmarshalSimpleValueOnBadData(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
errMsg string
|
|
}{
|
|
// Empty data
|
|
{
|
|
name: "nil data",
|
|
data: nil,
|
|
errMsg: io.EOF.Error(),
|
|
},
|
|
{
|
|
name: "empty data",
|
|
data: []byte{},
|
|
errMsg: io.EOF.Error(),
|
|
},
|
|
|
|
// Wrong CBOR types
|
|
{
|
|
name: "uint type",
|
|
data: hexDecode("01"),
|
|
errMsg: "cbor: cannot unmarshal positive integer into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "int type",
|
|
data: hexDecode("20"),
|
|
errMsg: "cbor: cannot unmarshal negative integer into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "byte string type",
|
|
data: hexDecode("40"),
|
|
errMsg: "cbor: cannot unmarshal byte string into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "string type",
|
|
data: hexDecode("60"),
|
|
errMsg: "cbor: cannot unmarshal UTF-8 text string into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "array type",
|
|
data: hexDecode("80"),
|
|
errMsg: "cbor: cannot unmarshal array into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "map type",
|
|
data: hexDecode("a0"),
|
|
errMsg: "cbor: cannot unmarshal map into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "tag type",
|
|
data: hexDecode("c074323031332d30332d32315432303a30343a30305a"),
|
|
errMsg: "cbor: cannot unmarshal tag into Go value of type SimpleValue",
|
|
},
|
|
{
|
|
name: "float type",
|
|
data: hexDecode("f90000"),
|
|
errMsg: "cbor: cannot unmarshal primitives into Go value of type SimpleValue",
|
|
},
|
|
|
|
// Truncated CBOR data
|
|
{
|
|
name: "truncated head",
|
|
data: hexDecode("18"),
|
|
errMsg: io.ErrUnexpectedEOF.Error(),
|
|
},
|
|
|
|
// Truncated CBOR simple value
|
|
{
|
|
name: "truncated simple value",
|
|
data: hexDecode("f8"),
|
|
errMsg: io.ErrUnexpectedEOF.Error(),
|
|
},
|
|
|
|
// Invalid simple value
|
|
{
|
|
name: "invalid simple value",
|
|
data: hexDecode("f800"),
|
|
errMsg: "cbor: invalid simple value 0 for type primitives",
|
|
},
|
|
|
|
// Extraneous CBOR data
|
|
{
|
|
name: "extraneous data",
|
|
data: hexDecode("f4f5"),
|
|
errMsg: "cbor: 1 bytes of extraneous data starting at index 1",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Test SimpleValue.UnmarshalCBOR(data)
|
|
{
|
|
var v SimpleValue
|
|
|
|
err := v.UnmarshalCBOR(tc.data)
|
|
if err == nil {
|
|
t.Errorf("UnmarshalCBOR(%x) didn't return error", tc.data)
|
|
}
|
|
if !strings.HasPrefix(err.Error(), tc.errMsg) {
|
|
t.Errorf("UnmarshalCBOR(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg)
|
|
}
|
|
}
|
|
// Test Unmarshal(data, *SimpleValue), which calls SimpleValue.unmarshalCBOR() under the hood
|
|
{
|
|
var v SimpleValue
|
|
|
|
err := Unmarshal(tc.data, &v)
|
|
if err == nil {
|
|
t.Errorf("Unmarshal(%x) didn't return error", tc.data)
|
|
}
|
|
if !strings.HasPrefix(err.Error(), tc.errMsg) {
|
|
t.Errorf("Unmarshal(%x) returned error %q, want %q", tc.data, err.Error(), tc.errMsg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func testUnmarshalInvalidSimpleValueToEmptyInterface(t *testing.T, data []byte) {
|
|
var v any
|
|
if err := Unmarshal(data, v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*SyntaxError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*SyntaxError)", data, err)
|
|
}
|
|
}
|
|
|
|
func testUnmarshalInvalidSimpleValue(t *testing.T, data []byte) {
|
|
var v SimpleValue
|
|
if err := Unmarshal(data, v); err == nil {
|
|
t.Errorf("Unmarshal(0x%x) didn't return an error", data)
|
|
} else if _, ok := err.(*SyntaxError); !ok {
|
|
t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*SyntaxError)", data, err)
|
|
}
|
|
}
|
|
|
|
func testUnmarshalSimpleValueToEmptyInterface(t *testing.T, data []byte, want any) {
|
|
var v any
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
|
|
func testUnmarshalSimpleValue(t *testing.T, data []byte, want SimpleValue) {
|
|
cborNil := isCBORNil(data)
|
|
|
|
// Decode to SimpleValue
|
|
var v SimpleValue
|
|
err := Unmarshal(data, &v)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
|
|
// Decode to uninitialized *SimpleValue
|
|
var pv *SimpleValue
|
|
err = Unmarshal(data, &pv)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if cborNil {
|
|
if pv != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned %v, want nil *SimpleValue", data, *pv)
|
|
}
|
|
} else {
|
|
if !reflect.DeepEqual(*pv, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, *pv, *pv, want, want)
|
|
}
|
|
}
|
|
|
|
// Decode to initialized *SimpleValue
|
|
v = SimpleValue(0)
|
|
pv = &v
|
|
err = Unmarshal(data, &pv)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
|
|
return
|
|
}
|
|
if cborNil {
|
|
if pv != nil {
|
|
t.Errorf("Unmarshal(0x%x) returned %v, want nil *SimpleValue", data, *pv)
|
|
}
|
|
} else {
|
|
if !reflect.DeepEqual(v, want) {
|
|
t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v, v, want, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalSimpleValue(t *testing.T) {
|
|
t.Run("0..23", func(t *testing.T) {
|
|
for i := 0; i <= 23; i++ {
|
|
wantData := []byte{byte(cborTypePrimitives) | byte(i)}
|
|
v := SimpleValue(i)
|
|
|
|
data, err := Marshal(v)
|
|
if err != nil {
|
|
t.Errorf("Marshal(%v) returned error %v", v, err)
|
|
continue
|
|
}
|
|
if !bytes.Equal(data, wantData) {
|
|
t.Errorf("Marshal(%v) = 0x%x, want 0x%x", v, data, wantData)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("24..31", func(t *testing.T) {
|
|
for i := 24; i <= 31; i++ {
|
|
v := SimpleValue(i)
|
|
|
|
if data, err := Marshal(v); err == nil {
|
|
t.Errorf("Marshal(%v) didn't return an error", data)
|
|
} else if _, ok := err.(*UnsupportedValueError); !ok {
|
|
t.Errorf("Marshal(%v) returned wrong error type %T, want (*UnsupportedValueError)", data, err)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("32..255", func(t *testing.T) {
|
|
for i := 32; i <= 255; i++ {
|
|
wantData := []byte{byte(cborTypePrimitives) | byte(24), byte(i)}
|
|
v := SimpleValue(i)
|
|
|
|
data, err := Marshal(v)
|
|
if err != nil {
|
|
t.Errorf("Marshal(%v) returned error %v", v, err)
|
|
continue
|
|
}
|
|
if !bytes.Equal(data, wantData) {
|
|
t.Errorf("Marshal(%v) = 0x%x, want 0x%x", v, data, wantData)
|
|
}
|
|
}
|
|
})
|
|
}
|